This commit is contained in:
fourtf 2018-02-05 21:20:38 +01:00
commit a44758ad23
23 changed files with 255 additions and 104 deletions

View file

@ -17,6 +17,11 @@ DEFINES += QT_DEPRECATED_WARNINGS
PRECOMPILED_HEADER = src/precompiled_header.hpp PRECOMPILED_HEADER = src/precompiled_header.hpp
CONFIG += precompile_header CONFIG += precompile_header
# https://bugreports.qt.io/browse/QTBUG-27018
equals(QMAKE_CXX, "clang++") {
TARGET = bin/chatterino
}
# Icons # Icons
macx:ICON = resources/images/chatterino2.icns macx:ICON = resources/images/chatterino2.icns
win32:RC_FILE = resources/windows.rc win32:RC_FILE = resources/windows.rc
@ -167,7 +172,6 @@ SOURCES += \
src/widgets/splitcontainer.cpp \ src/widgets/splitcontainer.cpp \
src/widgets/streamview.cpp \ src/widgets/streamview.cpp \
src/widgets/textinputdialog.cpp \ src/widgets/textinputdialog.cpp \
src/widgets/titlebar.cpp \
src/widgets/tooltipwidget.cpp \ src/widgets/tooltipwidget.cpp \
src/widgets/window.cpp \ src/widgets/window.cpp \
src/providers/irc/_ircaccount.cpp \ src/providers/irc/_ircaccount.cpp \
@ -280,7 +284,6 @@ HEADERS += \
src/widgets/splitcontainer.hpp \ src/widgets/splitcontainer.hpp \
src/widgets/streamview.hpp \ src/widgets/streamview.hpp \
src/widgets/textinputdialog.hpp \ src/widgets/textinputdialog.hpp \
src/widgets/titlebar.hpp \
src/widgets/tooltipwidget.hpp \ src/widgets/tooltipwidget.hpp \
src/widgets/window.hpp \ src/widgets/window.hpp \
src/common.hpp \ src/common.hpp \

View file

@ -97,20 +97,16 @@ void AbstractIrcServer::writeConnectionMessageReceived(Communi::IrcMessage *mess
std::shared_ptr<Channel> AbstractIrcServer::addChannel(const QString &channelName) std::shared_ptr<Channel> AbstractIrcServer::addChannel(const QString &channelName)
{ {
std::lock_guard<std::mutex> lock(this->channelMutex); // try get channel
ChannelPtr chan = this->getChannel(channelName);
// value exists if (chan != Channel::getEmpty()) {
auto it = this->channels.find(channelName); return chan;
if (it != this->channels.end()) {
std::shared_ptr<Channel> chan = it.value().lock();
if (chan) {
return chan;
}
} }
std::lock_guard<std::mutex> lock(this->channelMutex);
// value doesn't exist // value doesn't exist
std::shared_ptr<Channel> chan = this->createChannel(channelName); chan = this->createChannel(channelName);
if (!chan) { if (!chan) {
return Channel::getEmpty(); return Channel::getEmpty();
} }
@ -119,7 +115,7 @@ std::shared_ptr<Channel> AbstractIrcServer::addChannel(const QString &channelNam
this->channels.insert(channelName, chan); this->channels.insert(channelName, chan);
chan->destroyed.connect([this, clojuresInCppAreShit] { chan->destroyed.connect([this, clojuresInCppAreShit] {
// fourtf: issues when the server itself in destroyed // fourtf: issues when the server itself is destroyed
debug::Log("[AbstractIrcServer::addChannel] {} was destroyed", clojuresInCppAreShit); debug::Log("[AbstractIrcServer::addChannel] {} was destroyed", clojuresInCppAreShit);
this->channels.remove(clojuresInCppAreShit); this->channels.remove(clojuresInCppAreShit);
@ -128,6 +124,7 @@ std::shared_ptr<Channel> AbstractIrcServer::addChannel(const QString &channelNam
// join irc channel // join irc channel
{ {
std::lock_guard<std::mutex> lock2(this->connectionMutex); std::lock_guard<std::mutex> lock2(this->connectionMutex);
if (this->readConnection) { if (this->readConnection) {
this->readConnection->sendRaw("JOIN #" + channelName); this->readConnection->sendRaw("JOIN #" + channelName);
} }
@ -144,10 +141,16 @@ std::shared_ptr<Channel> AbstractIrcServer::getChannel(const QString &channelNam
{ {
std::lock_guard<std::mutex> lock(this->channelMutex); std::lock_guard<std::mutex> lock(this->channelMutex);
// try get special channel
ChannelPtr chan = this->getCustomChannel(channelName);
if (chan) {
return chan;
}
// value exists // value exists
auto it = this->channels.find(channelName); auto it = this->channels.find(channelName);
if (it != this->channels.end()) { if (it != this->channels.end()) {
std::shared_ptr<Channel> chan = it.value().lock(); chan = it.value().lock();
if (chan) { if (chan) {
return chan; return chan;
@ -221,6 +224,20 @@ void AbstractIrcServer::privateMessageReceived(Communi::IrcPrivateMessage *messa
void AbstractIrcServer::messageReceived(Communi::IrcMessage *message) void AbstractIrcServer::messageReceived(Communi::IrcMessage *message)
{ {
} }
void AbstractIrcServer::forEachChannel(std::function<void(ChannelPtr)> func)
{
std::lock_guard<std::mutex> lock(this->channelMutex);
for (std::weak_ptr<Channel> &weak : this->channels.values()) {
std::shared_ptr<Channel> chan = weak.lock();
if (!chan) {
continue;
}
func(chan);
}
}
} // namespace irc } // namespace irc
} // namespace providers } // namespace providers
} // namespace chatterino } // namespace chatterino

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <IrcMessage> #include <IrcMessage>
#include <functional>
#include <mutex> #include <mutex>
#include <pajlada/signals/signal.hpp> #include <pajlada/signals/signal.hpp>
@ -31,6 +32,9 @@ public:
void addFakeMessage(const QString &data); void addFakeMessage(const QString &data);
// iteration
void forEachChannel(std::function<void(ChannelPtr)> func);
protected: protected:
AbstractIrcServer(); AbstractIrcServer();
@ -47,16 +51,16 @@ protected:
virtual std::shared_ptr<Channel> getCustomChannel(const QString &channelName); virtual std::shared_ptr<Channel> getCustomChannel(const QString &channelName);
QMap<QString, std::weak_ptr<Channel>> channels;
std::mutex channelMutex;
private: private:
void initConnection(); void initConnection();
QMap<QString, std::weak_ptr<Channel>> channels;
std::unique_ptr<Communi::IrcConnection> writeConnection = nullptr; std::unique_ptr<Communi::IrcConnection> writeConnection = nullptr;
std::unique_ptr<Communi::IrcConnection> readConnection = nullptr; std::unique_ptr<Communi::IrcConnection> readConnection = nullptr;
std::mutex connectionMutex; std::mutex connectionMutex;
std::mutex channelMutex;
}; };
} // namespace irc } // namespace irc
} // namespace providers } // namespace providers

View file

@ -6,10 +6,10 @@
#include "messages/limitedqueue.hpp" #include "messages/limitedqueue.hpp"
#include "messages/message.hpp" #include "messages/message.hpp"
#include "providers/twitch/twitchchannel.hpp" #include "providers/twitch/twitchchannel.hpp"
//#include "singletons/channelmanager.hpp" #include "providers/twitch/twitchmessagebuilder.hpp"
#include "providers/twitch/twitchserver.hpp"
#include "singletons/resourcemanager.hpp" #include "singletons/resourcemanager.hpp"
#include "singletons/windowmanager.hpp" #include "singletons/windowmanager.hpp"
#include "twitchserver.hpp"
using namespace chatterino::singletons; using namespace chatterino::singletons;
using namespace chatterino::messages; using namespace chatterino::messages;
@ -149,7 +149,29 @@ void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message)
void IrcMessageHandler::handleWhisperMessage(Communi::IrcMessage *message) void IrcMessageHandler::handleWhisperMessage(Communi::IrcMessage *message)
{ {
// TODO: Implement debug::Log("Received whisper!");
messages::MessageParseArgs args;
args.isReceivedWhisper = true;
auto c = TwitchServer::getInstance().whispersChannel.get();
twitch::TwitchMessageBuilder builder(c, message, message->parameter(1), args);
if (!builder.isIgnored()) {
messages::MessagePtr _message = builder.build();
if (_message->flags & messages::Message::Highlighted) {
TwitchServer::getInstance().mentionsChannel->addMessage(_message);
}
c->addMessage(_message);
if (SettingManager::getInstance().inlineWhispers) {
TwitchServer::getInstance().forEachChannel([_message](ChannelPtr channel) {
channel->addMessage(_message); //
});
}
}
} }
void IrcMessageHandler::handleUserNoticeMessage(Communi::IrcMessage *message) void IrcMessageHandler::handleUserNoticeMessage(Communi::IrcMessage *message)
@ -177,9 +199,9 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message)
if (broadcast) { if (broadcast) {
// fourtf: send to all twitch channels // fourtf: send to all twitch channels
// this->channelManager.doOnAll([msg](const auto &c) { TwitchServer::getInstance().forEachChannelAndSpecialChannels([msg](const auto &c) {
// c->addMessage(msg); // c->addMessage(msg); //
// }); });
return; return;
} }

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <QColor>
#include <QString> #include <QString>
namespace chatterino { namespace chatterino {
@ -27,6 +28,8 @@ public:
bool isAnon() const; bool isAnon() const;
QColor color;
private: private:
QString oauthClient; QString oauthClient;
QString oauthToken; QString oauthToken;

View file

@ -249,6 +249,7 @@ void TwitchChannel::fetchRecentMessages()
} }
}); });
} }
} // namespace twitch } // namespace twitch
} // namespace providers } // namespace providers
} // namespace chatterino } // namespace chatterino

View file

@ -1,6 +1,7 @@
#include "providers/twitch/twitchmessagebuilder.hpp" #include "providers/twitch/twitchmessagebuilder.hpp"
#include "debug/log.hpp" #include "debug/log.hpp"
#include "providers/twitch/twitchchannel.hpp" #include "providers/twitch/twitchchannel.hpp"
#include "singletons/accountmanager.hpp"
#include "singletons/emotemanager.hpp" #include "singletons/emotemanager.hpp"
#include "singletons/ircmanager.hpp" #include "singletons/ircmanager.hpp"
#include "singletons/resourcemanager.hpp" #include "singletons/resourcemanager.hpp"
@ -27,8 +28,22 @@ TwitchMessageBuilder::TwitchMessageBuilder(Channel *_channel,
, args(_args) , args(_args)
, tags(this->ircMessage->tags()) , tags(this->ircMessage->tags())
, usernameColor(singletons::ThemeManager::getInstance().messages.textColors.system) , usernameColor(singletons::ThemeManager::getInstance().messages.textColors.system)
, originalMessage(_ircMessage->content())
, action(_ircMessage->isAction())
{
}
TwitchMessageBuilder::TwitchMessageBuilder(Channel *_channel,
const Communi::IrcMessage *_ircMessage, QString content,
const messages::MessageParseArgs &_args)
: channel(_channel)
, twitchChannel(dynamic_cast<TwitchChannel *>(_channel))
, ircMessage(_ircMessage)
, args(_args)
, tags(this->ircMessage->tags())
, usernameColor(singletons::ThemeManager::getInstance().messages.textColors.system)
, originalMessage(content)
{ {
this->originalMessage = this->ircMessage->content();
} }
bool TwitchMessageBuilder::isIgnored() const bool TwitchMessageBuilder::isIgnored() const
@ -125,8 +140,8 @@ MessagePtr TwitchMessageBuilder::build()
long int i = 0; long int i = 0;
for (QString split : splits) { for (QString split : splits) {
MessageColor textColor = ircMessage->isAction() ? MessageColor(this->usernameColor) MessageColor textColor =
: MessageColor(MessageColor::Text); this->action ? MessageColor(this->usernameColor) : MessageColor(MessageColor::Text);
// twitch emote // twitch emote
if (currentTwitchEmote != twitchEmotes.end() && currentTwitchEmote->first == i) { if (currentTwitchEmote != twitchEmotes.end() && currentTwitchEmote->first == i) {
@ -244,7 +259,7 @@ void TwitchMessageBuilder::parseUsername()
} }
// username // username
this->userName = ircMessage->nick(); this->userName = this->ircMessage->nick();
if (this->userName.isEmpty()) { if (this->userName.isEmpty()) {
this->userName = this->tags.value(QLatin1String("login")).toString(); this->userName = this->tags.value(QLatin1String("login")).toString();
@ -309,20 +324,36 @@ void TwitchMessageBuilder::appendUsername()
if (this->args.isSentWhisper) { if (this->args.isSentWhisper) {
// TODO(pajlada): Re-implement // TODO(pajlada): Re-implement
// userDisplayString += IrcManager::getInstance().getUser().getUserName(); // userDisplayString += IrcManager::getInstance().getUser().getUserName();
} } else if (this->args.isReceivedWhisper) {
// Sender username
this->emplace<TextElement>(usernameText, MessageElement::Text, this->usernameColor,
FontStyle::MediumBold)
->setLink({Link::UserInfo, this->userName});
if (this->args.isReceivedWhisper) { auto currentUser = singletons::AccountManager::getInstance().Twitch.getCurrent();
// TODO(pajlada): Re-implement
// userDisplayString += " -> " + IrcManager::getInstance().getUser().getUserName();
}
if (!ircMessage->isAction()) { // Separator
usernameText += ":"; this->emplace<TextElement>(
} "->", MessageElement::Text,
singletons::ThemeManager::getInstance().messages.textColors.system, FontStyle::Medium);
this->emplace<TextElement>(usernameText, MessageElement::Text, this->usernameColor, QColor selfColor = currentUser->color;
FontStyle::MediumBold) if (!selfColor.isValid()) {
->setLink({Link::UserInfo, this->userName}); selfColor = singletons::ThemeManager::getInstance().messages.textColors.system;
}
// Your own username
this->emplace<TextElement>(currentUser->getUserName() + ":", MessageElement::Text,
selfColor, FontStyle::MediumBold);
} else {
if (!this->action) {
usernameText += ":";
}
this->emplace<TextElement>(usernameText, MessageElement::Text, this->usernameColor,
FontStyle::MediumBold)
->setLink({Link::UserInfo, this->userName});
}
} }
void TwitchMessageBuilder::parseHighlights() void TwitchMessageBuilder::parseHighlights()
@ -330,11 +361,12 @@ void TwitchMessageBuilder::parseHighlights()
static auto player = new QMediaPlayer; static auto player = new QMediaPlayer;
static QUrl currentPlayerUrl; static QUrl currentPlayerUrl;
singletons::SettingManager &settings = singletons::SettingManager::getInstance(); singletons::SettingManager &settings = singletons::SettingManager::getInstance();
static pajlada::Settings::Setting<std::string> currentUser("/accounts/current"); auto currentUser = singletons::AccountManager::getInstance().Twitch.getCurrent();
QString currentUsername = QString::fromStdString(currentUser.getValue()); QString currentUsername = currentUser->getUserName();
if (this->ircMessage->nick() == currentUsername) { if (this->ircMessage->nick() == currentUsername) {
currentUser->color = this->usernameColor;
// Do nothing. Highlights cannot be triggered by yourself // Do nothing. Highlights cannot be triggered by yourself
return; return;
} }
@ -413,7 +445,7 @@ void TwitchMessageBuilder::parseHighlights()
} }
} }
void TwitchMessageBuilder::appendTwitchEmote(const Communi::IrcPrivateMessage *ircMessage, void TwitchMessageBuilder::appendTwitchEmote(const Communi::IrcMessage *ircMessage,
const QString &emote, const QString &emote,
std::vector<std::pair<long int, util::EmoteData>> &vec) std::vector<std::pair<long int, util::EmoteData>> &vec)
{ {
@ -442,11 +474,11 @@ void TwitchMessageBuilder::appendTwitchEmote(const Communi::IrcPrivateMessage *i
long int start = std::stol(coords.at(0).toStdString(), nullptr, 10); long int start = std::stol(coords.at(0).toStdString(), nullptr, 10);
long int end = std::stol(coords.at(1).toStdString(), nullptr, 10); long int end = std::stol(coords.at(1).toStdString(), nullptr, 10);
if (start >= end || start < 0 || end > ircMessage->content().length()) { if (start >= end || start < 0 || end > this->originalMessage.length()) {
return; return;
} }
QString name = ircMessage->content().mid(start, end - start + 1); QString name = this->originalMessage.mid(start, end - start + 1);
vec.push_back( vec.push_back(
std::pair<long int, util::EmoteData>(start, emoteManager.getTwitchEmoteById(id, name))); std::pair<long int, util::EmoteData>(start, emoteManager.getTwitchEmoteById(id, name)));

View file

@ -29,10 +29,12 @@ public:
explicit TwitchMessageBuilder(Channel *_channel, const Communi::IrcPrivateMessage *_ircMessage, explicit TwitchMessageBuilder(Channel *_channel, const Communi::IrcPrivateMessage *_ircMessage,
const messages::MessageParseArgs &_args); const messages::MessageParseArgs &_args);
explicit TwitchMessageBuilder(Channel *_channel, const Communi::IrcMessage *_ircMessage,
QString content, const messages::MessageParseArgs &_args);
Channel *channel; Channel *channel;
TwitchChannel *twitchChannel; TwitchChannel *twitchChannel;
const Communi::IrcPrivateMessage *ircMessage; const Communi::IrcMessage *ircMessage;
messages::MessageParseArgs args; messages::MessageParseArgs args;
const QVariantMap tags; const QVariantMap tags;
@ -46,7 +48,9 @@ private:
QString roomID; QString roomID;
QColor usernameColor; QColor usernameColor;
QString originalMessage; const QString originalMessage;
const bool action = false;
void parseMessageID(); void parseMessageID();
void parseRoomID(); void parseRoomID();
@ -55,7 +59,7 @@ private:
void appendUsername(); void appendUsername();
void parseHighlights(); void parseHighlights();
void appendTwitchEmote(const Communi::IrcPrivateMessage *ircMessage, const QString &emote, void appendTwitchEmote(const Communi::IrcMessage *ircMessage, const QString &emote,
std::vector<std::pair<long, util::EmoteData>> &vec); std::vector<std::pair<long, util::EmoteData>> &vec);
bool tryAppendEmote(QString &emoteString); bool tryAppendEmote(QString &emoteString);

View file

@ -143,6 +143,23 @@ std::shared_ptr<Channel> TwitchServer::getCustomChannel(const QString &channelNa
return nullptr; return nullptr;
} }
void TwitchServer::forEachChannelAndSpecialChannels(std::function<void(ChannelPtr)> func)
{
std::lock_guard<std::mutex> lock(this->channelMutex);
for (std::weak_ptr<Channel> &weak : this->channels) {
std::shared_ptr<Channel> chan = weak.lock();
if (!chan) {
continue;
}
func(chan);
}
func(this->whispersChannel);
func(this->mentionsChannel);
}
} // namespace twitch } // namespace twitch
} // namespace providers } // namespace providers
} // namespace chatterino } // namespace chatterino

View file

@ -16,6 +16,9 @@ class TwitchServer final : public irc::AbstractIrcServer
public: public:
static TwitchServer &getInstance(); static TwitchServer &getInstance();
// fourtf: ugh
void forEachChannelAndSpecialChannels(std::function<void(ChannelPtr)> func);
const ChannelPtr whispersChannel; const ChannelPtr whispersChannel;
const ChannelPtr mentionsChannel; const ChannelPtr mentionsChannel;

View file

@ -136,5 +136,14 @@
// func(this->mentionsChannel); // func(this->mentionsChannel);
//} //}
//} // namespace singletons //}
// void ChannelManager::doOnAllNormalChannels(std::function<void(ChannelPtr)> func)
//{
// for (const auto &channel : this->twitchChannels) {
// func(std::get<0>(channel));
// }
//}
//} // namespace chatterino //} // namespace chatterino
//}

View file

@ -27,6 +27,8 @@
// const ChannelPtr whispersChannel; // const ChannelPtr whispersChannel;
// const ChannelPtr mentionsChannel; // const ChannelPtr mentionsChannel;
// const ChannelPtr emptyChannel; // const ChannelPtr emptyChannel;
// void doOnAll(std::function<void(ChannelPtr)> func);
// void doOnAllNormalChannels(std::function<void(ChannelPtr)> func);
// private: // private:
// std::map<std::string, std::string> usernameToID; // std::map<std::string, std::string> usernameToID;

View file

@ -7,18 +7,18 @@
namespace chatterino { namespace chatterino {
namespace singletons { namespace singletons {
QByteArray endline("\n");
LoggingChannel::LoggingChannel(const QString &_channelName, const QString &_baseDirectory) LoggingChannel::LoggingChannel(const QString &_channelName, const QString &_baseDirectory)
: channelName(_channelName) : channelName(_channelName)
, baseDirectory(_baseDirectory) , baseDirectory(_baseDirectory)
{ {
QDateTime now = QDateTime::currentDateTime(); QDateTime now = QDateTime::currentDateTime();
QString baseFileName = this->channelName + "-" + now.toString("yyyy-MM-dd") + ".log"; this->dateString = this->generateDateString(now);
// Open file handle to log file of current date this->openLogFile();
this->fileHandle.setFileName(this->baseDirectory + QDir::separator() + baseFileName);
this->fileHandle.open(QIODevice::Append);
this->appendLine(this->generateOpeningString(now)); this->appendLine(this->generateOpeningString(now));
} }
@ -28,24 +28,38 @@ LoggingChannel::~LoggingChannel()
this->fileHandle.close(); this->fileHandle.close();
} }
void LoggingChannel::openLogFile()
{
if (this->fileHandle.isOpen()) {
this->fileHandle.flush();
this->fileHandle.close();
}
QString baseFileName = this->channelName + "-" + this->dateString + ".log";
// Open file handle to log file of current date
this->fileHandle.setFileName(this->baseDirectory + QDir::separator() + baseFileName);
this->fileHandle.open(QIODevice::Append);
}
void LoggingChannel::addMessage(std::shared_ptr<messages::Message> message) void LoggingChannel::addMessage(std::shared_ptr<messages::Message> message)
{ {
QDateTime now = QDateTime::currentDateTime(); QDateTime now = QDateTime::currentDateTime();
QString messageDateString = this->generateDateString(now);
if (messageDateString != this->dateString) {
this->dateString = messageDateString;
this->openLogFile();
}
QString str; QString str;
str.append('['); str.append('[');
str.append(now.toString("HH:mm:ss")); str.append(now.toString("HH:mm:ss"));
str.append("] "); str.append("] ");
if ((message->flags & messages::Message::MessageFlags::System) != 0) { str.append(message->searchText);
str.append(message->searchText); str.append(endline);
str.append('\n');
} else {
str.append(message->loginName);
str.append(": ");
str.append(message->searchText);
str.append('\n');
}
this->appendLine(str); this->appendLine(str);
} }
@ -56,7 +70,7 @@ QString LoggingChannel::generateOpeningString(const QDateTime &now) const
ret.append(now.toString("yyyy-MM-dd HH:mm:ss ")); ret.append(now.toString("yyyy-MM-dd HH:mm:ss "));
ret.append(now.timeZoneAbbreviation()); ret.append(now.timeZoneAbbreviation());
ret.append('\n'); ret.append(endline);
return ret; return ret;
} }
@ -67,16 +81,31 @@ QString LoggingChannel::generateClosingString(const QDateTime &now) const
ret.append(now.toString("yyyy-MM-dd HH:mm:ss")); ret.append(now.toString("yyyy-MM-dd HH:mm:ss"));
ret.append(now.timeZoneAbbreviation()); ret.append(now.timeZoneAbbreviation());
ret.append('\n'); ret.append(endline);
return ret; return ret;
} }
void LoggingChannel::appendLine(const QString &line) void LoggingChannel::appendLine(const QString &line)
{ {
auto a1 = line.toUtf8();
auto a2 = line.toLatin1();
auto a3 = line.toLocal8Bit();
auto a4 = line.data();
auto a5 = line.toStdString();
// this->fileHandle.write(a5.c_str(), a5.length());
// this->fileHandle.write(a5.c_str(), a5.length());
this->fileHandle.write(line.toUtf8()); this->fileHandle.write(line.toUtf8());
this->fileHandle.flush(); this->fileHandle.flush();
} }
QString LoggingChannel::generateDateString(const QDateTime &now)
{
return now.toString("yyyy-MM-dd");
}
} // namespace singletons } // namespace singletons
} // namespace chatterino } // namespace chatterino

View file

@ -21,17 +21,22 @@ public:
void addMessage(std::shared_ptr<messages::Message> message); void addMessage(std::shared_ptr<messages::Message> message);
private: private:
void openLogFile();
QString generateOpeningString(const QDateTime &now = QDateTime::currentDateTime()) const; QString generateOpeningString(const QDateTime &now = QDateTime::currentDateTime()) const;
QString generateClosingString(const QDateTime &now = QDateTime::currentDateTime()) const; QString generateClosingString(const QDateTime &now = QDateTime::currentDateTime()) const;
void appendLine(const QString &line); void appendLine(const QString &line);
private: QString generateDateString(const QDateTime &now);
QString channelName;
const QString &baseDirectory; const QString channelName;
QString fileName; const QString baseDirectory;
QFile fileHandle; QFile fileHandle;
QString dateString;
friend class LoggingManager; friend class LoggingManager;
}; };

View file

@ -85,12 +85,16 @@ void ResizingTextEdit::keyPressEvent(QKeyEvent *event)
if (doComplete) { if (doComplete) {
// check if there is a completer // check if there is a completer
return_if_not(this->completer); if (!this->completer) {
return;
}
QString currentCompletionPrefix = this->textUnderCursor(); QString currentCompletionPrefix = this->textUnderCursor();
// check if there is something to complete // check if there is something to complete
return_if_not(currentCompletionPrefix.size()); if (!currentCompletionPrefix.size()) {
return;
}
auto *completionModel = auto *completionModel =
static_cast<chatterino::singletons::CompletionModel *>(this->completer->model()); static_cast<chatterino::singletons::CompletionModel *>(this->completer->model());

View file

@ -5,6 +5,7 @@
namespace chatterino { namespace chatterino {
namespace widgets { namespace widgets {
namespace settingspages { namespace settingspages {
EmotesPage::EmotesPage() EmotesPage::EmotesPage()
: SettingsPage("Emotes", ":/images/emote.svg") : SettingsPage("Emotes", ":/images/emote.svg")
{ {
@ -22,6 +23,7 @@ EmotesPage::EmotesPage()
layout->addStretch(1); layout->addStretch(1);
} }
} // namespace settingspages } // namespace settingspages
} // namespace widgets } // namespace widgets
} // namespace chatterino } // namespace chatterino

View file

@ -1,4 +1,5 @@
#include "logspage.hpp" #include "logspage.hpp"
#include "singletons/pathmanager.hpp"
#include <QFormLayout> #include <QFormLayout>
#include <QVBoxLayout> #include <QVBoxLayout>
@ -9,6 +10,16 @@ namespace chatterino {
namespace widgets { namespace widgets {
namespace settingspages { namespace settingspages {
inline QString CreateLink(const QString &url, bool file = false)
{
if (file) {
return QString("<a href=\"file:///" + url + "\"><span style=\"color: white;\">" + url +
"</span></a>");
}
return QString("<a href=\"" + url + "\"><span style=\"color: white;\">" + url + "</span></a>");
}
LogsPage::LogsPage() LogsPage::LogsPage()
: SettingsPage("Logs", "") : SettingsPage("Logs", "")
{ {
@ -16,13 +27,16 @@ LogsPage::LogsPage()
util::LayoutCreator<LogsPage> layoutCreator(this); util::LayoutCreator<LogsPage> layoutCreator(this);
auto layout = layoutCreator.emplace<QVBoxLayout>().withoutMargin(); auto layout = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
{ singletons::PathManager &pathManager = singletons::PathManager::getInstance();
auto form = layout.emplace<QFormLayout>(); auto logPath = pathManager.logsFolderPath;
// clang-format off auto created = layout.emplace<QLabel>();
form->addRow("Enabled:", this->createCheckBox("Enable logging", settings.enableLogging)); created->setText("Logs are saved to " + CreateLink(logPath, true));
// clang-format on created->setTextFormat(Qt::RichText);
} created->setTextInteractionFlags(Qt::TextBrowserInteraction | Qt::LinksAccessibleByKeyboard |
Qt::LinksAccessibleByKeyboard);
created->setOpenExternalLinks(true);
layout.append(this->createCheckBox("Enable logging", settings.enableLogging));
layout->addStretch(1); layout->addStretch(1);
} }

View file

@ -13,6 +13,7 @@ namespace settingspages {
SpecialChannelsPage::SpecialChannelsPage() SpecialChannelsPage::SpecialChannelsPage()
: SettingsPage("Special channels", "") : SettingsPage("Special channels", "")
{ {
singletons::SettingManager &settings = singletons::SettingManager::getInstance();
util::LayoutCreator<SpecialChannelsPage> layoutCreator(this); util::LayoutCreator<SpecialChannelsPage> layoutCreator(this);
auto layout = layoutCreator.setLayoutType<QVBoxLayout>(); auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
@ -21,6 +22,12 @@ SpecialChannelsPage::SpecialChannelsPage()
mentions.emplace<QLabel>("Join /mentions to view your mentions."); mentions.emplace<QLabel>("Join /mentions to view your mentions.");
} }
auto whispers = layout.emplace<QGroupBox>("Whispers").setLayoutType<QVBoxLayout>();
{
whispers.emplace<QLabel>("Join /whispers to view your mentions.");
whispers.append(this->createCheckBox("Show whispers inline", settings.inlineWhispers));
}
layout->addStretch(1); layout->addStretch(1);
} }
} // namespace settingspages } // namespace settingspages

View file

@ -139,11 +139,6 @@ ChannelPtr Split::getChannel() const
return this->channel; return this->channel;
} }
ChannelPtr &Split::getChannelRef()
{
return this->channel;
}
void Split::setChannel(ChannelPtr _newChannel) void Split::setChannel(ChannelPtr _newChannel)
{ {
this->view.setChannel(_newChannel); this->view.setChannel(_newChannel);

View file

@ -57,7 +57,6 @@ public:
const std::string &getUUID() const; const std::string &getUUID() const;
ChannelPtr getChannel() const; ChannelPtr getChannel() const;
ChannelPtr &getChannelRef();
void setFlexSizeX(double x); void setFlexSizeX(double x);
double getFlexSizeX(); double getFlexSizeX();
void setFlexSizeY(double y); void setFlexSizeY(double y);

View file

@ -1,13 +0,0 @@
#include "titlebar.hpp"
namespace chatterino {
namespace widgets {
TitleBar::TitleBar(QWidget *parent)
: QWidget(parent)
{
setFixedHeight(32);
}
} // namespace widgets
} // namespace chatterino

View file

@ -46,11 +46,6 @@ Window::Window(const QString &windowName, singletons::ThemeManager &_themeManage
QVBoxLayout *layout = new QVBoxLayout(this); QVBoxLayout *layout = new QVBoxLayout(this);
// add titlebar
// if (SettingsManager::getInstance().useCustomWindowFrame.get()) {
// layout->addWidget(&_titleBar);
// }
layout->addWidget(&this->notebook); layout->addWidget(&this->notebook);
this->getLayoutContainer()->setLayout(layout); this->getLayoutContainer()->setLayout(layout);
@ -63,9 +58,7 @@ Window::Window(const QString &windowName, singletons::ThemeManager &_themeManage
/// Initialize program-wide hotkeys /// Initialize program-wide hotkeys
// CTRL+P: Open Settings Dialog // CTRL+P: Open Settings Dialog
CreateWindowShortcut(this, "CTRL+P", [] { CreateWindowShortcut(this, "CTRL+P", [] { SettingsDialog::showDialog(); });
SettingsDialog::showDialog(); //
});
// CTRL+Number: Switch to n'th tab // CTRL+Number: Switch to n'th tab
CreateWindowShortcut(this, "CTRL+1", [this] { this->notebook.selectIndex(0); }); CreateWindowShortcut(this, "CTRL+1", [this] { this->notebook.selectIndex(0); });

View file

@ -3,7 +3,6 @@
#include "util/helpers.hpp" #include "util/helpers.hpp"
#include "widgets/basewindow.hpp" #include "widgets/basewindow.hpp"
#include "widgets/notebook.hpp" #include "widgets/notebook.hpp"
#include "widgets/titlebar.hpp"
//#ifdef USEWINSDK //#ifdef USEWINSDK
//#include <platform/borderless/qwinwidget.h> //#include <platform/borderless/qwinwidget.h>
@ -65,7 +64,7 @@ private:
void loadGeometry(); void loadGeometry();
Notebook notebook; Notebook notebook;
TitleBar titleBar; // TitleBar titleBar;
friend class Notebook; friend class Notebook;