Feature: execute commands on chat messages using the context menu (#3738)

This commit is contained in:
xel86 2022-05-22 10:45:54 -04:00 committed by GitHub
parent 7d9c3c65da
commit 4239666934
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 103 additions and 9 deletions

View file

@ -15,6 +15,7 @@
- Minor: Prevent user from entering incorrect characters in Live Notifications channels list. (#3715, #3730)
- Minor: Fixed automod caught message notice appearing twice for mods. (#3717)
- Minor: Added `/requests` command. Usage: `/requests [channel]`. Opens the channel points requests queue for the provided channel or the current channel if no input is provided. (#3746)
- Minor: Added ability to execute commands on chat messages using the message context menu. (#3738)
- Bugfix: Fixed live notifications for usernames containing uppercase characters. (#3646)
- Bugfix: Fixed live notifications not getting updated for closed streams going offline. (#3678)
- Bugfix: Fixed certain settings dialogs appearing behind the main window, when `Always on top` was used. (#3679)

View file

@ -15,11 +15,14 @@ Command::Command(const QString &_text)
this->name = _text.mid(0, index).trimmed();
this->func = _text.mid(index + 1).trimmed();
this->showInMsgContextMenu = false;
}
Command::Command(const QString &_name, const QString &_func)
Command::Command(const QString &_name, const QString &_func,
bool _showInMsgContextMenu)
: name(_name.trimmed())
, func(_func.trimmed())
, showInMsgContextMenu(_showInMsgContextMenu)
{
}

View file

@ -10,10 +10,12 @@ namespace chatterino {
struct Command {
QString name;
QString func;
bool showInMsgContextMenu;
Command() = default;
explicit Command(const QString &text);
Command(const QString &name, const QString &func);
Command(const QString &name, const QString &func,
bool showInMsgContextMenu = false);
QString toString() const;
};
@ -31,6 +33,8 @@ struct Serialize<chatterino::Command> {
chatterino::rj::set(ret, "name", value.name, a);
chatterino::rj::set(ret, "func", value.func, a);
chatterino::rj::set(ret, "showInMsgContextMenu",
value.showInMsgContextMenu, a);
return ret;
}
@ -59,6 +63,15 @@ struct Deserialize<chatterino::Command> {
PAJLADA_REPORT_ERROR(error);
return command;
}
if (!chatterino::rj::getSafe(value, "showInMsgContextMenu",
command.showInMsgContextMenu))
{
command.showInMsgContextMenu = false;
PAJLADA_REPORT_ERROR(error);
return command;
}
return command;
}

View file

@ -6,7 +6,7 @@ namespace chatterino {
// commandmodel
CommandModel::CommandModel(QObject *parent)
: SignalVectorModel<Command>(2, parent)
: SignalVectorModel<Command>(Column::COUNT, parent)
{
}
@ -14,16 +14,21 @@ CommandModel::CommandModel(QObject *parent)
Command CommandModel::getItemFromRow(std::vector<QStandardItem *> &row,
const Command &original)
{
return Command(row[0]->data(Qt::EditRole).toString(),
row[1]->data(Qt::EditRole).toString());
return Command(row[Column::Trigger]->data(Qt::EditRole).toString(),
row[Column::CommandFunc]->data(Qt::EditRole).toString(),
row[Column::ShowInMessageContextMenu]
->data(Qt::CheckStateRole)
.toBool());
}
// turns a row in the model into a vector item
void CommandModel::getRowFromItem(const Command &item,
std::vector<QStandardItem *> &row)
{
setStringItem(row[0], item.name);
setStringItem(row[1], item.func);
setStringItem(row[Column::Trigger], item.name);
setStringItem(row[Column::CommandFunc], item.func);
setBoolItem(row[Column::ShowInMessageContextMenu],
item.showInMsgContextMenu);
}
} // namespace chatterino

View file

@ -13,6 +13,13 @@ class CommandModel : public SignalVectorModel<Command>
{
explicit CommandModel(QObject *parent);
enum Column {
Trigger = 0,
CommandFunc = 1,
ShowInMessageContextMenu = 2,
COUNT,
};
protected:
// turn a vector item into a model row
virtual Command getItemFromRow(std::vector<QStandardItem *> &row,

View file

@ -1885,6 +1885,10 @@ void ChannelView::addContextMenuItems(
// Add hidden options (e.g. copy message ID) if the user held down Shift
this->addHiddenContextMenuItems(hoveredElement, layout, event, *menu);
// Add executable command options
this->addCommandExecutionContextMenuItems(hoveredElement, layout, event,
*menu);
menu->popup(QCursor::pos());
menu->raise();
}
@ -2081,6 +2085,62 @@ void ChannelView::addHiddenContextMenuItems(
});
}
}
void ChannelView::addCommandExecutionContextMenuItems(
const MessageLayoutElement * /*hoveredElement*/, MessageLayoutPtr layout,
QMouseEvent * /*event*/, QMenu &menu)
{
/* Get commands to be displayed in context menu;
* only those that had the showInMsgContextMenu check box marked in the Commands page */
std::vector<Command> cmds;
for (auto &cmd : getApp()->commands->items)
{
if (cmd.showInMsgContextMenu)
{
cmds.push_back(cmd);
}
}
if (cmds.empty())
{
return;
}
menu.addSeparator();
auto executeAction = menu.addAction("Execute command");
auto cmdMenu = new QMenu;
executeAction->setMenu(cmdMenu);
for (auto &cmd : cmds)
{
QString inputText = this->selection_.isEmpty()
? layout->getMessage()->messageText
: this->getSelectedText();
inputText.push_front(cmd.name + " ");
cmdMenu->addAction(cmd.name, [this, inputText] {
ChannelPtr channel;
/* Search popups and user message history's underlyingChannels aren't of type TwitchChannel, but
* we would still like to execute commands from them. Use their source channel instead if applicable. */
if (this->hasSourceChannel())
{
channel = this->sourceChannel();
}
else
{
channel = this->underlyingChannel_;
}
QString value =
getApp()->commands->execCommand(inputText, channel, false);
channel->sendMessage(value);
});
}
}
void ChannelView::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() != Qt::LeftButton)

View file

@ -184,6 +184,10 @@ private:
void addHiddenContextMenuItems(const MessageLayoutElement *hoveredElement,
MessageLayoutPtr layout, QMouseEvent *event,
QMenu &menu);
void addCommandExecutionContextMenuItems(
const MessageLayoutElement *hoveredElement, MessageLayoutPtr layout,
QMouseEvent *event, QMenu &menu);
int getLayoutWidth() const;
void updatePauses();
void unpaused();

View file

@ -44,8 +44,9 @@ CommandPage::CommandPage()
layout.emplace<EditableModelView>(app->commands->createModel(nullptr))
.getElement();
view->setTitles({"Trigger", "Command"});
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
view->setTitles({"Trigger", "Command", "Show In\nMessage Menu"});
view->getTableView()->horizontalHeader()->setSectionResizeMode(
1, QHeaderView::Stretch);
view->addButtonPressed.connect([] {
getApp()->commands->items.append(
Command{"/command", "I made a new command HeyGuys"});