@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## Unversioned
|
## Unversioned
|
||||||
|
|
||||||
|
- Minor: Added user notes to the user info dialog (when clicking a username). (#6122)
|
||||||
- Minor: Added cached emotes fallback when fetching from a provider fails. (#6125)
|
- Minor: Added cached emotes fallback when fetching from a provider fails. (#6125)
|
||||||
- Minor: Add an option for the reduced opacity of message history. (#6121)
|
- Minor: Add an option for the reduced opacity of message history. (#6121)
|
||||||
- Minor: Make paused chat indicator more visible, and fix its zoom behavior. (#6123)
|
- Minor: Make paused chat indicator more visible, and fix its zoom behavior. (#6123)
|
||||||
|
|||||||
@@ -27,21 +27,24 @@ public:
|
|||||||
void setUserColor(const QString &userID,
|
void setUserColor(const QString &userID,
|
||||||
const QString &colorString) override
|
const QString &colorString) override
|
||||||
{
|
{
|
||||||
auto it = this->userMap.find(userID);
|
this->userMap[userID].color = QColor(colorString);
|
||||||
if (it != this->userMap.end())
|
this->userDataUpdated_.invoke();
|
||||||
{
|
|
||||||
it->second.color = QColor(colorString);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
void setUserNotes(const QString &userID, const QString ¬es) override
|
||||||
{
|
{
|
||||||
this->userMap.emplace(userID, UserData{
|
this->userMap[userID].notes = notes;
|
||||||
.color = QColor(colorString),
|
this->userDataUpdated_.invoke();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pajlada::Signals::NoArgSignal &userDataUpdated() override
|
||||||
|
{
|
||||||
|
return this->userDataUpdated_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<QString, UserData> userMap;
|
std::unordered_map<QString, UserData> userMap;
|
||||||
|
pajlada::Signals::NoArgSignal userDataUpdated_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino::mock
|
} // namespace chatterino::mock
|
||||||
|
|||||||
@@ -617,6 +617,8 @@ set(SOURCE_FILES
|
|||||||
widgets/dialogs/ColorPickerDialog.hpp
|
widgets/dialogs/ColorPickerDialog.hpp
|
||||||
widgets/dialogs/EditHotkeyDialog.cpp
|
widgets/dialogs/EditHotkeyDialog.cpp
|
||||||
widgets/dialogs/EditHotkeyDialog.hpp
|
widgets/dialogs/EditHotkeyDialog.hpp
|
||||||
|
widgets/dialogs/EditUserNotesDialog.cpp
|
||||||
|
widgets/dialogs/EditUserNotesDialog.hpp
|
||||||
widgets/dialogs/EmotePopup.cpp
|
widgets/dialogs/EmotePopup.cpp
|
||||||
widgets/dialogs/EmotePopup.hpp
|
widgets/dialogs/EmotePopup.hpp
|
||||||
widgets/dialogs/LastRunCrashDialog.cpp
|
widgets/dialogs/LastRunCrashDialog.cpp
|
||||||
|
|||||||
@@ -17,8 +17,12 @@ namespace chatterino {
|
|||||||
// Replacement fields should be optional, where none denotes that the field should not be updated for the user
|
// Replacement fields should be optional, where none denotes that the field should not be updated for the user
|
||||||
struct UserData {
|
struct UserData {
|
||||||
std::optional<QColor> color{std::nullopt};
|
std::optional<QColor> color{std::nullopt};
|
||||||
|
QString notes;
|
||||||
|
|
||||||
// TODO: User note?
|
bool isEmpty() const
|
||||||
|
{
|
||||||
|
return !color.has_value() && notes.isEmpty();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
@@ -38,6 +42,11 @@ struct Serialize<chatterino::UserData> {
|
|||||||
chatterino::rj::set(obj, "color",
|
chatterino::rj::set(obj, "color",
|
||||||
color.name().toUtf8().toStdString(), a);
|
color.name().toUtf8().toStdString(), a);
|
||||||
}
|
}
|
||||||
|
if (!value.notes.isEmpty())
|
||||||
|
{
|
||||||
|
chatterino::rj::set(obj, "notes",
|
||||||
|
value.notes.toUtf8().toStdString(), a);
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -65,6 +74,12 @@ struct Deserialize<chatterino::UserData> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString notes;
|
||||||
|
if (chatterino::rj::getSafe(value, "notes", notes))
|
||||||
|
{
|
||||||
|
user.notes = notes;
|
||||||
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ UserDataController::UserDataController(const Paths &paths)
|
|||||||
|
|
||||||
std::optional<UserData> UserDataController::getUser(const QString &userID) const
|
std::optional<UserData> UserDataController::getUser(const QString &userID) const
|
||||||
{
|
{
|
||||||
|
if (userID.isEmpty())
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_lock lock(this->usersMutex);
|
std::shared_lock lock(this->usersMutex);
|
||||||
auto it = this->users.find(userID);
|
auto it = this->users.find(userID);
|
||||||
|
|
||||||
@@ -59,7 +64,14 @@ std::unordered_map<QString, UserData> UserDataController::getUsers() const
|
|||||||
void UserDataController::setUserColor(const QString &userID,
|
void UserDataController::setUserColor(const QString &userID,
|
||||||
const QString &colorString)
|
const QString &colorString)
|
||||||
{
|
{
|
||||||
auto c = this->getUsers();
|
if (userID.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_lock lock(this->usersMutex);
|
||||||
|
|
||||||
|
auto c = this->users;
|
||||||
auto it = c.find(userID);
|
auto it = c.find(userID);
|
||||||
std::optional<QColor> finalColor =
|
std::optional<QColor> finalColor =
|
||||||
makeConditionedOptional(!colorString.isEmpty(), QColor(colorString));
|
makeConditionedOptional(!colorString.isEmpty(), QColor(colorString));
|
||||||
@@ -80,15 +92,46 @@ void UserDataController::setUserColor(const QString &userID,
|
|||||||
it->second.color = finalColor;
|
it->second.color = finalColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->update(std::move(c));
|
this->update(std::move(c), std::move(lock));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserDataController::update(
|
void UserDataController::update(
|
||||||
std::unordered_map<QString, UserData> &&newUsers)
|
std::unordered_map<QString, UserData> &&newUsers,
|
||||||
|
std::unique_lock<std::shared_mutex> usersLock)
|
||||||
{
|
{
|
||||||
std::unique_lock lock(this->usersMutex);
|
// Remove empty user data items
|
||||||
|
std::erase_if(newUsers, [](const auto &pair) {
|
||||||
|
return pair.second.isEmpty();
|
||||||
|
});
|
||||||
|
|
||||||
this->users = std::move(newUsers);
|
this->users = std::move(newUsers);
|
||||||
this->setting.setValue(this->users);
|
this->setting.setValue(this->users);
|
||||||
|
|
||||||
|
// unlock before invoking updated signal
|
||||||
|
usersLock.unlock();
|
||||||
|
|
||||||
|
this->userDataUpdated_.invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserDataController::setUserNotes(const QString &userID,
|
||||||
|
const QString ¬es)
|
||||||
|
{
|
||||||
|
if (userID.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_lock lock(this->usersMutex);
|
||||||
|
|
||||||
|
auto users = this->users;
|
||||||
|
users[userID].notes = notes;
|
||||||
|
|
||||||
|
this->update(std::move(users), std::move(lock));
|
||||||
|
}
|
||||||
|
|
||||||
|
pajlada::Signals::NoArgSignal &UserDataController::userDataUpdated()
|
||||||
|
{
|
||||||
|
return this->userDataUpdated_;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "util/serialize/Container.hpp"
|
#include "util/serialize/Container.hpp"
|
||||||
|
|
||||||
#include <pajlada/settings.hpp>
|
#include <pajlada/settings.hpp>
|
||||||
|
#include <pajlada/signals/signal.hpp>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
@@ -27,6 +28,9 @@ public:
|
|||||||
|
|
||||||
virtual void setUserColor(const QString &userID,
|
virtual void setUserColor(const QString &userID,
|
||||||
const QString &colorString) = 0;
|
const QString &colorString) = 0;
|
||||||
|
virtual void setUserNotes(const QString &userID, const QString ¬es) = 0;
|
||||||
|
|
||||||
|
virtual pajlada::Signals::NoArgSignal &userDataUpdated() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UserDataController : public IUserDataController
|
class UserDataController : public IUserDataController
|
||||||
@@ -42,8 +46,14 @@ public:
|
|||||||
void setUserColor(const QString &userID,
|
void setUserColor(const QString &userID,
|
||||||
const QString &colorString) override;
|
const QString &colorString) override;
|
||||||
|
|
||||||
|
// Update or insert extra data for the notes about a user
|
||||||
|
void setUserNotes(const QString &userID, const QString ¬es) override;
|
||||||
|
|
||||||
|
pajlada::Signals::NoArgSignal &userDataUpdated() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void update(std::unordered_map<QString, UserData> &&newUsers);
|
void update(std::unordered_map<QString, UserData> &&newUsers,
|
||||||
|
std::unique_lock<std::shared_mutex> usersLock);
|
||||||
|
|
||||||
std::unordered_map<QString, UserData> getUsers() const;
|
std::unordered_map<QString, UserData> getUsers() const;
|
||||||
|
|
||||||
@@ -53,6 +63,7 @@ private:
|
|||||||
|
|
||||||
std::shared_ptr<pajlada::Settings::SettingManager> sm;
|
std::shared_ptr<pajlada::Settings::SettingManager> sm;
|
||||||
pajlada::Settings::Setting<std::unordered_map<QString, UserData>> setting;
|
pajlada::Settings::Setting<std::unordered_map<QString, UserData>> setting;
|
||||||
|
pajlada::Signals::NoArgSignal userDataUpdated_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|||||||
+23
-18
@@ -484,6 +484,28 @@ bool BaseWindow::supportsCustomWindowFrame()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseWindow::windowDeactivationEvent()
|
||||||
|
{
|
||||||
|
switch (this->windowDeactivateAction)
|
||||||
|
{
|
||||||
|
case WindowDeactivateAction::Delete:
|
||||||
|
this->deleteLater();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WindowDeactivateAction::Close:
|
||||||
|
this->close();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WindowDeactivateAction::Hide:
|
||||||
|
this->hide();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WindowDeactivateAction::Nothing:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BaseWindow::themeChangedEvent()
|
void BaseWindow::themeChangedEvent()
|
||||||
{
|
{
|
||||||
if (this->hasCustomWindowFrame())
|
if (this->hasCustomWindowFrame())
|
||||||
@@ -520,24 +542,7 @@ bool BaseWindow::event(QEvent *event)
|
|||||||
{
|
{
|
||||||
if (event->type() == QEvent::WindowDeactivate)
|
if (event->type() == QEvent::WindowDeactivate)
|
||||||
{
|
{
|
||||||
switch (this->windowDeactivateAction)
|
this->windowDeactivationEvent();
|
||||||
{
|
|
||||||
case WindowDeactivateAction::Delete:
|
|
||||||
this->deleteLater();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WindowDeactivateAction::Close:
|
|
||||||
this->close();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WindowDeactivateAction::Hide:
|
|
||||||
this->hide();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WindowDeactivateAction::Nothing:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ protected:
|
|||||||
WindowDeactivateAction windowDeactivateAction =
|
WindowDeactivateAction windowDeactivateAction =
|
||||||
WindowDeactivateAction::Nothing;
|
WindowDeactivateAction::Nothing;
|
||||||
|
|
||||||
|
virtual void windowDeactivationEvent();
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
bool nativeEvent(const QByteArray &eventType, void *message,
|
bool nativeEvent(const QByteArray &eventType, void *message,
|
||||||
qintptr *result) override;
|
qintptr *result) override;
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#include "EditUserNotesDialog.hpp"
|
||||||
|
|
||||||
|
#include "singletons/Theme.hpp"
|
||||||
|
#include "util/LayoutCreator.hpp"
|
||||||
|
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QTextEdit>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
EditUserNotesDialog::EditUserNotesDialog(QWidget *parent)
|
||||||
|
: BasePopup(
|
||||||
|
{
|
||||||
|
BaseWindow::EnableCustomFrame,
|
||||||
|
BaseWindow::DisableLayoutSave,
|
||||||
|
BaseWindow::BoundsCheckOnShow,
|
||||||
|
},
|
||||||
|
parent)
|
||||||
|
{
|
||||||
|
this->setScaleIndependantSize(500, 350);
|
||||||
|
|
||||||
|
auto layout = LayoutCreator<QWidget>(this->getLayoutContainer())
|
||||||
|
.setLayoutType<QVBoxLayout>();
|
||||||
|
|
||||||
|
auto edit = layout.emplace<QTextEdit>().assign(&this->textEdit_);
|
||||||
|
|
||||||
|
layout
|
||||||
|
.emplace<QDialogButtonBox>(QDialogButtonBox::Ok |
|
||||||
|
QDialogButtonBox::Cancel)
|
||||||
|
.connect(&QDialogButtonBox::accepted, this,
|
||||||
|
[this, edit = edit.getElement()] {
|
||||||
|
this->onOk.invoke(edit->toPlainText());
|
||||||
|
this->close();
|
||||||
|
})
|
||||||
|
.connect(&QDialogButtonBox::rejected, this, [this] {
|
||||||
|
this->close();
|
||||||
|
});
|
||||||
|
|
||||||
|
this->themeChangedEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditUserNotesDialog::setNotes(const QString ¬es)
|
||||||
|
{
|
||||||
|
this->textEdit_->setPlainText(notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditUserNotesDialog::updateWindowTitle(const QString &displayUsername)
|
||||||
|
{
|
||||||
|
this->setWindowTitle("Editing notes for " + displayUsername);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditUserNotesDialog::showEvent(QShowEvent *event)
|
||||||
|
{
|
||||||
|
this->textEdit_->setFocus(Qt::FocusReason::ActiveWindowFocusReason);
|
||||||
|
|
||||||
|
BasePopup::showEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditUserNotesDialog::themeChangedEvent()
|
||||||
|
{
|
||||||
|
if (!this->theme)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto palette = this->palette();
|
||||||
|
|
||||||
|
palette.setColor(QPalette::Window,
|
||||||
|
this->theme->tabs.selected.backgrounds.regular);
|
||||||
|
palette.setColor(QPalette::Base, getTheme()->splits.background);
|
||||||
|
palette.setColor(QPalette::Text, getTheme()->window.text);
|
||||||
|
|
||||||
|
this->setPalette(palette);
|
||||||
|
|
||||||
|
if (this->textEdit_)
|
||||||
|
{
|
||||||
|
this->textEdit_->setPalette(palette);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chatterino
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pajlada/signals/signal.hpp"
|
||||||
|
#include "widgets/BasePopup.hpp"
|
||||||
|
|
||||||
|
class QTextEdit;
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
class EditUserNotesDialog : public BasePopup
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
EditUserNotesDialog(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
void setNotes(const QString &initialNotes);
|
||||||
|
void updateWindowTitle(const QString &displayUsername);
|
||||||
|
|
||||||
|
pajlada::Signals::Signal<const QString &> onOk;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent *event) override;
|
||||||
|
void themeChangedEvent() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTextEdit *textEdit_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "controllers/commands/CommandController.hpp"
|
#include "controllers/commands/CommandController.hpp"
|
||||||
#include "controllers/highlights/HighlightBlacklistUser.hpp"
|
#include "controllers/highlights/HighlightBlacklistUser.hpp"
|
||||||
#include "controllers/hotkeys/HotkeyController.hpp"
|
#include "controllers/hotkeys/HotkeyController.hpp"
|
||||||
|
#include "controllers/userdata/UserDataController.hpp"
|
||||||
#include "messages/Message.hpp"
|
#include "messages/Message.hpp"
|
||||||
#include "messages/MessageBuilder.hpp"
|
#include "messages/MessageBuilder.hpp"
|
||||||
#include "providers/IvrApi.hpp"
|
#include "providers/IvrApi.hpp"
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
#include "util/Helpers.hpp"
|
#include "util/Helpers.hpp"
|
||||||
#include "util/LayoutCreator.hpp"
|
#include "util/LayoutCreator.hpp"
|
||||||
#include "util/PostToThread.hpp"
|
#include "util/PostToThread.hpp"
|
||||||
|
#include "widgets/dialogs/EditUserNotesDialog.hpp"
|
||||||
#include "widgets/helper/ChannelView.hpp"
|
#include "widgets/helper/ChannelView.hpp"
|
||||||
#include "widgets/helper/EffectLabel.hpp"
|
#include "widgets/helper/EffectLabel.hpp"
|
||||||
#include "widgets/helper/InvisibleSizeGrip.hpp"
|
#include "widgets/helper/InvisibleSizeGrip.hpp"
|
||||||
@@ -55,6 +57,7 @@ constexpr QStringView TEXT_UNAVAILABLE = u"(not available)";
|
|||||||
constexpr QStringView TEXT_PRONOUNS = u"Pronouns: %1";
|
constexpr QStringView TEXT_PRONOUNS = u"Pronouns: %1";
|
||||||
constexpr QStringView TEXT_UNSPECIFIED = u"(unspecified)";
|
constexpr QStringView TEXT_UNSPECIFIED = u"(unspecified)";
|
||||||
constexpr QStringView TEXT_LOADING = u"(loading...)";
|
constexpr QStringView TEXT_LOADING = u"(loading...)";
|
||||||
|
constexpr qsizetype NOTES_PREVIEW_LENGTH = 80;
|
||||||
|
|
||||||
using namespace chatterino;
|
using namespace chatterino;
|
||||||
|
|
||||||
@@ -407,6 +410,9 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split)
|
|||||||
.assign(&this->ui_.ignoreHighlights);
|
.assign(&this->ui_.ignoreHighlights);
|
||||||
// visibility of this is updated in setData
|
// visibility of this is updated in setData
|
||||||
|
|
||||||
|
auto notesAdd =
|
||||||
|
user.emplace<EffectLabel2>(this).assign(&this->ui_.notesAdd);
|
||||||
|
notesAdd->getLabel().setText("Add notes");
|
||||||
auto usercard =
|
auto usercard =
|
||||||
user.emplace<EffectLabel2>(this).assign(&this->ui_.usercardLabel);
|
user.emplace<EffectLabel2>(this).assign(&this->ui_.usercardLabel);
|
||||||
usercard->getLabel().setText("Usercard");
|
usercard->getLabel().setText("Usercard");
|
||||||
@@ -485,6 +491,9 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto notesPreview = layout.emplace<Label>().assign(&ui_.notesPreview);
|
||||||
|
notesPreview->setVisible(false);
|
||||||
|
|
||||||
auto lineMod = layout.emplace<Line>(false);
|
auto lineMod = layout.emplace<Line>(false);
|
||||||
|
|
||||||
// third line
|
// third line
|
||||||
@@ -618,6 +627,15 @@ void UserInfoPopup::scaleChangedEvent(float /*scale*/)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UserInfoPopup::windowDeactivationEvent()
|
||||||
|
{
|
||||||
|
if (this->editUserNotesDialog_.isNull() ||
|
||||||
|
!this->editUserNotesDialog_->isVisible())
|
||||||
|
{
|
||||||
|
BaseWindow::windowDeactivationEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UserInfoPopup::installEvents()
|
void UserInfoPopup::installEvents()
|
||||||
{
|
{
|
||||||
std::shared_ptr<bool> ignoreNext = std::make_shared<bool>(false);
|
std::shared_ptr<bool> ignoreNext = std::make_shared<bool>(false);
|
||||||
@@ -742,6 +760,35 @@ void UserInfoPopup::installEvents()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// user notes
|
||||||
|
QObject::connect(
|
||||||
|
this->ui_.notesAdd, &EffectLabel2::clicked, [this]() mutable {
|
||||||
|
if (this->editUserNotesDialog_.isNull())
|
||||||
|
{
|
||||||
|
this->editUserNotesDialog_ = new EditUserNotesDialog(this);
|
||||||
|
// ignoring since it the dialog is only used in this instance
|
||||||
|
std::ignore = this->editUserNotesDialog_->onOk.connect(
|
||||||
|
[userId = this->userId_](const QString &newNotes) {
|
||||||
|
getApp()->getUserData()->setUserNotes(userId, newNotes);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto userData = getApp()->getUserData()->getUser(this->userId_);
|
||||||
|
auto initialNotes =
|
||||||
|
userData.has_value() ? userData->notes : QString();
|
||||||
|
|
||||||
|
this->editUserNotesDialog_->setNotes(initialNotes);
|
||||||
|
this->editUserNotesDialog_->updateWindowTitle(this->userName_);
|
||||||
|
this->editUserNotesDialog_->show();
|
||||||
|
});
|
||||||
|
|
||||||
|
// user data updated
|
||||||
|
this->userDataUpdatedConnection_ =
|
||||||
|
std::make_unique<pajlada::Signals::ScopedConnection>(
|
||||||
|
getApp()->getUserData()->userDataUpdated().connect([this]() {
|
||||||
|
this->updateNotes();
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserInfoPopup::setData(const QString &name, const ChannelPtr &channel)
|
void UserInfoPopup::setData(const QString &name, const ChannelPtr &channel)
|
||||||
@@ -758,6 +805,7 @@ void UserInfoPopup::setData(const QString &name,
|
|||||||
if (isId)
|
if (isId)
|
||||||
{
|
{
|
||||||
this->userId_ = name.mid(idPrefix.size());
|
this->userId_ = name.mid(idPrefix.size());
|
||||||
|
updateNotes();
|
||||||
this->userName_ = "";
|
this->userName_ = "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -879,6 +927,7 @@ void UserInfoPopup::updateUserData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->userId_ = user.id;
|
this->userId_ = user.id;
|
||||||
|
this->updateNotes();
|
||||||
this->avatarUrl_ = user.profileImageUrl;
|
this->avatarUrl_ = user.profileImageUrl;
|
||||||
|
|
||||||
// copyable button for login name of users with a localized username
|
// copyable button for login name of users with a localized username
|
||||||
@@ -1081,6 +1130,31 @@ void UserInfoPopup::loadAvatar(const QUrl &url)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UserInfoPopup::updateNotes()
|
||||||
|
{
|
||||||
|
static QRegularExpression onlySpaceRegex{"^\\s*$"};
|
||||||
|
|
||||||
|
auto userData = getApp()->getUserData()->getUser(this->userId_);
|
||||||
|
if (!userData.has_value() ||
|
||||||
|
onlySpaceRegex.match(userData->notes).hasMatch())
|
||||||
|
{
|
||||||
|
this->ui_.notesPreview->setText("");
|
||||||
|
this->ui_.notesPreview->setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QRegularExpression spaceRegex{"\\s+"};
|
||||||
|
|
||||||
|
auto previewText = "Notes: " + userData->notes.replace(spaceRegex, " ");
|
||||||
|
if (previewText.length() > NOTES_PREVIEW_LENGTH)
|
||||||
|
{
|
||||||
|
previewText = previewText.left(NOTES_PREVIEW_LENGTH - 3) + "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
this->ui_.notesPreview->setText(previewText);
|
||||||
|
this->ui_.notesPreview->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// TimeoutWidget
|
// TimeoutWidget
|
||||||
//
|
//
|
||||||
@@ -1141,42 +1215,6 @@ UserInfoPopup::TimeoutWidget::TimeoutWidget()
|
|||||||
[this, pair] {
|
[this, pair] {
|
||||||
this->buttonClicked.invoke(pair);
|
this->buttonClicked.invoke(pair);
|
||||||
});
|
});
|
||||||
|
|
||||||
//auto addTimeouts = [&](const QString &title_,
|
|
||||||
// const std::vector<std::pair<QString, int>> &items) {
|
|
||||||
// auto vbox = layout.emplace<QVBoxLayout>().withoutMargin();
|
|
||||||
// {
|
|
||||||
// auto title = vbox.emplace<QHBoxLayout>().withoutMargin();
|
|
||||||
// title->addStretch(1);
|
|
||||||
// auto label = title.emplace<Label>(title_);
|
|
||||||
// label->setStyleSheet("color: #BBB");
|
|
||||||
// label->setHasOffset(false);
|
|
||||||
// title->addStretch(1);
|
|
||||||
|
|
||||||
// auto hbox = vbox.emplace<QHBoxLayout>().withoutMargin();
|
|
||||||
// hbox->setSpacing(0);
|
|
||||||
|
|
||||||
// for (const auto &item : items)
|
|
||||||
// {
|
|
||||||
// auto a = hbox.emplace<EffectLabel2>();
|
|
||||||
// a->getLabel().setText(std::get<0>(item));
|
|
||||||
|
|
||||||
// if (std::get<0>(item).length() > 1)
|
|
||||||
// {
|
|
||||||
// a->setScaleIndependantSize(buttonWidth2, buttonHeight);
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// a->setScaleIndependantSize(buttonWidth, buttonHeight);
|
|
||||||
// }
|
|
||||||
// a->setBorderColor(color1);
|
|
||||||
|
|
||||||
// QObject::connect(a.getElement(), &EffectLabel2::leftClicked,
|
|
||||||
// [this, timeout = std::get<1>(item)] {
|
|
||||||
// this->buttonClicked.invoke(std::make_pair(
|
|
||||||
// Action::Timeout, timeout));
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
|
|
||||||
#include <pajlada/signals/scoped-connection.hpp>
|
#include <pajlada/signals/scoped-connection.hpp>
|
||||||
#include <pajlada/signals/signal.hpp>
|
#include <pajlada/signals/signal.hpp>
|
||||||
|
#include <QPointer>
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
|
|
||||||
@@ -15,6 +14,7 @@ namespace chatterino {
|
|||||||
class Channel;
|
class Channel;
|
||||||
using ChannelPtr = std::shared_ptr<Channel>;
|
using ChannelPtr = std::shared_ptr<Channel>;
|
||||||
class Label;
|
class Label;
|
||||||
|
class EditUserNotesDialog;
|
||||||
class ChannelView;
|
class ChannelView;
|
||||||
class Split;
|
class Split;
|
||||||
|
|
||||||
@@ -36,11 +36,13 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void themeChangedEvent() override;
|
void themeChangedEvent() override;
|
||||||
void scaleChangedEvent(float scale) override;
|
void scaleChangedEvent(float scale) override;
|
||||||
|
void windowDeactivationEvent() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void installEvents();
|
void installEvents();
|
||||||
void updateUserData();
|
void updateUserData();
|
||||||
void updateLatestMessages();
|
void updateLatestMessages();
|
||||||
|
void updateNotes();
|
||||||
|
|
||||||
void loadAvatar(const QUrl &url);
|
void loadAvatar(const QUrl &url);
|
||||||
bool isMod_{};
|
bool isMod_{};
|
||||||
@@ -61,6 +63,8 @@ private:
|
|||||||
pajlada::Signals::NoArgSignal userStateChanged_;
|
pajlada::Signals::NoArgSignal userStateChanged_;
|
||||||
|
|
||||||
std::unique_ptr<pajlada::Signals::ScopedConnection> refreshConnection_;
|
std::unique_ptr<pajlada::Signals::ScopedConnection> refreshConnection_;
|
||||||
|
std::unique_ptr<pajlada::Signals::ScopedConnection>
|
||||||
|
userDataUpdatedConnection_;
|
||||||
|
|
||||||
// If we should close the dialog automatically if the user clicks out
|
// If we should close the dialog automatically if the user clicks out
|
||||||
// Set based on the "Automatically close usercard when it loses focus" setting
|
// Set based on the "Automatically close usercard when it loses focus" setting
|
||||||
@@ -82,6 +86,8 @@ private:
|
|||||||
|
|
||||||
QCheckBox *block = nullptr;
|
QCheckBox *block = nullptr;
|
||||||
QCheckBox *ignoreHighlights = nullptr;
|
QCheckBox *ignoreHighlights = nullptr;
|
||||||
|
Label *notesPreview = nullptr;
|
||||||
|
EffectLabel2 *notesAdd = nullptr;
|
||||||
|
|
||||||
Label *noMessagesLabel = nullptr;
|
Label *noMessagesLabel = nullptr;
|
||||||
ChannelView *latestMessages = nullptr;
|
ChannelView *latestMessages = nullptr;
|
||||||
@@ -89,6 +95,8 @@ private:
|
|||||||
EffectLabel2 *usercardLabel = nullptr;
|
EffectLabel2 *usercardLabel = nullptr;
|
||||||
} ui_;
|
} ui_;
|
||||||
|
|
||||||
|
QPointer<EditUserNotesDialog> editUserNotesDialog_;
|
||||||
|
|
||||||
class TimeoutWidget : public BaseWidget
|
class TimeoutWidget : public BaseWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
Reference in New Issue
Block a user