Merge branch '4tf'
|
@ -17,6 +17,10 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
||||||
PRECOMPILED_HEADER = src/PrecompiledHeader.hpp
|
PRECOMPILED_HEADER = src/PrecompiledHeader.hpp
|
||||||
CONFIG += precompile_header
|
CONFIG += precompile_header
|
||||||
|
|
||||||
|
debug {
|
||||||
|
DEFINES += QT_DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
useBreakpad {
|
useBreakpad {
|
||||||
LIBS += -L$$PWD/lib/qBreakpad/handler/build
|
LIBS += -L$$PWD/lib/qBreakpad/handler/build
|
||||||
include(lib/qBreakpad/qBreakpad.pri)
|
include(lib/qBreakpad/qBreakpad.pri)
|
||||||
|
@ -132,9 +136,7 @@ SOURCES += \
|
||||||
src/messages/MessageBuilder.cpp \
|
src/messages/MessageBuilder.cpp \
|
||||||
src/messages/MessageColor.cpp \
|
src/messages/MessageColor.cpp \
|
||||||
src/messages/MessageElement.cpp \
|
src/messages/MessageElement.cpp \
|
||||||
src/providers/bttv/BttvEmotes.cpp \
|
|
||||||
src/providers/emoji/Emojis.cpp \
|
src/providers/emoji/Emojis.cpp \
|
||||||
src/providers/ffz/FfzEmotes.cpp \
|
|
||||||
src/providers/irc/AbstractIrcServer.cpp \
|
src/providers/irc/AbstractIrcServer.cpp \
|
||||||
src/providers/irc/IrcAccount.cpp \
|
src/providers/irc/IrcAccount.cpp \
|
||||||
src/providers/irc/IrcChannel2.cpp \
|
src/providers/irc/IrcChannel2.cpp \
|
||||||
|
@ -232,7 +234,21 @@ SOURCES += \
|
||||||
src/widgets/dialogs/UpdateDialog.cpp \
|
src/widgets/dialogs/UpdateDialog.cpp \
|
||||||
src/widgets/settingspages/IgnoresPage.cpp \
|
src/widgets/settingspages/IgnoresPage.cpp \
|
||||||
src/providers/twitch/PubsubClient.cpp \
|
src/providers/twitch/PubsubClient.cpp \
|
||||||
src/providers/twitch/TwitchApi.cpp
|
src/providers/twitch/TwitchApi.cpp \
|
||||||
|
src/messages/Emote.cpp \
|
||||||
|
src/messages/EmoteMap.cpp \
|
||||||
|
src/messages/ImageSet.cpp \
|
||||||
|
src/providers/bttv/BttvEmotes.cpp \
|
||||||
|
src/providers/ffz/FfzEmotes.cpp \
|
||||||
|
src/autogenerated/ResourcesAutogen.cpp \
|
||||||
|
src/singletons/Badges.cpp \
|
||||||
|
src/providers/twitch/TwitchBadges.cpp \
|
||||||
|
src/providers/chatterino/ChatterinoBadges.cpp \
|
||||||
|
src/providers/twitch/TwitchParseCheerEmotes.cpp \
|
||||||
|
src/providers/bttv/LoadBttvChannelEmote.cpp \
|
||||||
|
src/util/JsonQuery.cpp \
|
||||||
|
src/RunGui.cpp \
|
||||||
|
src/BrowserExtension.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/Application.hpp \
|
src/Application.hpp \
|
||||||
|
@ -292,9 +308,7 @@ HEADERS += \
|
||||||
src/messages/MessageParseArgs.hpp \
|
src/messages/MessageParseArgs.hpp \
|
||||||
src/messages/Selection.hpp \
|
src/messages/Selection.hpp \
|
||||||
src/PrecompiledHeader.hpp \
|
src/PrecompiledHeader.hpp \
|
||||||
src/providers/bttv/BttvEmotes.hpp \
|
|
||||||
src/providers/emoji/Emojis.hpp \
|
src/providers/emoji/Emojis.hpp \
|
||||||
src/providers/ffz/FfzEmotes.hpp \
|
|
||||||
src/providers/irc/AbstractIrcServer.hpp \
|
src/providers/irc/AbstractIrcServer.hpp \
|
||||||
src/providers/irc/IrcAccount.hpp \
|
src/providers/irc/IrcAccount.hpp \
|
||||||
src/providers/irc/IrcChannel2.hpp \
|
src/providers/irc/IrcChannel2.hpp \
|
||||||
|
@ -413,10 +427,28 @@ HEADERS += \
|
||||||
src/widgets/dialogs/UpdateDialog.hpp \
|
src/widgets/dialogs/UpdateDialog.hpp \
|
||||||
src/widgets/settingspages/IgnoresPage.hpp \
|
src/widgets/settingspages/IgnoresPage.hpp \
|
||||||
src/providers/twitch/PubsubClient.hpp \
|
src/providers/twitch/PubsubClient.hpp \
|
||||||
src/providers/twitch/TwitchApi.hpp
|
src/providers/twitch/TwitchApi.hpp \
|
||||||
|
src/messages/Emote.hpp \
|
||||||
|
src/messages/EmoteMap.hpp \
|
||||||
|
src/messages/EmoteCache.hpp \
|
||||||
|
src/messages/ImageSet.hpp \
|
||||||
|
src/common/Outcome.hpp \
|
||||||
|
src/providers/bttv/BttvEmotes.hpp \
|
||||||
|
src/providers/ffz/FfzEmotes.hpp \
|
||||||
|
src/autogenerated/ResourcesAutogen.hpp \
|
||||||
|
src/singletons/Badges.hpp \
|
||||||
|
src/providers/twitch/TwitchBadges.hpp \
|
||||||
|
src/providers/chatterino/ChatterinoBadges.hpp \
|
||||||
|
src/common/Aliases.hpp \
|
||||||
|
src/providers/twitch/TwitchParseCheerEmotes.hpp \
|
||||||
|
src/providers/bttv/LoadBttvChannelEmote.hpp \
|
||||||
|
src/util/JsonQuery.hpp \
|
||||||
|
src/RunGui.hpp \
|
||||||
|
src/BrowserExtension.hpp
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
resources/resources.qrc \
|
resources/resources.qrc \
|
||||||
|
resources/resources_autogenerated.qrc
|
||||||
|
|
||||||
DISTFILES +=
|
DISTFILES +=
|
||||||
|
|
||||||
|
|
BIN
resources/__pycache__/_generate_resources.cpython-36.pyc
Normal file
38
resources/_generate_resources.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
resources_header = \
|
||||||
|
'''<RCC>
|
||||||
|
<qresource prefix="/">'''
|
||||||
|
|
||||||
|
resources_footer = \
|
||||||
|
''' </qresource>
|
||||||
|
</RCC>'''
|
||||||
|
|
||||||
|
header_header = \
|
||||||
|
'''#include <QPixmap>
|
||||||
|
#include "common/Singleton.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
class Resources2 : public Singleton {
|
||||||
|
public:
|
||||||
|
Resources2();
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
header_footer = \
|
||||||
|
'''};
|
||||||
|
|
||||||
|
} // namespace chatterino'''
|
||||||
|
|
||||||
|
source_header = \
|
||||||
|
'''#include "ResourcesAutogen.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
Resources2::Resources2()
|
||||||
|
{
|
||||||
|
'''
|
||||||
|
|
||||||
|
source_footer = \
|
||||||
|
'''}
|
||||||
|
|
||||||
|
} // namespace chatterino'''
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 847 B After Width: | Height: | Size: 847 B |
Before Width: | Height: | Size: 847 B After Width: | Height: | Size: 847 B |
Before Width: | Height: | Size: 307 B After Width: | Height: | Size: 307 B |
Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 328 B |
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 349 B |
Before Width: | Height: | Size: 344 B After Width: | Height: | Size: 344 B |
Before Width: | Height: | Size: 332 B After Width: | Height: | Size: 332 B |
BIN
resources/error.png
Normal file
After Width: | Height: | Size: 685 B |
61
resources/generate_resources.py
Executable file
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from _generate_resources import *
|
||||||
|
|
||||||
|
ignored_files = ['qt.conf', 'resources.qrc', 'resources_autogenerated.qrc', 'windows.rc',
|
||||||
|
'generate_resources.py', '_generate_resources.py']
|
||||||
|
ignored_directories = ['__pycache__']
|
||||||
|
|
||||||
|
def isNotIgnored(file):
|
||||||
|
return str(file) not in ignored_files
|
||||||
|
|
||||||
|
all_files = list(filter(isNotIgnored, \
|
||||||
|
filter(Path.is_file, Path('.').glob('**/*'))))
|
||||||
|
image_files = list(filter(isNotIgnored, \
|
||||||
|
filter(Path.is_file, Path('.').glob('**/*.png'))))
|
||||||
|
|
||||||
|
with open('./resources_autogenerated.qrc', 'w') as out:
|
||||||
|
out.write(resources_header)
|
||||||
|
for file in all_files:
|
||||||
|
out.write(f" <file>{str(file)}</file>\n")
|
||||||
|
out.write(resources_footer)
|
||||||
|
|
||||||
|
with open('../src/autogenerated/ResourcesAutogen.cpp', 'w') as out:
|
||||||
|
out.write(source_header)
|
||||||
|
for file in sorted(image_files):
|
||||||
|
var_name = str(file.with_suffix("")).replace("/",".")
|
||||||
|
out.write(f' this->{var_name}')
|
||||||
|
out.write(f' = QPixmap(":/{file}");\n')
|
||||||
|
out.write(source_footer)
|
||||||
|
|
||||||
|
def writeHeader(out, name, element, indent):
|
||||||
|
if isinstance(element, dict):
|
||||||
|
if name != "":
|
||||||
|
out.write(f"{indent}struct {{\n")
|
||||||
|
for (key, value) in element.items():
|
||||||
|
writeHeader(out, key, value, indent + ' ')
|
||||||
|
if name != "":
|
||||||
|
out.write(f"{indent}}} {name};\n");
|
||||||
|
else:
|
||||||
|
out.write(f"{indent}QPixmap {element};\n")
|
||||||
|
|
||||||
|
with open('../src/autogenerated/ResourcesAutogen.hpp', 'w') as out:
|
||||||
|
out.write(header_header)
|
||||||
|
|
||||||
|
elements = {}
|
||||||
|
for file in sorted(image_files):
|
||||||
|
elements_ref = elements
|
||||||
|
directories = str(file).split('/')[:-1]
|
||||||
|
filename = file.stem
|
||||||
|
for directory in directories:
|
||||||
|
if directory not in elements_ref:
|
||||||
|
if directory not in ignored_directories:
|
||||||
|
elements_ref[directory] = {}
|
||||||
|
elements_ref = elements_ref[directory]
|
||||||
|
elements_ref[filename] = filename
|
||||||
|
|
||||||
|
writeHeader(out, "", elements, '')
|
||||||
|
|
||||||
|
out.write(header_footer)
|
||||||
|
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 347 B |
Before Width: | Height: | Size: 680 B |
Before Width: | Height: | Size: 403 B |
Before Width: | Height: | Size: 368 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 660 B |
Before Width: | Height: | Size: 280 B |
Before Width: | Height: | Size: 179 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 286 B |
Before Width: | Height: | Size: 480 B |
Before Width: | Height: | Size: 360 B |
Before Width: | Height: | Size: 351 B |
Before Width: | Height: | Size: 330 B |
Before Width: | Height: | Size: 285 B |
Before Width: | Height: | Size: 362 B |
Before Width: | Height: | Size: 236 B |
Before Width: | Height: | Size: 354 B |
Before Width: | Height: | Size: 274 B |
Before Width: | Height: | Size: 279 B |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
@ -1,81 +1,4 @@
|
||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
|
||||||
<file>images/AppearanceEditorPart_16x.png</file>
|
|
||||||
<file>images/BrowserLink_16x.png</file>
|
|
||||||
<file>images/cheer1.png</file>
|
|
||||||
<file>images/cheer100.png</file>
|
|
||||||
<file>images/cheer1000.png</file>
|
|
||||||
<file>images/cheer10000.png</file>
|
|
||||||
<file>images/cheer100000.png</file>
|
|
||||||
<file>images/cheer5000.png</file>
|
|
||||||
<file>images/verified.png</file>
|
|
||||||
<file>images/CopyLongTextToClipboard_16x.png</file>
|
|
||||||
<file>images/CustomActionEditor_16x.png</file>
|
|
||||||
<file>images/Emoji_Color_1F60A_19.png</file>
|
|
||||||
<file>images/Filter_16x.png</file>
|
|
||||||
<file>images/format_Bold_16xLG.png</file>
|
|
||||||
<file>images/Message_16xLG.png</file>
|
|
||||||
<file>images/settings.png</file>
|
|
||||||
<file>images/tool_moreCollapser_off16.png</file>
|
|
||||||
<file>images/twitchprime_bg.png</file>
|
|
||||||
<file>qss/settings.qss</file>
|
|
||||||
<file>images/admin_bg.png</file>
|
|
||||||
<file>images/broadcaster_bg.png</file>
|
|
||||||
<file>images/globalmod_bg.png</file>
|
|
||||||
<file>images/moderator_bg.png</file>
|
|
||||||
<file>images/staff_bg.png</file>
|
|
||||||
<file>images/turbo_bg.png</file>
|
|
||||||
<file>emojidata.txt</file>
|
|
||||||
<file>images/button_ban.png</file>
|
|
||||||
<file>images/button_timeout.png</file>
|
|
||||||
<file>images/StatusAnnotations_Blocked_16xLG_color.png</file>
|
|
||||||
<file>images/UserProfile_22x.png</file>
|
|
||||||
<file>images/VSO_Link_blue_16x.png</file>
|
|
||||||
<file>sounds/ping2.wav</file>
|
|
||||||
<file>images/subscriber.png</file>
|
|
||||||
<file>images/collapse.png</file>
|
|
||||||
<file>images/emote.svg</file>
|
|
||||||
<file>images/notifications.svg</file>
|
|
||||||
<file>images/behave.svg</file>
|
|
||||||
<file>images/theme.svg</file>
|
|
||||||
<file>images/accounts.svg</file>
|
|
||||||
<file>images/chatterino2.icns</file>
|
|
||||||
<file>images/icon.png</file>
|
|
||||||
<file>images/commands.svg</file>
|
|
||||||
<file>images/aboutlogo.png</file>
|
|
||||||
<file>images/about.svg</file>
|
|
||||||
<file>images/moderatormode_disabled.png</file>
|
|
||||||
<file>images/moderatormode_enabled.png</file>
|
|
||||||
<file>images/split/splitdown.png</file>
|
|
||||||
<file>images/split/splitleft.png</file>
|
|
||||||
<file>images/split/splitright.png</file>
|
|
||||||
<file>images/split/splitup.png</file>
|
|
||||||
<file>images/split/splitmove.png</file>
|
|
||||||
<file>licenses/boost_boost.txt</file>
|
|
||||||
<file>licenses/fmt_bsd2.txt</file>
|
|
||||||
<file>licenses/libcommuni_BSD3.txt</file>
|
|
||||||
<file>licenses/openssl.txt</file>
|
|
||||||
<file>licenses/pajlada_settings.txt</file>
|
|
||||||
<file>licenses/pajlada_signals.txt</file>
|
|
||||||
<file>licenses/qt_lgpl-3.0.txt</file>
|
|
||||||
<file>licenses/rapidjson.txt</file>
|
|
||||||
<file>licenses/websocketpp.txt</file>
|
|
||||||
<file>emoji.json</file>
|
|
||||||
<file>images/buttons/ban.png</file>
|
|
||||||
<file>images/buttons/mod.png</file>
|
|
||||||
<file>images/buttons/unban.png</file>
|
|
||||||
<file>images/buttons/unmod.png</file>
|
|
||||||
<file>images/emote_dark.svg</file>
|
|
||||||
<file>tlds.txt</file>
|
|
||||||
<file>images/menu_black.png</file>
|
|
||||||
<file>images/menu_white.png</file>
|
|
||||||
<file>contributors.txt</file>
|
|
||||||
<file>avatars/fourtf.png</file>
|
|
||||||
<file>avatars/pajlada.png</file>
|
|
||||||
<file>images/download_update.png</file>
|
|
||||||
<file>images/download_update_error.png</file>
|
|
||||||
<file>images/pajaDank.png</file>
|
|
||||||
</qresource>
|
|
||||||
<qresource prefix="/qt/etc">
|
<qresource prefix="/qt/etc">
|
||||||
<file>qt.conf</file>
|
<file>qt.conf</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
|
64
resources/resources_autogenerated.qrc
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/"> <file>pajaDank.png</file>
|
||||||
|
<file>icon.png</file>
|
||||||
|
<file>emojidata.txt</file>
|
||||||
|
<file>contributors.txt</file>
|
||||||
|
<file>error.png</file>
|
||||||
|
<file>emoji.json</file>
|
||||||
|
<file>icon.ico</file>
|
||||||
|
<file>tlds.txt</file>
|
||||||
|
<file>chatterino2.icns</file>
|
||||||
|
<file>qss/settings.qss</file>
|
||||||
|
<file>__pycache__/_generate_resources.cpython-36.pyc</file>
|
||||||
|
<file>licenses/fmt_bsd2.txt</file>
|
||||||
|
<file>licenses/openssl.txt</file>
|
||||||
|
<file>licenses/pajlada_settings.txt</file>
|
||||||
|
<file>licenses/qt_lgpl-3.0.txt</file>
|
||||||
|
<file>licenses/pajlada_signals.txt</file>
|
||||||
|
<file>licenses/rapidjson.txt</file>
|
||||||
|
<file>licenses/websocketpp.txt</file>
|
||||||
|
<file>licenses/boost_boost.txt</file>
|
||||||
|
<file>licenses/libcommuni_BSD3.txt</file>
|
||||||
|
<file>settings/aboutlogo.png</file>
|
||||||
|
<file>settings/behave.svg</file>
|
||||||
|
<file>settings/accounts.svg</file>
|
||||||
|
<file>settings/about.svg</file>
|
||||||
|
<file>settings/notifications.svg</file>
|
||||||
|
<file>settings/commands.svg</file>
|
||||||
|
<file>settings/theme.svg</file>
|
||||||
|
<file>split/up.png</file>
|
||||||
|
<file>split/left.png</file>
|
||||||
|
<file>split/move.png</file>
|
||||||
|
<file>split/right.png</file>
|
||||||
|
<file>split/down.png</file>
|
||||||
|
<file>buttons/unban.png</file>
|
||||||
|
<file>buttons/menuDark.png</file>
|
||||||
|
<file>buttons/mod.png</file>
|
||||||
|
<file>buttons/emote.svg</file>
|
||||||
|
<file>buttons/modModeEnabled2.png</file>
|
||||||
|
<file>buttons/ban.png</file>
|
||||||
|
<file>buttons/unmod.png</file>
|
||||||
|
<file>buttons/emoteDark.svg</file>
|
||||||
|
<file>buttons/updateError.png</file>
|
||||||
|
<file>buttons/modModeDisabled.png</file>
|
||||||
|
<file>buttons/modModeDisabled2.png</file>
|
||||||
|
<file>buttons/modModeEnabled.png</file>
|
||||||
|
<file>buttons/menuLight.png</file>
|
||||||
|
<file>buttons/update.png</file>
|
||||||
|
<file>buttons/timeout.png</file>
|
||||||
|
<file>buttons/banRed.png</file>
|
||||||
|
<file>sounds/ping2.wav</file>
|
||||||
|
<file>twitch/prime.png</file>
|
||||||
|
<file>twitch/verified.png</file>
|
||||||
|
<file>twitch/admin.png</file>
|
||||||
|
<file>twitch/subscriber.png</file>
|
||||||
|
<file>twitch/turbo.png</file>
|
||||||
|
<file>twitch/moderator.png</file>
|
||||||
|
<file>twitch/globalmod.png</file>
|
||||||
|
<file>twitch/cheer1.png</file>
|
||||||
|
<file>twitch/broadcaster.png</file>
|
||||||
|
<file>twitch/staff.png</file>
|
||||||
|
<file>avatars/fourtf.png</file>
|
||||||
|
<file>avatars/pajlada.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 805 B After Width: | Height: | Size: 805 B |
Before Width: | Height: | Size: 820 B After Width: | Height: | Size: 820 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 955 B After Width: | Height: | Size: 955 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 361 B After Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 437 B After Width: | Height: | Size: 437 B |
Before Width: | Height: | Size: 772 B After Width: | Height: | Size: 772 B |
Before Width: | Height: | Size: 494 B After Width: | Height: | Size: 494 B |
Before Width: | Height: | Size: 361 B After Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 439 B After Width: | Height: | Size: 439 B |
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 191 B |
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 397 B |
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 116 B After Width: | Height: | Size: 116 B |
Before Width: | Height: | Size: 269 B After Width: | Height: | Size: 269 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 257 B After Width: | Height: | Size: 257 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
@ -6,9 +6,10 @@
|
||||||
#include "controllers/ignores/IgnoreController.hpp"
|
#include "controllers/ignores/IgnoreController.hpp"
|
||||||
#include "controllers/moderationactions/ModerationActions.hpp"
|
#include "controllers/moderationactions/ModerationActions.hpp"
|
||||||
#include "controllers/taggedusers/TaggedUsersController.hpp"
|
#include "controllers/taggedusers/TaggedUsersController.hpp"
|
||||||
|
#include "providers/bttv/BttvEmotes.hpp"
|
||||||
|
#include "providers/ffz/FfzEmotes.hpp"
|
||||||
#include "providers/twitch/PubsubClient.hpp"
|
#include "providers/twitch/PubsubClient.hpp"
|
||||||
#include "providers/twitch/TwitchServer.hpp"
|
#include "providers/twitch/TwitchServer.hpp"
|
||||||
#include "singletons/Emotes.hpp"
|
|
||||||
#include "singletons/Fonts.hpp"
|
#include "singletons/Fonts.hpp"
|
||||||
#include "singletons/Logging.hpp"
|
#include "singletons/Logging.hpp"
|
||||||
#include "singletons/NativeMessaging.hpp"
|
#include "singletons/NativeMessaging.hpp"
|
||||||
|
@ -24,69 +25,75 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
static std::atomic<bool> isAppConstructed{false};
|
|
||||||
static std::atomic<bool> isAppInitialized{false};
|
static std::atomic<bool> isAppInitialized{false};
|
||||||
|
|
||||||
static Application *staticApp = nullptr;
|
Application *Application::instance = nullptr;
|
||||||
|
|
||||||
// this class is responsible for handling the workflow of Chatterino
|
// this class is responsible for handling the workflow of Chatterino
|
||||||
// It will create the instances of the major classes, and connect their signals to each other
|
// It will create the instances of the major classes, and connect their signals to each other
|
||||||
|
|
||||||
Application::Application(int _argc, char **_argv)
|
Application::Application(Settings &_settings, Paths &_paths)
|
||||||
: argc_(_argc)
|
: settings(&_settings)
|
||||||
, argv_(_argv)
|
, paths(&_paths)
|
||||||
|
, resources(&this->emplace<Resources2>())
|
||||||
|
|
||||||
|
, themes(&this->emplace<Theme>())
|
||||||
|
, fonts(&this->emplace<Fonts>())
|
||||||
|
, emotes(&this->emplace<Emotes>())
|
||||||
|
, windows(&this->emplace<WindowManager>())
|
||||||
|
|
||||||
|
, accounts(&this->emplace<AccountController>())
|
||||||
|
, commands(&this->emplace<CommandController>())
|
||||||
|
, highlights(&this->emplace<HighlightController>())
|
||||||
|
, ignores(&this->emplace<IgnoreController>())
|
||||||
|
, taggedUsers(&this->emplace<TaggedUsersController>())
|
||||||
|
, moderationActions(&this->emplace<ModerationActions>())
|
||||||
|
, twitch2(&this->emplace<TwitchServer>())
|
||||||
|
, logging(&this->emplace<Logging>())
|
||||||
{
|
{
|
||||||
getSettings()->initialize();
|
this->instance = this;
|
||||||
getSettings()->load();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::construct()
|
this->fonts->fontChanged.connect([this]() { this->windows->layoutChannelViews(); });
|
||||||
{
|
|
||||||
assert(isAppConstructed == false);
|
|
||||||
isAppConstructed = true;
|
|
||||||
|
|
||||||
// 1. Instantiate all classes
|
|
||||||
this->settings = getSettings();
|
|
||||||
this->paths = getPaths();
|
|
||||||
|
|
||||||
this->addSingleton(this->themes = new Theme);
|
|
||||||
this->addSingleton(this->windows = new WindowManager);
|
|
||||||
this->addSingleton(this->logging = new Logging);
|
|
||||||
this->addSingleton(this->commands = new CommandController);
|
|
||||||
this->addSingleton(this->highlights = new HighlightController);
|
|
||||||
this->addSingleton(this->ignores = new IgnoreController);
|
|
||||||
this->addSingleton(this->taggedUsers = new TaggedUsersController);
|
|
||||||
this->addSingleton(this->accounts = new AccountController);
|
|
||||||
this->addSingleton(this->emotes = new Emotes);
|
|
||||||
this->addSingleton(this->fonts = new Fonts);
|
|
||||||
this->addSingleton(this->resources = new Resources);
|
|
||||||
this->addSingleton(this->moderationActions = new ModerationActions);
|
|
||||||
|
|
||||||
this->addSingleton(this->twitch2 = new TwitchServer);
|
|
||||||
this->twitch.server = this->twitch2;
|
this->twitch.server = this->twitch2;
|
||||||
this->twitch.pubsub = this->twitch2->pubsub;
|
this->twitch.pubsub = this->twitch2->pubsub;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::instantiate(int argc, char **argv)
|
void Application::initialize(Settings &settings, Paths &paths)
|
||||||
{
|
|
||||||
assert(staticApp == nullptr);
|
|
||||||
|
|
||||||
staticApp = new Application(argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::initialize()
|
|
||||||
{
|
{
|
||||||
assert(isAppInitialized == false);
|
assert(isAppInitialized == false);
|
||||||
isAppInitialized = true;
|
isAppInitialized = true;
|
||||||
|
|
||||||
// 2. Initialize/load classes
|
for (auto &singleton : this->singletons_) {
|
||||||
for (Singleton *singleton : this->singletons_) {
|
singleton->initialize(settings, paths);
|
||||||
singleton->initialize(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX
|
|
||||||
this->windows->updateWordTypeMask();
|
this->windows->updateWordTypeMask();
|
||||||
|
|
||||||
|
this->initNm();
|
||||||
|
this->initPubsub();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Application::run(QApplication &qtApp)
|
||||||
|
{
|
||||||
|
assert(isAppInitialized);
|
||||||
|
|
||||||
|
this->twitch.server->connect();
|
||||||
|
|
||||||
|
this->windows->getMainWindow().show();
|
||||||
|
|
||||||
|
return qtApp.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::save()
|
||||||
|
{
|
||||||
|
for (auto &singleton : this->singletons_) {
|
||||||
|
singleton->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::initNm()
|
||||||
|
{
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
#ifdef C_DEBUG_NM
|
#ifdef C_DEBUG_NM
|
||||||
|
@ -98,7 +105,10 @@ void Application::initialize()
|
||||||
this->nativeMessaging->openGuiMessageQueue();
|
this->nativeMessaging->openGuiMessageQueue();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::initPubsub()
|
||||||
|
{
|
||||||
this->twitch.pubsub->signals_.whisper.sent.connect([](const auto &msg) {
|
this->twitch.pubsub->signals_.whisper.sent.connect([](const auto &msg) {
|
||||||
Log("WHISPER SENT LOL"); //
|
Log("WHISPER SENT LOL"); //
|
||||||
});
|
});
|
||||||
|
@ -197,39 +207,11 @@ void Application::initialize()
|
||||||
RequestModerationActions();
|
RequestModerationActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Application::run(QApplication &qtApp)
|
|
||||||
{
|
|
||||||
// Start connecting to the IRC Servers (Twitch only for now)
|
|
||||||
this->twitch.server->connect();
|
|
||||||
|
|
||||||
// Show main window
|
|
||||||
this->windows->getMainWindow().show();
|
|
||||||
|
|
||||||
return qtApp.exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::save()
|
|
||||||
{
|
|
||||||
for (Singleton *singleton : this->singletons_) {
|
|
||||||
singleton->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::addSingleton(Singleton *singleton)
|
|
||||||
{
|
|
||||||
this->singletons_.push_back(singleton);
|
|
||||||
}
|
|
||||||
|
|
||||||
Application *getApp()
|
Application *getApp()
|
||||||
{
|
{
|
||||||
assert(staticApp != nullptr);
|
assert(Application::instance != nullptr);
|
||||||
|
|
||||||
return staticApp;
|
return Application::instance;
|
||||||
}
|
|
||||||
|
|
||||||
bool appInitialized()
|
|
||||||
{
|
|
||||||
return isAppInitialized;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/Singleton.hpp"
|
||||||
#include "singletons/Resources.hpp"
|
#include "singletons/Resources.hpp"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
class Singleton;
|
|
||||||
|
|
||||||
class TwitchServer;
|
class TwitchServer;
|
||||||
class PubSub;
|
class PubSub;
|
||||||
|
|
||||||
|
@ -24,45 +24,47 @@ class Logging;
|
||||||
class Paths;
|
class Paths;
|
||||||
class AccountManager;
|
class AccountManager;
|
||||||
class Emotes;
|
class Emotes;
|
||||||
class NativeMessaging;
|
|
||||||
class Settings;
|
class Settings;
|
||||||
class Fonts;
|
class Fonts;
|
||||||
class Resources;
|
class Resources;
|
||||||
|
|
||||||
class Application
|
class Application
|
||||||
{
|
{
|
||||||
Application(int _argc, char **_argv);
|
std::vector<std::unique_ptr<Singleton>> singletons_;
|
||||||
|
int argc_;
|
||||||
|
char **argv_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void instantiate(int argc_, char **argv_);
|
static Application *instance;
|
||||||
|
|
||||||
~Application() = delete;
|
Application(Settings &settings, Paths &paths);
|
||||||
|
|
||||||
void construct();
|
void initialize(Settings &settings, Paths &paths);
|
||||||
void initialize();
|
|
||||||
void load();
|
void load();
|
||||||
|
void save();
|
||||||
|
|
||||||
int run(QApplication &qtApp);
|
int run(QApplication &qtApp);
|
||||||
|
|
||||||
friend void test();
|
friend void test();
|
||||||
|
|
||||||
[[deprecated("use getSettings() instead")]] Settings *settings = nullptr;
|
Settings *const settings = nullptr;
|
||||||
[[deprecated("use getPaths() instead")]] Paths *paths = nullptr;
|
Paths *const paths = nullptr;
|
||||||
|
Resources2 *const resources;
|
||||||
|
|
||||||
Theme *themes = nullptr;
|
Theme *const themes = nullptr;
|
||||||
WindowManager *windows = nullptr;
|
Fonts *const fonts = nullptr;
|
||||||
Logging *logging = nullptr;
|
Emotes *const emotes = nullptr;
|
||||||
CommandController *commands = nullptr;
|
WindowManager *const windows = nullptr;
|
||||||
HighlightController *highlights = nullptr;
|
|
||||||
IgnoreController *ignores = nullptr;
|
AccountController *const accounts = nullptr;
|
||||||
TaggedUsersController *taggedUsers = nullptr;
|
CommandController *const commands = nullptr;
|
||||||
AccountController *accounts = nullptr;
|
HighlightController *const highlights = nullptr;
|
||||||
Emotes *emotes = nullptr;
|
IgnoreController *const ignores = nullptr;
|
||||||
NativeMessaging *nativeMessaging = nullptr;
|
TaggedUsersController *const taggedUsers = nullptr;
|
||||||
Fonts *fonts = nullptr;
|
ModerationActions *const moderationActions = nullptr;
|
||||||
Resources *resources = nullptr;
|
TwitchServer *const twitch2 = nullptr;
|
||||||
ModerationActions *moderationActions = nullptr;
|
|
||||||
TwitchServer *twitch2 = nullptr;
|
[[deprecated]] Logging *const logging = nullptr;
|
||||||
|
|
||||||
/// Provider-specific
|
/// Provider-specific
|
||||||
struct {
|
struct {
|
||||||
|
@ -70,22 +72,20 @@ public:
|
||||||
[[deprecated("use twitch2->pubsub instead")]] PubSub *pubsub = nullptr;
|
[[deprecated("use twitch2->pubsub instead")]] PubSub *pubsub = nullptr;
|
||||||
} twitch;
|
} twitch;
|
||||||
|
|
||||||
void save();
|
|
||||||
|
|
||||||
// Special application mode that only initializes the native messaging host
|
|
||||||
static void runNativeMessagingHost();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addSingleton(Singleton *singleton);
|
void addSingleton(Singleton *singleton);
|
||||||
|
void initPubsub();
|
||||||
|
void initNm();
|
||||||
|
|
||||||
int argc_;
|
template <typename T, typename = std::enable_if_t<std::is_base_of<Singleton, T>::value>>
|
||||||
char **argv_;
|
T &emplace()
|
||||||
|
{
|
||||||
std::vector<Singleton *> singletons_;
|
auto t = new T;
|
||||||
|
this->singletons_.push_back(std::unique_ptr<T>(t));
|
||||||
|
return *t;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Application *getApp();
|
Application *getApp();
|
||||||
|
|
||||||
bool appInitialized();
|
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
88
src/BrowserExtension.cpp
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#include "BrowserExtension.hpp"
|
||||||
|
|
||||||
|
#include "singletons/NativeMessaging.hpp"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void initFileMode()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
_setmode(_fileno(stdin), _O_BINARY);
|
||||||
|
_setmode(_fileno(stdout), _O_BINARY);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void runLoop(NativeMessagingClient &client)
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
char size_c[4];
|
||||||
|
std::cin.read(size_c, 4);
|
||||||
|
|
||||||
|
if (std::cin.eof()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t size = *reinterpret_cast<uint32_t *>(size_c);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
bool bigEndian = isBigEndian();
|
||||||
|
// To avoid breaking strict-aliasing rules and potentially inducing undefined behaviour, the following code can be run instead
|
||||||
|
uint32_t size = 0;
|
||||||
|
if (bigEndian) {
|
||||||
|
size = size_c[3] | static_cast<uint32_t>(size_c[2]) << 8 |
|
||||||
|
static_cast<uint32_t>(size_c[1]) << 16 | static_cast<uint32_t>(size_c[0]) << 24;
|
||||||
|
} else {
|
||||||
|
size = size_c[0] | static_cast<uint32_t>(size_c[1]) << 8 |
|
||||||
|
static_cast<uint32_t>(size_c[2]) << 16 | static_cast<uint32_t>(size_c[3]) << 24;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::unique_ptr<char[]> b(new char[size + 1]);
|
||||||
|
std::cin.read(b.get(), size);
|
||||||
|
*(b.get() + size) = '\0';
|
||||||
|
|
||||||
|
client.sendMessage(QByteArray::fromRawData(b.get(), static_cast<int32_t>(size)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool shouldRunBrowserExtensionHost(const QStringList &args)
|
||||||
|
{
|
||||||
|
return args.size() > 0 &&
|
||||||
|
(args[0].startsWith("chrome-extension://") || args[0].endsWith(".json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void runBrowserExtensionHost()
|
||||||
|
{
|
||||||
|
initFileMode();
|
||||||
|
|
||||||
|
std::atomic<bool> ping(false);
|
||||||
|
|
||||||
|
QTimer timer;
|
||||||
|
QObject::connect(&timer, &QTimer::timeout, [&ping] {
|
||||||
|
if (!ping.exchange(false)) {
|
||||||
|
_Exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
timer.setInterval(11000);
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
NativeMessagingClient client;
|
||||||
|
|
||||||
|
runLoop(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chatterino
|
10
src/BrowserExtension.hpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class QStringList;
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
bool shouldRunBrowserExtensionHost(const QStringList &args);
|
||||||
|
void runBrowserExtensionHost();
|
||||||
|
|
||||||
|
} // namespace chatterino
|
130
src/RunGui.cpp
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
#include "RunGui.hpp"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QPalette>
|
||||||
|
#include <QStyleFactory>
|
||||||
|
|
||||||
|
#include "Application.hpp"
|
||||||
|
#include "common/NetworkManager.hpp"
|
||||||
|
#include "singletons/Paths.hpp"
|
||||||
|
#include "singletons/Updates.hpp"
|
||||||
|
#include "widgets/dialogs/LastRunCrashDialog.hpp"
|
||||||
|
|
||||||
|
#ifdef C_USE_BREAKPAD
|
||||||
|
#include <QBreakpadHandler.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// void initQt();
|
||||||
|
// void installCustomPalette();
|
||||||
|
// void showLastCrashDialog();
|
||||||
|
// void createRunningFile(const QString &path);
|
||||||
|
// void removeRunningFile(const QString &path);
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace {
|
||||||
|
void installCustomPalette()
|
||||||
|
{
|
||||||
|
// borrowed from
|
||||||
|
// https://stackoverflow.com/questions/15035767/is-the-qt-5-dark-fusion-theme-available-for-windows
|
||||||
|
QPalette darkPalette = qApp->palette();
|
||||||
|
|
||||||
|
darkPalette.setColor(QPalette::Window, QColor(22, 22, 22));
|
||||||
|
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(127, 127, 127));
|
||||||
|
darkPalette.setColor(QPalette::Base, QColor("#333"));
|
||||||
|
darkPalette.setColor(QPalette::AlternateBase, QColor("#444"));
|
||||||
|
darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::Text, QColor(127, 127, 127));
|
||||||
|
darkPalette.setColor(QPalette::Dark, QColor(35, 35, 35));
|
||||||
|
darkPalette.setColor(QPalette::Shadow, QColor(20, 20, 20));
|
||||||
|
darkPalette.setColor(QPalette::Button, QColor(70, 70, 70));
|
||||||
|
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(127, 127, 127));
|
||||||
|
darkPalette.setColor(QPalette::BrightText, Qt::red);
|
||||||
|
darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
|
||||||
|
darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::Highlight, QColor(80, 80, 80));
|
||||||
|
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor(127, 127, 127));
|
||||||
|
|
||||||
|
qApp->setPalette(darkPalette);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initQt()
|
||||||
|
{
|
||||||
|
// set up the QApplication flags
|
||||||
|
QApplication::setAttribute(Qt::AA_Use96Dpi, true);
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
QApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QApplication::setStyle(QStyleFactory::create("Fusion"));
|
||||||
|
|
||||||
|
installCustomPalette();
|
||||||
|
}
|
||||||
|
|
||||||
|
void showLastCrashDialog()
|
||||||
|
{
|
||||||
|
#ifndef C_DISABLE_CRASH_DIALOG
|
||||||
|
LastRunCrashDialog dialog;
|
||||||
|
|
||||||
|
switch (dialog.exec()) {
|
||||||
|
case QDialog::Accepted: {
|
||||||
|
}; break;
|
||||||
|
default: {
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void createRunningFile(const QString &path)
|
||||||
|
{
|
||||||
|
QFile runningFile(path);
|
||||||
|
|
||||||
|
runningFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||||||
|
runningFile.flush();
|
||||||
|
runningFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeRunningFile(const QString &path)
|
||||||
|
{
|
||||||
|
QFile::remove(path);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void runGui(QApplication &a, Paths &paths, Settings &settings)
|
||||||
|
{
|
||||||
|
chatterino::NetworkManager::init();
|
||||||
|
chatterino::Updates::getInstance().checkForUpdates();
|
||||||
|
|
||||||
|
#ifdef C_USE_BREAKPAD
|
||||||
|
QBreakpadInstance.setDumpPath(app->paths->settingsFolderPath + "/Crashes");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Running file
|
||||||
|
auto runningPath = paths.miscDirectory + "/running_" + paths.applicationFilePathHash;
|
||||||
|
|
||||||
|
if (QFile::exists(runningPath)) {
|
||||||
|
showLastCrashDialog();
|
||||||
|
} else {
|
||||||
|
createRunningFile(runningPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Application app(settings, paths);
|
||||||
|
app.initialize(settings, paths);
|
||||||
|
app.run(a);
|
||||||
|
app.save();
|
||||||
|
|
||||||
|
removeRunningFile(runningPath);
|
||||||
|
|
||||||
|
pajlada::Settings::SettingManager::gSave();
|
||||||
|
|
||||||
|
chatterino::NetworkManager::deinit();
|
||||||
|
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
} // namespace chatterino
|
10
src/RunGui.hpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class QApplication;
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
class Paths;
|
||||||
|
class Settings;
|
||||||
|
|
||||||
|
void runGui(QApplication &a, Paths &paths, Settings &settings);
|
||||||
|
} // namespace chatterino
|
44
src/autogenerated/ResourcesAutogen.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include "ResourcesAutogen.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
Resources2::Resources2()
|
||||||
|
{
|
||||||
|
this->avatars.fourtf = QPixmap(":/avatars/fourtf.png");
|
||||||
|
this->avatars.pajlada = QPixmap(":/avatars/pajlada.png");
|
||||||
|
this->buttons.ban = QPixmap(":/buttons/ban.png");
|
||||||
|
this->buttons.banRed = QPixmap(":/buttons/banRed.png");
|
||||||
|
this->buttons.menuDark = QPixmap(":/buttons/menuDark.png");
|
||||||
|
this->buttons.menuLight = QPixmap(":/buttons/menuLight.png");
|
||||||
|
this->buttons.mod = QPixmap(":/buttons/mod.png");
|
||||||
|
this->buttons.modModeDisabled = QPixmap(":/buttons/modModeDisabled.png");
|
||||||
|
this->buttons.modModeDisabled2 = QPixmap(":/buttons/modModeDisabled2.png");
|
||||||
|
this->buttons.modModeEnabled = QPixmap(":/buttons/modModeEnabled.png");
|
||||||
|
this->buttons.modModeEnabled2 = QPixmap(":/buttons/modModeEnabled2.png");
|
||||||
|
this->buttons.timeout = QPixmap(":/buttons/timeout.png");
|
||||||
|
this->buttons.unban = QPixmap(":/buttons/unban.png");
|
||||||
|
this->buttons.unmod = QPixmap(":/buttons/unmod.png");
|
||||||
|
this->buttons.update = QPixmap(":/buttons/update.png");
|
||||||
|
this->buttons.updateError = QPixmap(":/buttons/updateError.png");
|
||||||
|
this->error = QPixmap(":/error.png");
|
||||||
|
this->icon = QPixmap(":/icon.png");
|
||||||
|
this->pajaDank = QPixmap(":/pajaDank.png");
|
||||||
|
this->settings.aboutlogo = QPixmap(":/settings/aboutlogo.png");
|
||||||
|
this->split.down = QPixmap(":/split/down.png");
|
||||||
|
this->split.left = QPixmap(":/split/left.png");
|
||||||
|
this->split.move = QPixmap(":/split/move.png");
|
||||||
|
this->split.right = QPixmap(":/split/right.png");
|
||||||
|
this->split.up = QPixmap(":/split/up.png");
|
||||||
|
this->twitch.admin = QPixmap(":/twitch/admin.png");
|
||||||
|
this->twitch.broadcaster = QPixmap(":/twitch/broadcaster.png");
|
||||||
|
this->twitch.cheer1 = QPixmap(":/twitch/cheer1.png");
|
||||||
|
this->twitch.globalmod = QPixmap(":/twitch/globalmod.png");
|
||||||
|
this->twitch.moderator = QPixmap(":/twitch/moderator.png");
|
||||||
|
this->twitch.prime = QPixmap(":/twitch/prime.png");
|
||||||
|
this->twitch.staff = QPixmap(":/twitch/staff.png");
|
||||||
|
this->twitch.subscriber = QPixmap(":/twitch/subscriber.png");
|
||||||
|
this->twitch.turbo = QPixmap(":/twitch/turbo.png");
|
||||||
|
this->twitch.verified = QPixmap(":/twitch/verified.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chatterino
|
57
src/autogenerated/ResourcesAutogen.hpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#include <QPixmap>
|
||||||
|
#include "common/Singleton.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
class Resources2 : public Singleton {
|
||||||
|
public:
|
||||||
|
Resources2();
|
||||||
|
|
||||||
|
struct {
|
||||||
|
QPixmap fourtf;
|
||||||
|
QPixmap pajlada;
|
||||||
|
} avatars;
|
||||||
|
struct {
|
||||||
|
QPixmap ban;
|
||||||
|
QPixmap banRed;
|
||||||
|
QPixmap menuDark;
|
||||||
|
QPixmap menuLight;
|
||||||
|
QPixmap mod;
|
||||||
|
QPixmap modModeDisabled;
|
||||||
|
QPixmap modModeDisabled2;
|
||||||
|
QPixmap modModeEnabled;
|
||||||
|
QPixmap modModeEnabled2;
|
||||||
|
QPixmap timeout;
|
||||||
|
QPixmap unban;
|
||||||
|
QPixmap unmod;
|
||||||
|
QPixmap update;
|
||||||
|
QPixmap updateError;
|
||||||
|
} buttons;
|
||||||
|
QPixmap error;
|
||||||
|
QPixmap icon;
|
||||||
|
QPixmap pajaDank;
|
||||||
|
struct {
|
||||||
|
QPixmap aboutlogo;
|
||||||
|
} settings;
|
||||||
|
struct {
|
||||||
|
QPixmap down;
|
||||||
|
QPixmap left;
|
||||||
|
QPixmap move;
|
||||||
|
QPixmap right;
|
||||||
|
QPixmap up;
|
||||||
|
} split;
|
||||||
|
struct {
|
||||||
|
QPixmap admin;
|
||||||
|
QPixmap broadcaster;
|
||||||
|
QPixmap cheer1;
|
||||||
|
QPixmap globalmod;
|
||||||
|
QPixmap moderator;
|
||||||
|
QPixmap prime;
|
||||||
|
QPixmap staff;
|
||||||
|
QPixmap subscriber;
|
||||||
|
QPixmap turbo;
|
||||||
|
QPixmap verified;
|
||||||
|
} twitch;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino
|
34
src/common/Aliases.hpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QString>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#define QStringAlias(name) \
|
||||||
|
namespace chatterino { \
|
||||||
|
struct name { \
|
||||||
|
QString string; \
|
||||||
|
bool operator==(const name &other) const \
|
||||||
|
{ \
|
||||||
|
return this->string == other.string; \
|
||||||
|
} \
|
||||||
|
bool operator!=(const name &other) const \
|
||||||
|
{ \
|
||||||
|
return this->string != other.string; \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
} /* namespace chatterino */ \
|
||||||
|
namespace std { \
|
||||||
|
template <> \
|
||||||
|
struct hash<chatterino::name> { \
|
||||||
|
size_t operator()(const chatterino::name &s) const \
|
||||||
|
{ \
|
||||||
|
return qHash(s.string); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
} /* namespace std */
|
||||||
|
|
||||||
|
QStringAlias(UserName);
|
||||||
|
QStringAlias(UserId);
|
||||||
|
QStringAlias(Url);
|
||||||
|
QStringAlias(Tooltip);
|
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
Channel::Channel(const QString &_name, Type type)
|
Channel::Channel(const QString &name, Type type)
|
||||||
: name(_name)
|
: completionModel(name)
|
||||||
, completionModel(this->name)
|
, name_(name)
|
||||||
, type_(type)
|
, type_(type)
|
||||||
{
|
{
|
||||||
QObject::connect(&this->clearCompletionModelTimer_, &QTimer::timeout, [this]() {
|
QObject::connect(&this->clearCompletionModelTimer_, &QTimer::timeout, [this]() {
|
||||||
|
@ -38,6 +38,11 @@ Channel::Type Channel::getType() const
|
||||||
return this->type_;
|
return this->type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString &Channel::getName() const
|
||||||
|
{
|
||||||
|
return this->name_;
|
||||||
|
}
|
||||||
|
|
||||||
bool Channel::isTwitchChannel() const
|
bool Channel::isTwitchChannel() const
|
||||||
{
|
{
|
||||||
return this->type_ >= Type::Twitch && this->type_ < Type::TwitchEnd;
|
return this->type_ >= Type::Twitch && this->type_ < Type::TwitchEnd;
|
||||||
|
@ -45,7 +50,7 @@ bool Channel::isTwitchChannel() const
|
||||||
|
|
||||||
bool Channel::isEmpty() const
|
bool Channel::isEmpty() const
|
||||||
{
|
{
|
||||||
return this->name.isEmpty();
|
return this->name_.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
LimitedQueueSnapshot<MessagePtr> Channel::getMessageSnapshot()
|
LimitedQueueSnapshot<MessagePtr> Channel::getMessageSnapshot()
|
||||||
|
@ -66,7 +71,7 @@ void Channel::addMessage(MessagePtr message)
|
||||||
|
|
||||||
// FOURTF: change this when adding more providers
|
// FOURTF: change this when adding more providers
|
||||||
if (this->isTwitchChannel()) {
|
if (this->isTwitchChannel()) {
|
||||||
app->logging->addMessage(this->name, message);
|
app->logging->addMessage(this->name_, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->messages_.pushBack(message, deleted)) {
|
if (this->messages_.pushBack(message, deleted)) {
|
||||||
|
|
|
@ -41,6 +41,7 @@ public:
|
||||||
pajlada::Signals::NoArgSignal destroyed;
|
pajlada::Signals::NoArgSignal destroyed;
|
||||||
|
|
||||||
Type getType() const;
|
Type getType() const;
|
||||||
|
const QString &getName() const;
|
||||||
bool isTwitchChannel() const;
|
bool isTwitchChannel() const;
|
||||||
virtual bool isEmpty() const;
|
virtual bool isEmpty() const;
|
||||||
LimitedQueueSnapshot<MessagePtr> getMessageSnapshot();
|
LimitedQueueSnapshot<MessagePtr> getMessageSnapshot();
|
||||||
|
@ -52,7 +53,6 @@ public:
|
||||||
void replaceMessage(MessagePtr message, MessagePtr replacement);
|
void replaceMessage(MessagePtr message, MessagePtr replacement);
|
||||||
virtual void addRecentChatter(const std::shared_ptr<Message> &message);
|
virtual void addRecentChatter(const std::shared_ptr<Message> &message);
|
||||||
|
|
||||||
QString name;
|
|
||||||
QStringList modList;
|
QStringList modList;
|
||||||
|
|
||||||
virtual bool canSendMessage() const;
|
virtual bool canSendMessage() const;
|
||||||
|
@ -72,6 +72,7 @@ protected:
|
||||||
virtual void onConnected();
|
virtual void onConnected();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const QString name_;
|
||||||
LimitedQueue<MessagePtr> messages_;
|
LimitedQueue<MessagePtr> messages_;
|
||||||
Type type_;
|
Type type_;
|
||||||
QTimer clearCompletionModelTimer_;
|
QTimer clearCompletionModelTimer_;
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/Aliases.hpp"
|
||||||
|
#include "common/Outcome.hpp"
|
||||||
|
#include "common/ProviderId.hpp"
|
||||||
#include "debug/Log.hpp"
|
#include "debug/Log.hpp"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
#include <boost/preprocessor.hpp>
|
#include <boost/preprocessor.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -27,14 +31,10 @@ const Qt::KeyboardModifiers showResizeHandlesModifiers = Qt::ControlModifier;
|
||||||
|
|
||||||
static const char *ANONYMOUS_USERNAME_LABEL ATTR_UNUSED = " - anonymous - ";
|
static const char *ANONYMOUS_USERNAME_LABEL ATTR_UNUSED = " - anonymous - ";
|
||||||
|
|
||||||
#define return_if(condition) \
|
template <typename T>
|
||||||
if ((condition)) { \
|
std::weak_ptr<T> weakOf(T *element)
|
||||||
return; \
|
{
|
||||||
}
|
return element->shared_from_this();
|
||||||
|
}
|
||||||
#define return_unless(condition) \
|
|
||||||
if (!(condition)) { \
|
|
||||||
return; \
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
#include "Application.hpp"
|
#include "Application.hpp"
|
||||||
#include "common/Common.hpp"
|
#include "common/Common.hpp"
|
||||||
|
#include "controllers/accounts/AccountController.hpp"
|
||||||
#include "controllers/commands/CommandController.hpp"
|
#include "controllers/commands/CommandController.hpp"
|
||||||
#include "debug/Log.hpp"
|
#include "debug/Log.hpp"
|
||||||
|
#include "providers/twitch/TwitchServer.hpp"
|
||||||
#include "singletons/Emotes.hpp"
|
#include "singletons/Emotes.hpp"
|
||||||
|
|
||||||
#include <QtAlgorithms>
|
#include <QtAlgorithms>
|
||||||
|
@ -107,41 +109,45 @@ void CompletionModel::refresh()
|
||||||
auto app = getApp();
|
auto app = getApp();
|
||||||
|
|
||||||
// User-specific: Twitch Emotes
|
// User-specific: Twitch Emotes
|
||||||
// TODO: Fix this so it properly updates with the proper api. oauth token needs proper scope
|
if (auto account = app->accounts->twitch.getCurrent()) {
|
||||||
for (const auto &m : app->emotes->twitch.emotes) {
|
for (const auto &emote : account->accessEmotes()->allEmoteNames) {
|
||||||
for (const auto &emoteName : m.second.emoteCodes) {
|
|
||||||
// XXX: No way to discern between a twitch global emote and sub emote right now
|
// XXX: No way to discern between a twitch global emote and sub emote right now
|
||||||
this->addString(emoteName, TaggedString::Type::TwitchGlobalEmote);
|
this->addString(emote.string, TaggedString::Type::TwitchGlobalEmote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global: BTTV Global Emotes
|
// // Global: BTTV Global Emotes
|
||||||
std::vector<QString> &bttvGlobalEmoteCodes = app->emotes->bttv.globalEmoteCodes;
|
// std::vector<QString> &bttvGlobalEmoteCodes = app->emotes->bttv.globalEmoteNames_;
|
||||||
for (const auto &m : bttvGlobalEmoteCodes) {
|
// for (const auto &m : bttvGlobalEmoteCodes) {
|
||||||
this->addString(m, TaggedString::Type::BTTVGlobalEmote);
|
// this->addString(m, TaggedString::Type::BTTVGlobalEmote);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Global: FFZ Global Emotes
|
// // Global: FFZ Global Emotes
|
||||||
std::vector<QString> &ffzGlobalEmoteCodes = app->emotes->ffz.globalEmoteCodes;
|
// std::vector<QString> &ffzGlobalEmoteCodes = app->emotes->ffz.globalEmoteCodes;
|
||||||
for (const auto &m : ffzGlobalEmoteCodes) {
|
// for (const auto &m : ffzGlobalEmoteCodes) {
|
||||||
this->addString(m, TaggedString::Type::FFZGlobalEmote);
|
// this->addString(m, TaggedString::Type::FFZGlobalEmote);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Channel-specific: BTTV Channel Emotes
|
// Channel emotes
|
||||||
std::vector<QString> &bttvChannelEmoteCodes =
|
if (auto channel = dynamic_cast<TwitchChannel *>(
|
||||||
app->emotes->bttv.channelEmoteCodes[this->channelName_];
|
getApp()->twitch2->getChannelOrEmptyByID(this->channelName_).get())) {
|
||||||
for (const auto &m : bttvChannelEmoteCodes) {
|
auto bttv = channel->accessBttvEmotes();
|
||||||
this->addString(m, TaggedString::Type::BTTVChannelEmote);
|
// auto it = bttv->begin();
|
||||||
}
|
// for (const auto &emote : *bttv) {
|
||||||
|
// }
|
||||||
|
// std::vector<QString> &bttvChannelEmoteCodes =
|
||||||
|
// app->emotes->bttv.channelEmoteName_[this->channelName_];
|
||||||
|
// for (const auto &m : bttvChannelEmoteCodes) {
|
||||||
|
// this->addString(m, TaggedString::Type::BTTVChannelEmote);
|
||||||
|
// }
|
||||||
|
|
||||||
// Channel-specific: FFZ Channel Emotes
|
// Channel-specific: FFZ Channel Emotes
|
||||||
std::vector<QString> &ffzChannelEmoteCodes =
|
for (const auto &emote : *channel->accessFfzEmotes()) {
|
||||||
app->emotes->ffz.channelEmoteCodes[this->channelName_];
|
this->addString(emote.second->name.string, TaggedString::Type::FFZChannelEmote);
|
||||||
for (const auto &m : ffzChannelEmoteCodes) {
|
}
|
||||||
this->addString(m, TaggedString::Type::FFZChannelEmote);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global: Emojis
|
// Emojis
|
||||||
const auto &emojiShortCodes = app->emotes->emojis.shortCodes;
|
const auto &emojiShortCodes = app->emotes->emojis.shortCodes;
|
||||||
for (const auto &m : emojiShortCodes) {
|
for (const auto &m : emojiShortCodes) {
|
||||||
this->addString(":" + m + ":", TaggedString::Type::Emoji);
|
this->addString(":" + m + ":", TaggedString::Type::Emoji);
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
class TwitchChannel;
|
||||||
|
|
||||||
class CompletionModel : public QAbstractListModel
|
class CompletionModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
struct TaggedString {
|
struct TaggedString {
|
||||||
|
|
|
@ -5,42 +5,42 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
EmoteData::EmoteData(Image *image)
|
// EmoteData::EmoteData(Image *image)
|
||||||
: image1x(image)
|
// : image1x(image)
|
||||||
{
|
//{
|
||||||
}
|
//}
|
||||||
|
|
||||||
// Emotes must have a 1x image to be valid
|
//// Emotes must have a 1x image to be valid
|
||||||
bool EmoteData::isValid() const
|
// bool EmoteData::isValid() const
|
||||||
{
|
//{
|
||||||
return this->image1x != nullptr;
|
// return this->image1x != nullptr;
|
||||||
}
|
//}
|
||||||
|
|
||||||
Image *EmoteData::getImage(float scale) const
|
// Image *EmoteData::getImage(float scale) const
|
||||||
{
|
//{
|
||||||
int quality = getApp()->settings->preferredEmoteQuality;
|
// int quality = getApp()->settings->preferredEmoteQuality;
|
||||||
|
|
||||||
if (quality == 0) {
|
// if (quality == 0) {
|
||||||
scale *= getApp()->settings->emoteScale.getValue();
|
// scale *= getApp()->settings->emoteScale.getValue();
|
||||||
quality = [&] {
|
// quality = [&] {
|
||||||
if (scale <= 1)
|
// if (scale <= 1)
|
||||||
return 1;
|
// return 1;
|
||||||
if (scale <= 2)
|
// if (scale <= 2)
|
||||||
return 2;
|
// return 2;
|
||||||
return 3;
|
// return 3;
|
||||||
}();
|
// }();
|
||||||
}
|
// }
|
||||||
|
|
||||||
Image *_image;
|
// Image *_image;
|
||||||
if (quality == 3 && this->image3x != nullptr) {
|
// if (quality == 3 && this->image3x != nullptr) {
|
||||||
_image = this->image3x;
|
// _image = this->image3x;
|
||||||
} else if (quality >= 2 && this->image2x != nullptr) {
|
// } else if (quality >= 2 && this->image2x != nullptr) {
|
||||||
_image = this->image2x;
|
// _image = this->image2x;
|
||||||
} else {
|
// } else {
|
||||||
_image = this->image1x;
|
// _image = this->image1x;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return _image;
|
// return _image;
|
||||||
}
|
//}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -5,23 +5,23 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
struct EmoteData {
|
// struct EmoteData {
|
||||||
EmoteData() = default;
|
// EmoteData() = default;
|
||||||
|
|
||||||
EmoteData(Image *image);
|
// EmoteData(Image *image);
|
||||||
|
|
||||||
// Emotes must have a 1x image to be valid
|
// // Emotes must have a 1x image to be valid
|
||||||
bool isValid() const;
|
// bool isValid() const;
|
||||||
Image *getImage(float scale) const;
|
// Image *getImage(float scale) const;
|
||||||
|
|
||||||
// Link to the emote page i.e. https://www.frankerfacez.com/emoticon/144722-pajaCringe
|
// // Link to the emote page i.e. https://www.frankerfacez.com/emoticon/144722-pajaCringe
|
||||||
QString pageLink;
|
// QString pageLink;
|
||||||
|
|
||||||
Image *image1x = nullptr;
|
// Image *image1x = nullptr;
|
||||||
Image *image2x = nullptr;
|
// Image *image2x = nullptr;
|
||||||
Image *image3x = nullptr;
|
// Image *image3x = nullptr;
|
||||||
};
|
//};
|
||||||
|
|
||||||
using EmoteMap = ConcurrentMap<QString, EmoteData>;
|
// using EmoteMap = ConcurrentMap<QString, EmoteData>;
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
class QNetworkReply;
|
class QNetworkReply;
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
class NetworkResult;
|
class NetworkResult;
|
||||||
|
|
||||||
using NetworkSuccessCallback = std::function<bool(NetworkResult)>;
|
using NetworkSuccessCallback = std::function<Outcome(NetworkResult)>;
|
||||||
using NetworkErrorCallback = std::function<bool(int)>;
|
using NetworkErrorCallback = std::function<bool(int)>;
|
||||||
using NetworkReplyCreatedCallback = std::function<void(QNetworkReply *)>;
|
using NetworkReplyCreatedCallback = std::function<void(QNetworkReply *)>;
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,23 @@
|
||||||
|
|
||||||
#include "Application.hpp"
|
#include "Application.hpp"
|
||||||
#include "singletons/Paths.hpp"
|
#include "singletons/Paths.hpp"
|
||||||
|
#include "util/DebugCount.hpp"
|
||||||
|
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
NetworkData::NetworkData()
|
||||||
|
{
|
||||||
|
DebugCount::increase("NetworkData");
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkData::~NetworkData()
|
||||||
|
{
|
||||||
|
DebugCount::decrease("NetworkData");
|
||||||
|
}
|
||||||
|
|
||||||
QString NetworkData::getHash()
|
QString NetworkData::getHash()
|
||||||
{
|
{
|
||||||
if (this->hash_.isEmpty()) {
|
if (this->hash_.isEmpty()) {
|
||||||
|
|
|
@ -13,6 +13,9 @@ namespace chatterino {
|
||||||
class NetworkResult;
|
class NetworkResult;
|
||||||
|
|
||||||
struct NetworkData {
|
struct NetworkData {
|
||||||
|
NetworkData();
|
||||||
|
~NetworkData();
|
||||||
|
|
||||||
QNetworkRequest request_;
|
QNetworkRequest request_;
|
||||||
const QObject *caller_ = nullptr;
|
const QObject *caller_ = nullptr;
|
||||||
bool useQuickLoadCache_{};
|
bool useQuickLoadCache_{};
|
||||||
|
|
|
@ -129,7 +129,7 @@ void NetworkRequest::execute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetworkRequest::tryLoadCachedFile()
|
Outcome NetworkRequest::tryLoadCachedFile()
|
||||||
{
|
{
|
||||||
auto app = getApp();
|
auto app = getApp();
|
||||||
|
|
||||||
|
@ -137,24 +137,24 @@ bool NetworkRequest::tryLoadCachedFile()
|
||||||
|
|
||||||
if (!cachedFile.exists()) {
|
if (!cachedFile.exists()) {
|
||||||
// File didn't exist
|
// File didn't exist
|
||||||
return false;
|
return Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cachedFile.open(QIODevice::ReadOnly)) {
|
if (!cachedFile.open(QIODevice::ReadOnly)) {
|
||||||
// File could not be opened
|
// File could not be opened
|
||||||
return false;
|
return Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray bytes = cachedFile.readAll();
|
QByteArray bytes = cachedFile.readAll();
|
||||||
NetworkResult result(bytes);
|
NetworkResult result(bytes);
|
||||||
|
|
||||||
bool success = this->data->onSuccess_(result);
|
auto outcome = this->data->onSuccess_(result);
|
||||||
|
|
||||||
cachedFile.close();
|
cachedFile.close();
|
||||||
|
|
||||||
// XXX: If success is false, we should invalidate the cache file somehow/somewhere
|
// XXX: If success is false, we should invalidate the cache file somehow/somewhere
|
||||||
|
|
||||||
return success;
|
return outcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkRequest::doRequest()
|
void NetworkRequest::doRequest()
|
||||||
|
@ -167,20 +167,21 @@ void NetworkRequest::doRequest()
|
||||||
this->timer->start();
|
this->timer->start();
|
||||||
|
|
||||||
auto onUrlRequested = [data = this->data, timer = this->timer, worker]() mutable {
|
auto onUrlRequested = [data = this->data, timer = this->timer, worker]() mutable {
|
||||||
QNetworkReply *reply = nullptr;
|
auto reply = [&]() -> QNetworkReply * {
|
||||||
switch (data->requestType_) {
|
switch (data->requestType_) {
|
||||||
case NetworkRequestType::Get: {
|
case NetworkRequestType::Get:
|
||||||
reply = NetworkManager::NaM.get(data->request_);
|
return NetworkManager::NaM.get(data->request_);
|
||||||
} break;
|
|
||||||
|
|
||||||
case NetworkRequestType::Put: {
|
case NetworkRequestType::Put:
|
||||||
reply = NetworkManager::NaM.put(data->request_, data->payload_);
|
return NetworkManager::NaM.put(data->request_, data->payload_);
|
||||||
} break;
|
|
||||||
|
|
||||||
case NetworkRequestType::Delete: {
|
case NetworkRequestType::Delete:
|
||||||
reply = NetworkManager::NaM.deleteResource(data->request_);
|
return NetworkManager::NaM.deleteResource(data->request_);
|
||||||
} break;
|
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
if (reply == nullptr) {
|
if (reply == nullptr) {
|
||||||
Log("Unhandled request type");
|
Log("Unhandled request type");
|
||||||
|
@ -201,8 +202,6 @@ void NetworkRequest::doRequest()
|
||||||
data->onReplyCreated_(reply);
|
data->onReplyCreated_(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool directAction = (data->caller_ == nullptr);
|
|
||||||
|
|
||||||
auto handleReply = [data, timer, reply]() mutable {
|
auto handleReply = [data, timer, reply]() mutable {
|
||||||
// TODO(pajlada): A reply was received, kill the timeout timer
|
// TODO(pajlada): A reply was received, kill the timeout timer
|
||||||
if (reply->error() != QNetworkReply::NetworkError::NoError) {
|
if (reply->error() != QNetworkReply::NetworkError::NoError) {
|
||||||
|
@ -222,8 +221,7 @@ void NetworkRequest::doRequest()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data->caller_ != nullptr) {
|
if (data->caller_ != nullptr) {
|
||||||
QObject::connect(worker, &NetworkWorker::doneUrl, data->caller_,
|
QObject::connect(worker, &NetworkWorker::doneUrl, data->caller_, handleReply);
|
||||||
std::move(handleReply));
|
|
||||||
QObject::connect(reply, &QNetworkReply::finished, worker, [worker]() mutable {
|
QObject::connect(reply, &QNetworkReply::finished, worker, [worker]() mutable {
|
||||||
emit worker->doneUrl();
|
emit worker->doneUrl();
|
||||||
|
|
||||||
|
@ -231,7 +229,7 @@ void NetworkRequest::doRequest()
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
QObject::connect(reply, &QNetworkReply::finished, worker,
|
QObject::connect(reply, &QNetworkReply::finished, worker,
|
||||||
[handleReply = std::move(handleReply), worker]() mutable {
|
[handleReply, worker]() mutable {
|
||||||
handleReply();
|
handleReply();
|
||||||
|
|
||||||
delete worker;
|
delete worker;
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
|
|
||||||
explicit NetworkRequest(const std::string &url,
|
explicit NetworkRequest(const std::string &url,
|
||||||
NetworkRequestType requestType = NetworkRequestType::Get);
|
NetworkRequestType requestType = NetworkRequestType::Get);
|
||||||
NetworkRequest(QUrl url, NetworkRequestType requestType = NetworkRequestType::Get);
|
explicit NetworkRequest(QUrl url, NetworkRequestType requestType = NetworkRequestType::Get);
|
||||||
|
|
||||||
~NetworkRequest();
|
~NetworkRequest();
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ private:
|
||||||
// Returns true if the file was successfully loaded from cache
|
// Returns true if the file was successfully loaded from cache
|
||||||
// Returns false if the cache file either didn't exist, or it contained "invalid" data
|
// Returns false if the cache file either didn't exist, or it contained "invalid" data
|
||||||
// "invalid" is specified by the onSuccess callback
|
// "invalid" is specified by the onSuccess callback
|
||||||
bool tryLoadCachedFile();
|
Outcome tryLoadCachedFile();
|
||||||
|
|
||||||
void doRequest();
|
void doRequest();
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ rapidjson::Document NetworkResult::parseRapidJson() const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray NetworkResult::getData() const
|
const QByteArray &NetworkResult::getData() const
|
||||||
{
|
{
|
||||||
return this->data_;
|
return this->data_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,15 @@ namespace chatterino {
|
||||||
|
|
||||||
class NetworkResult
|
class NetworkResult
|
||||||
{
|
{
|
||||||
QByteArray data_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NetworkResult(const QByteArray &data);
|
NetworkResult(const QByteArray &data);
|
||||||
|
|
||||||
QJsonObject parseJson() const;
|
QJsonObject parseJson() const;
|
||||||
rapidjson::Document parseRapidJson() const;
|
rapidjson::Document parseRapidJson() const;
|
||||||
QByteArray getData() const;
|
const QByteArray &getData() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArray data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -23,7 +25,7 @@ public:
|
||||||
return element_;
|
return element_;
|
||||||
}
|
}
|
||||||
|
|
||||||
T &operator*() const
|
typename std::add_lvalue_reference<T>::type operator*() const
|
||||||
{
|
{
|
||||||
assert(this->hasElement());
|
assert(this->hasElement());
|
||||||
|
|
||||||
|
@ -52,6 +54,17 @@ public:
|
||||||
return this->hasElement();
|
return this->hasElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator!() const
|
||||||
|
{
|
||||||
|
return !this->hasElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename X = T, typename = std::enable_if_t<!std::is_const<X>::value>>
|
||||||
|
operator NullablePtr<const T>() const
|
||||||
|
{
|
||||||
|
return NullablePtr<const T>(this->element_);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T *element_;
|
T *element_;
|
||||||
};
|
};
|
||||||
|
|
51
src/common/Outcome.hpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
struct SuccessTag {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FailureTag {
|
||||||
|
};
|
||||||
|
|
||||||
|
const SuccessTag Success{};
|
||||||
|
const FailureTag Failure{};
|
||||||
|
|
||||||
|
class Outcome
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Outcome(SuccessTag)
|
||||||
|
: success_(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Outcome(FailureTag)
|
||||||
|
: success_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const
|
||||||
|
{
|
||||||
|
return this->success_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!() const
|
||||||
|
{
|
||||||
|
return !this->success_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Outcome &other) const
|
||||||
|
{
|
||||||
|
return this->success_ == other.success_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Outcome &other) const
|
||||||
|
{
|
||||||
|
return !this->operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool success_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino
|
|
@ -4,14 +4,18 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
class Application;
|
class Settings;
|
||||||
|
class Paths;
|
||||||
|
|
||||||
class Singleton : boost::noncopyable
|
class Singleton : boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void initialize(Application &app)
|
virtual ~Singleton() = default;
|
||||||
|
|
||||||
|
virtual void initialize(Settings &settings, Paths &paths)
|
||||||
{
|
{
|
||||||
(void)(app);
|
(void)(settings);
|
||||||
|
(void)(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void save()
|
virtual void save()
|
||||||
|
|
|
@ -10,52 +10,52 @@ class AccessGuard
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AccessGuard(T &element, std::mutex &mutex)
|
AccessGuard(T &element, std::mutex &mutex)
|
||||||
: element_(element)
|
: element_(&element)
|
||||||
, mutex_(mutex)
|
, mutex_(&mutex)
|
||||||
{
|
{
|
||||||
this->mutex_.lock();
|
this->mutex_->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessGuard(AccessGuard<T> &&other)
|
||||||
|
: element_(other.element_)
|
||||||
|
, mutex_(other.mutex_)
|
||||||
|
{
|
||||||
|
other.isValid_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessGuard<T> &operator=(AccessGuard<T> &&other)
|
||||||
|
{
|
||||||
|
other.isValid_ = false;
|
||||||
|
this->element_ = other.element_;
|
||||||
|
this->mutex_ = other.element_;
|
||||||
}
|
}
|
||||||
|
|
||||||
~AccessGuard()
|
~AccessGuard()
|
||||||
{
|
{
|
||||||
this->mutex_.unlock();
|
if (this->isValid_) this->mutex_->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
const T *operator->() const
|
T *operator->() const
|
||||||
{
|
|
||||||
return &this->element_;
|
|
||||||
}
|
|
||||||
|
|
||||||
T *operator->()
|
|
||||||
{
|
|
||||||
return &this->element_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T &operator*() const
|
|
||||||
{
|
{
|
||||||
return this->element_;
|
return this->element_;
|
||||||
}
|
}
|
||||||
|
|
||||||
T &operator*()
|
T &operator*() const
|
||||||
{
|
{
|
||||||
return this->element_;
|
return *this->element_;
|
||||||
}
|
|
||||||
|
|
||||||
T clone() const
|
|
||||||
{
|
|
||||||
return T(this->element_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T &element_;
|
T *element_;
|
||||||
std::mutex &mutex_;
|
std::mutex *mutex_;
|
||||||
|
bool isValid_ = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class UniqueAccess
|
class UniqueAccess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template <typename X = decltype(T())>
|
// template <typename X = decltype(T())>
|
||||||
UniqueAccess()
|
UniqueAccess()
|
||||||
: element_(T())
|
: element_(T())
|
||||||
{
|
{
|
||||||
|
@ -83,14 +83,15 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessGuard<T> access()
|
AccessGuard<T> access() const
|
||||||
{
|
{
|
||||||
return AccessGuard<T>(this->element_, this->mutex_);
|
return AccessGuard<T>(this->element_, this->mutex_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const AccessGuard<T> access() const
|
template <typename X = T, typename = std::enable_if_t<!std::is_const_v<X>>>
|
||||||
|
AccessGuard<const X> accessConst() const
|
||||||
{
|
{
|
||||||
return AccessGuard<T>(this->element_, this->mutex_);
|
return AccessGuard<const T>(this->element_, this->mutex_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -33,7 +33,7 @@ AccountController::AccountController()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountController::initialize(Application &app)
|
void AccountController::initialize(Settings &settings, Paths &paths)
|
||||||
{
|
{
|
||||||
this->twitch.load();
|
this->twitch.load();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,19 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
class Settings;
|
||||||
|
class Paths;
|
||||||
|
|
||||||
class AccountModel;
|
class AccountModel;
|
||||||
|
|
||||||
class AccountController : public Singleton
|
class AccountController final : public Singleton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AccountController();
|
AccountController();
|
||||||
|
|
||||||
AccountModel *createModel(QObject *parent);
|
AccountModel *createModel(QObject *parent);
|
||||||
|
|
||||||
virtual void initialize(Application &app) override;
|
virtual void initialize(Settings &settings, Paths &paths) override;
|
||||||
|
|
||||||
TwitchAccountManager twitch;
|
TwitchAccountManager twitch;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "providers/twitch/TwitchServer.hpp"
|
#include "providers/twitch/TwitchServer.hpp"
|
||||||
#include "singletons/Paths.hpp"
|
#include "singletons/Paths.hpp"
|
||||||
#include "singletons/Settings.hpp"
|
#include "singletons/Settings.hpp"
|
||||||
|
#include "util/CombinePath.hpp"
|
||||||
#include "widgets/dialogs/LogsPopup.hpp"
|
#include "widgets/dialogs/LogsPopup.hpp"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
@ -44,15 +45,14 @@ CommandController::CommandController()
|
||||||
this->items.itemRemoved.connect(addFirstMatchToMap);
|
this->items.itemRemoved.connect(addFirstMatchToMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandController::initialize(Application &app)
|
void CommandController::initialize(Settings &, Paths &paths)
|
||||||
{
|
{
|
||||||
this->load();
|
this->load(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandController::load()
|
void CommandController::load(Paths &paths)
|
||||||
{
|
{
|
||||||
auto app = getApp();
|
this->filePath_ = combinePath(paths.settingsDirectory, "commands.txt");
|
||||||
this->filePath_ = app->paths->settingsDirectory + "/commands.txt";
|
|
||||||
|
|
||||||
QFile textFile(this->filePath_);
|
QFile textFile(this->filePath_);
|
||||||
if (!textFile.open(QIODevice::ReadOnly)) {
|
if (!textFile.open(QIODevice::ReadOnly)) {
|
||||||
|
@ -140,7 +140,7 @@ QString CommandController::execCommand(const QString &text, ChannelPtr channel,
|
||||||
|
|
||||||
app->twitch.server->whispersChannel->addMessage(b.getMessage());
|
app->twitch.server->whispersChannel->addMessage(b.getMessage());
|
||||||
|
|
||||||
app->twitch.server->getWriteConnection()->sendRaw("PRIVMSG #jtv :" + text + "\r\n");
|
app->twitch.server->sendMessage("jtv", text);
|
||||||
|
|
||||||
if (getSettings()->inlineWhispers) {
|
if (getSettings()->inlineWhispers) {
|
||||||
app->twitch.server->forEachChannel(
|
app->twitch.server->forEachChannel(
|
||||||
|
|
|
@ -10,11 +10,14 @@
|
||||||
#include "controllers/commands/Command.hpp"
|
#include "controllers/commands/Command.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
class Settings;
|
||||||
|
class Paths;
|
||||||
class Channel;
|
class Channel;
|
||||||
|
|
||||||
class CommandModel;
|
class CommandModel;
|
||||||
|
|
||||||
class CommandController : public Singleton
|
class CommandController final : public Singleton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CommandController();
|
CommandController();
|
||||||
|
@ -22,7 +25,7 @@ public:
|
||||||
QString execCommand(const QString &text, std::shared_ptr<Channel> channel, bool dryRun);
|
QString execCommand(const QString &text, std::shared_ptr<Channel> channel, bool dryRun);
|
||||||
QStringList getDefaultTwitchCommandList();
|
QStringList getDefaultTwitchCommandList();
|
||||||
|
|
||||||
virtual void initialize(Application &app) override;
|
virtual void initialize(Settings &settings, Paths &paths) override;
|
||||||
virtual void save() override;
|
virtual void save() override;
|
||||||
|
|
||||||
CommandModel *createModel(QObject *parent);
|
CommandModel *createModel(QObject *parent);
|
||||||
|
@ -30,7 +33,7 @@ public:
|
||||||
UnsortedSignalVector<Command> items;
|
UnsortedSignalVector<Command> items;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void load();
|
void load(Paths &paths);
|
||||||
|
|
||||||
QMap<QString, Command> commandsMap_;
|
QMap<QString, Command> commandsMap_;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ HighlightController::HighlightController()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void HighlightController::initialize(Application &app)
|
void HighlightController::initialize(Settings &settings, Paths &paths)
|
||||||
{
|
{
|
||||||
assert(!this->initialized_);
|
assert(!this->initialized_);
|
||||||
this->initialized_ = true;
|
this->initialized_ = true;
|
||||||
|
|