Add a setting to send messages with Enter, Shift+Enter or Ctrl+Enter
Previously the option was just `invertEnterKey` boolean, which didn't allow any flexibility, so I replaced it with a three-choice option: Enter, Shift+Enter and Ctrl+Enter being the send message choices. Add newline combos are Shift+Enter, Enter and Shift+Enter respectively. I ended up fixing the emoji/mention pop-up behavior as a side product. If any of the three combos are pressed, the pop-up is handled and the event is accepted. This makes it impossible to accidentally send the message if a pop-up is open. If an Enter combo didn't match, it's passed to the next event handler. The old `invertEnterKey` is migrated to the new `sendMessageKey`, so this change doesn't change the existing preference.
This commit is contained in:
parent
2769642d3c
commit
451e88fe72
3 changed files with 81 additions and 42 deletions
|
|
@ -170,15 +170,13 @@ Rectangle {
|
||||||
} else if (event.matches(StandardKey.SelectAll) && popup.opened) {
|
} else if (event.matches(StandardKey.SelectAll) && popup.opened) {
|
||||||
completer.completerName = "";
|
completer.completerName = "";
|
||||||
popup.close();
|
popup.close();
|
||||||
} else if (event.matches(StandardKey.InsertLineSeparator)) {
|
} else if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) {
|
||||||
if (popup.opened)
|
// Handling popup takes priority over newline and sending message.
|
||||||
popup.close();
|
if (popup.opened &&
|
||||||
if (Settings.invertEnterKey) {
|
(event.modifiers == Qt.NoModifier
|
||||||
room.input.send();
|
|| event.modifiers == Qt.ShiftModifier
|
||||||
event.accepted = true;
|
|| event.modifiers == Qt.ControlModifier)
|
||||||
}
|
) {
|
||||||
} else if (event.matches(StandardKey.InsertParagraphSeparator)) {
|
|
||||||
if (popup.opened) {
|
|
||||||
var currentCompletion = completer.currentCompletion();
|
var currentCompletion = completer.currentCompletion();
|
||||||
let userid = completer.currentUserid();
|
let userid = completer.currentUserid();
|
||||||
|
|
||||||
|
|
@ -191,14 +189,26 @@ Rectangle {
|
||||||
console.log(userid);
|
console.log(userid);
|
||||||
room.input.addMention(userid, currentCompletion);
|
room.input.addMention(userid, currentCompletion);
|
||||||
}
|
}
|
||||||
event.accepted = true;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
if (!Settings.invertEnterKey) {
|
// Send message Enter key combination event.
|
||||||
|
else if (Settings.sendMessageKey == 0 && event.modifiers == Qt.NoModifier
|
||||||
|
|| Settings.sendMessageKey == 1 && event.modifiers == Qt.ShiftModifier
|
||||||
|
|| Settings.sendMessageKey == 2 && event.modifiers == Qt.ControlModifier
|
||||||
|
) {
|
||||||
room.input.send();
|
room.input.send();
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
|
// Add newline Enter key combination event.
|
||||||
|
else if (Settings.sendMessageKey == 0 && event.modifiers == Qt.ShiftModifier
|
||||||
|
|| Settings.sendMessageKey == 1 && event.modifiers == Qt.NoModifier
|
||||||
|
|| Settings.sendMessageKey == 2 && event.modifiers == Qt.ShiftModifier
|
||||||
|
) {
|
||||||
|
messageInput.insert(messageInput.cursorPosition, "\n");
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
// Any other Enter key combo is ignored here.
|
||||||
} else if (event.key == Qt.Key_Tab && (event.modifiers == Qt.NoModifier || event.modifiers == Qt.ShiftModifier)) {
|
} else if (event.key == Qt.Key_Tab && (event.modifiers == Qt.NoModifier || event.modifiers == Qt.ShiftModifier)) {
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
if (popup.opened) {
|
if (popup.opened) {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,14 @@ QSharedPointer<UserSettings> UserSettings::instance_;
|
||||||
|
|
||||||
UserSettings::UserSettings()
|
UserSettings::UserSettings()
|
||||||
{
|
{
|
||||||
|
if (settings.contains("user/invert_enter_key")) {
|
||||||
|
auto oldValue =
|
||||||
|
(settings.value("user/invert_enter_key", false).toBool() ? SendMessageKey::ShiftEnter
|
||||||
|
: SendMessageKey::Enter);
|
||||||
|
settings.setValue("user/send_message_key", static_cast<int>(oldValue));
|
||||||
|
settings.remove("user/invert_enter_key");
|
||||||
|
}
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
QCoreApplication::instance(), &QCoreApplication::aboutToQuit, []() { instance_.clear(); });
|
QCoreApplication::instance(), &QCoreApplication::aboutToQuit, []() { instance_.clear(); });
|
||||||
}
|
}
|
||||||
|
|
@ -71,8 +79,13 @@ UserSettings::load(std::optional<QString> profile)
|
||||||
settings.value("user/timeline/message_hover_highlight", false).toBool();
|
settings.value("user/timeline/message_hover_highlight", false).toBool();
|
||||||
enlargeEmojiOnlyMessages_ =
|
enlargeEmojiOnlyMessages_ =
|
||||||
settings.value("user/timeline/enlarge_emoji_only_msg", false).toBool();
|
settings.value("user/timeline/enlarge_emoji_only_msg", false).toBool();
|
||||||
markdown_ = settings.value("user/markdown_enabled", true).toBool();
|
markdown_ = settings.value("user/markdown_enabled", true).toBool();
|
||||||
invertEnterKey_ = settings.value("user/invert_enter_key", false).toBool();
|
|
||||||
|
auto sendMessageKey = settings.value("user/send_message_key", 0).toInt();
|
||||||
|
if (sendMessageKey < 0 || sendMessageKey > 2)
|
||||||
|
sendMessageKey = static_cast<int>(SendMessageKey::Enter);
|
||||||
|
sendMessageKey_ = static_cast<SendMessageKey>(sendMessageKey);
|
||||||
|
|
||||||
bubbles_ = settings.value("user/bubbles_enabled", false).toBool();
|
bubbles_ = settings.value("user/bubbles_enabled", false).toBool();
|
||||||
smallAvatars_ = settings.value("user/small_avatars_enabled", false).toBool();
|
smallAvatars_ = settings.value("user/small_avatars_enabled", false).toBool();
|
||||||
animateImagesOnHover_ = settings.value("user/animate_images_on_hover", false).toBool();
|
animateImagesOnHover_ = settings.value("user/animate_images_on_hover", false).toBool();
|
||||||
|
|
@ -340,13 +353,12 @@ UserSettings::setMarkdown(bool state)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UserSettings::setInvertEnterKey(bool state)
|
UserSettings::setSendMessageKey(SendMessageKey key)
|
||||||
{
|
{
|
||||||
if (state == invertEnterKey_)
|
if (key == sendMessageKey_)
|
||||||
return;
|
return;
|
||||||
|
sendMessageKey_ = key;
|
||||||
invertEnterKey_ = state;
|
emit sendMessageKeyChanged(key);
|
||||||
emit invertEnterKeyChanged(state);
|
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -936,7 +948,7 @@ UserSettings::save()
|
||||||
settings.setValue("group_view", groupView_);
|
settings.setValue("group_view", groupView_);
|
||||||
settings.setValue("scrollbars_in_roomlist", scrollbarsInRoomlist_);
|
settings.setValue("scrollbars_in_roomlist", scrollbarsInRoomlist_);
|
||||||
settings.setValue("markdown_enabled", markdown_);
|
settings.setValue("markdown_enabled", markdown_);
|
||||||
settings.setValue("invert_enter_key", invertEnterKey_);
|
settings.setValue("send_message_key", static_cast<int>(sendMessageKey_));
|
||||||
settings.setValue("bubbles_enabled", bubbles_);
|
settings.setValue("bubbles_enabled", bubbles_);
|
||||||
settings.setValue("small_avatars_enabled", smallAvatars_);
|
settings.setValue("small_avatars_enabled", smallAvatars_);
|
||||||
settings.setValue("animate_images_on_hover", animateImagesOnHover_);
|
settings.setValue("animate_images_on_hover", animateImagesOnHover_);
|
||||||
|
|
@ -1050,8 +1062,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
||||||
return tr("Scrollbars in room list");
|
return tr("Scrollbars in room list");
|
||||||
case Markdown:
|
case Markdown:
|
||||||
return tr("Send messages as Markdown");
|
return tr("Send messages as Markdown");
|
||||||
case InvertEnterKey:
|
case SendMessageKey:
|
||||||
return tr("Use shift+enter to send and enter to start a new line");
|
return tr("Send messages with a shortcut");
|
||||||
case Bubbles:
|
case Bubbles:
|
||||||
return tr("Enable message bubbles");
|
return tr("Enable message bubbles");
|
||||||
case SmallAvatars:
|
case SmallAvatars:
|
||||||
|
|
@ -1205,8 +1217,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
||||||
return i->scrollbarsInRoomlist();
|
return i->scrollbarsInRoomlist();
|
||||||
case Markdown:
|
case Markdown:
|
||||||
return i->markdown();
|
return i->markdown();
|
||||||
case InvertEnterKey:
|
case SendMessageKey:
|
||||||
return i->invertEnterKey();
|
return static_cast<int>(i->sendMessageKey());
|
||||||
case Bubbles:
|
case Bubbles:
|
||||||
return i->bubbles();
|
return i->bubbles();
|
||||||
case SmallAvatars:
|
case SmallAvatars:
|
||||||
|
|
@ -1371,10 +1383,11 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
||||||
return tr(
|
return tr(
|
||||||
"Allow using markdown in messages.\nWhen disabled, all messages are sent as a plain "
|
"Allow using markdown in messages.\nWhen disabled, all messages are sent as a plain "
|
||||||
"text.");
|
"text.");
|
||||||
case InvertEnterKey:
|
case SendMessageKey:
|
||||||
return tr(
|
return tr(
|
||||||
"Invert the behavior of the enter key in the text input, making it send the message "
|
"Select what Enter key combination sends the message. Shift+Enter adds a new line, "
|
||||||
"when shift+enter is pressed and starting a new line when enter is pressed.");
|
"unless it has been selected, in which case Enter adds a new line instead.\n\n"
|
||||||
|
"If an emoji picker or a mention picker is open, it is always handled first.");
|
||||||
case Bubbles:
|
case Bubbles:
|
||||||
return tr(
|
return tr(
|
||||||
"Messages get a bubble background. This also triggers some layout changes (WIP).");
|
"Messages get a bubble background. This also triggers some layout changes (WIP).");
|
||||||
|
|
@ -1542,6 +1555,7 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
||||||
case CameraFrameRate:
|
case CameraFrameRate:
|
||||||
case Ringtone:
|
case Ringtone:
|
||||||
case ShowImage:
|
case ShowImage:
|
||||||
|
case SendMessageKey:
|
||||||
return Options;
|
return Options;
|
||||||
case TimelineMaxWidth:
|
case TimelineMaxWidth:
|
||||||
case PrivacyScreenTimeout:
|
case PrivacyScreenTimeout:
|
||||||
|
|
@ -1556,7 +1570,6 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
||||||
case GroupView:
|
case GroupView:
|
||||||
case ScrollbarsInRoomlist:
|
case ScrollbarsInRoomlist:
|
||||||
case Markdown:
|
case Markdown:
|
||||||
case InvertEnterKey:
|
|
||||||
case Bubbles:
|
case Bubbles:
|
||||||
case SmallAvatars:
|
case SmallAvatars:
|
||||||
case AnimateImagesOnHover:
|
case AnimateImagesOnHover:
|
||||||
|
|
@ -1675,6 +1688,12 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
||||||
tr("Only in private rooms"),
|
tr("Only in private rooms"),
|
||||||
tr("Never"),
|
tr("Never"),
|
||||||
};
|
};
|
||||||
|
case SendMessageKey:
|
||||||
|
return QStringList{
|
||||||
|
tr("Enter"),
|
||||||
|
tr("Shift+Enter"),
|
||||||
|
tr("Ctrl+Enter"),
|
||||||
|
};
|
||||||
case Microphone:
|
case Microphone:
|
||||||
return vecToList(CallDevices::instance().names(false, i->microphone().toStdString()));
|
return vecToList(CallDevices::instance().names(false, i->microphone().toStdString()));
|
||||||
case Camera:
|
case Camera:
|
||||||
|
|
@ -1816,12 +1835,14 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case InvertEnterKey: {
|
case SendMessageKey: {
|
||||||
if (value.userType() == QMetaType::Bool) {
|
auto newKey = value.toInt();
|
||||||
i->setInvertEnterKey(value.toBool());
|
if (newKey < 0 ||
|
||||||
return true;
|
QMetaEnum::fromType<UserSettings::SendMessageKey>().keyCount() <= newKey)
|
||||||
} else
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
i->setSendMessageKey(static_cast<UserSettings::SendMessageKey>(newKey));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
case Bubbles: {
|
case Bubbles: {
|
||||||
if (value.userType() == QMetaType::Bool) {
|
if (value.userType() == QMetaType::Bool) {
|
||||||
|
|
@ -2306,8 +2327,8 @@ UserSettingsModel::UserSettingsModel(QObject *p)
|
||||||
connect(s.get(), &UserSettings::markdownChanged, this, [this]() {
|
connect(s.get(), &UserSettings::markdownChanged, this, [this]() {
|
||||||
emit dataChanged(index(Markdown), index(Markdown), {Value});
|
emit dataChanged(index(Markdown), index(Markdown), {Value});
|
||||||
});
|
});
|
||||||
connect(s.get(), &UserSettings::invertEnterKeyChanged, this, [this]() {
|
connect(s.get(), &UserSettings::sendMessageKeyChanged, this, [this]() {
|
||||||
emit dataChanged(index(InvertEnterKey), index(InvertEnterKey), {Value});
|
emit dataChanged(index(SendMessageKey), index(SendMessageKey), {Value});
|
||||||
});
|
});
|
||||||
connect(s.get(), &UserSettings::bubblesChanged, this, [this]() {
|
connect(s.get(), &UserSettings::bubblesChanged, this, [this]() {
|
||||||
emit dataChanged(index(Bubbles), index(Bubbles), {Value});
|
emit dataChanged(index(Bubbles), index(Bubbles), {Value});
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ class UserSettings final : public QObject
|
||||||
Q_PROPERTY(bool scrollbarsInRoomlist READ scrollbarsInRoomlist WRITE setScrollbarsInRoomlist
|
Q_PROPERTY(bool scrollbarsInRoomlist READ scrollbarsInRoomlist WRITE setScrollbarsInRoomlist
|
||||||
NOTIFY scrollbarsInRoomlistChanged)
|
NOTIFY scrollbarsInRoomlistChanged)
|
||||||
Q_PROPERTY(bool markdown READ markdown WRITE setMarkdown NOTIFY markdownChanged)
|
Q_PROPERTY(bool markdown READ markdown WRITE setMarkdown NOTIFY markdownChanged)
|
||||||
Q_PROPERTY(
|
Q_PROPERTY(SendMessageKey sendMessageKey READ sendMessageKey WRITE setSendMessageKey NOTIFY
|
||||||
bool invertEnterKey READ invertEnterKey WRITE setInvertEnterKey NOTIFY invertEnterKeyChanged)
|
sendMessageKeyChanged)
|
||||||
Q_PROPERTY(bool bubbles READ bubbles WRITE setBubbles NOTIFY bubblesChanged)
|
Q_PROPERTY(bool bubbles READ bubbles WRITE setBubbles NOTIFY bubblesChanged)
|
||||||
Q_PROPERTY(bool smallAvatars READ smallAvatars WRITE setSmallAvatars NOTIFY smallAvatarsChanged)
|
Q_PROPERTY(bool smallAvatars READ smallAvatars WRITE setSmallAvatars NOTIFY smallAvatarsChanged)
|
||||||
Q_PROPERTY(bool animateImagesOnHover READ animateImagesOnHover WRITE setAnimateImagesOnHover
|
Q_PROPERTY(bool animateImagesOnHover READ animateImagesOnHover WRITE setAnimateImagesOnHover
|
||||||
|
|
@ -166,6 +166,14 @@ public:
|
||||||
};
|
};
|
||||||
Q_ENUM(ShowImage)
|
Q_ENUM(ShowImage)
|
||||||
|
|
||||||
|
enum class SendMessageKey
|
||||||
|
{
|
||||||
|
Enter,
|
||||||
|
ShiftEnter,
|
||||||
|
CtrlEnter,
|
||||||
|
};
|
||||||
|
Q_ENUM(SendMessageKey)
|
||||||
|
|
||||||
void save();
|
void save();
|
||||||
void load(std::optional<QString> profile);
|
void load(std::optional<QString> profile);
|
||||||
void applyTheme();
|
void applyTheme();
|
||||||
|
|
@ -182,7 +190,7 @@ public:
|
||||||
void setGroupView(bool state);
|
void setGroupView(bool state);
|
||||||
void setScrollbarsInRoomlist(bool state);
|
void setScrollbarsInRoomlist(bool state);
|
||||||
void setMarkdown(bool state);
|
void setMarkdown(bool state);
|
||||||
void setInvertEnterKey(bool state);
|
void setSendMessageKey(SendMessageKey key);
|
||||||
void setBubbles(bool state);
|
void setBubbles(bool state);
|
||||||
void setSmallAvatars(bool state);
|
void setSmallAvatars(bool state);
|
||||||
void setAnimateImagesOnHover(bool state);
|
void setAnimateImagesOnHover(bool state);
|
||||||
|
|
@ -255,7 +263,7 @@ public:
|
||||||
bool privacyScreen() const { return privacyScreen_; }
|
bool privacyScreen() const { return privacyScreen_; }
|
||||||
int privacyScreenTimeout() const { return privacyScreenTimeout_; }
|
int privacyScreenTimeout() const { return privacyScreenTimeout_; }
|
||||||
bool markdown() const { return markdown_; }
|
bool markdown() const { return markdown_; }
|
||||||
bool invertEnterKey() const { return invertEnterKey_; }
|
SendMessageKey sendMessageKey() const { return sendMessageKey_; }
|
||||||
bool bubbles() const { return bubbles_; }
|
bool bubbles() const { return bubbles_; }
|
||||||
bool smallAvatars() const { return smallAvatars_; }
|
bool smallAvatars() const { return smallAvatars_; }
|
||||||
bool animateImagesOnHover() const { return animateImagesOnHover_; }
|
bool animateImagesOnHover() const { return animateImagesOnHover_; }
|
||||||
|
|
@ -328,7 +336,7 @@ signals:
|
||||||
void trayChanged(bool state);
|
void trayChanged(bool state);
|
||||||
void startInTrayChanged(bool state);
|
void startInTrayChanged(bool state);
|
||||||
void markdownChanged(bool state);
|
void markdownChanged(bool state);
|
||||||
void invertEnterKeyChanged(bool state);
|
void sendMessageKeyChanged(SendMessageKey key);
|
||||||
void bubblesChanged(bool state);
|
void bubblesChanged(bool state);
|
||||||
void smallAvatarsChanged(bool state);
|
void smallAvatarsChanged(bool state);
|
||||||
void animateImagesOnHoverChanged(bool state);
|
void animateImagesOnHoverChanged(bool state);
|
||||||
|
|
@ -399,7 +407,7 @@ private:
|
||||||
bool groupView_;
|
bool groupView_;
|
||||||
bool scrollbarsInRoomlist_;
|
bool scrollbarsInRoomlist_;
|
||||||
bool markdown_;
|
bool markdown_;
|
||||||
bool invertEnterKey_;
|
SendMessageKey sendMessageKey_;
|
||||||
bool bubbles_;
|
bool bubbles_;
|
||||||
bool smallAvatars_;
|
bool smallAvatars_;
|
||||||
bool animateImagesOnHover_;
|
bool animateImagesOnHover_;
|
||||||
|
|
@ -510,7 +518,7 @@ class UserSettingsModel : public QAbstractListModel
|
||||||
TypingNotifications,
|
TypingNotifications,
|
||||||
ReadReceipts,
|
ReadReceipts,
|
||||||
Markdown,
|
Markdown,
|
||||||
InvertEnterKey,
|
SendMessageKey,
|
||||||
Bubbles,
|
Bubbles,
|
||||||
SmallAvatars,
|
SmallAvatars,
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue