From b6ef00b5ee14bd0adc85c3a98bb8a127f79932ea Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Thu, 23 Feb 2023 21:57:53 -0500 Subject: Show warning when invalid command is entered Fixes #1363 Please note that this doesn't prompt when you try to send a message with a bad command. --- src/CompletionProxyModel.h | 2 ++ src/timeline/InputBar.cpp | 2 ++ src/ui/NhekoGlobalObject.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++ src/ui/NhekoGlobalObject.h | 3 +++ 4 files changed, 67 insertions(+) (limited to 'src') diff --git a/src/CompletionProxyModel.h b/src/CompletionProxyModel.h index e0f00788..90daf7ad 100644 --- a/src/CompletionProxyModel.h +++ b/src/CompletionProxyModel.h @@ -184,6 +184,8 @@ public slots: void setSearchString(const QString &s); QString searchString() const { return searchString_; } + bool hasCompletion() const { return rowCount() > 0; } + signals: void newSearchString(QString); diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 7d964bb5..5184ba94 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -846,6 +846,8 @@ InputBar::command(const QString &command, QString args) cache::getMembers(this->room->roomId().toStdString(), 0, -1)); } else if (command == QLatin1String("converttoroom")) { utils::removeDirectFromRoom(this->room->roomId()); + } else { + message("/" + command + " " + args); } } diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp index a6f9abe7..3cb6a8a8 100644 --- a/src/ui/NhekoGlobalObject.cpp +++ b/src/ui/NhekoGlobalObject.cpp @@ -190,3 +190,63 @@ Nheko::setWindowRole([[maybe_unused]] QWindow *win, [[maybe_unused]] QString new QXcbWindowFunctions::setWmWindowRole(win, newRole.toUtf8()); #endif } + +QString +Nheko::getCommandFromText(const QString &text) +{ + if (text.startsWith('/')) { + int command_end = text.indexOf(QRegularExpression(QStringLiteral("\\s"))); + if (command_end == -1) + command_end = text.size(); + auto command = text.mid(1, command_end - 1); + if (command.isEmpty() || command == QLatin1String("/")) + return {}; + else { + return command; + } + } else + return {}; +} + +bool +Nheko::isInvalidCommand(QString command) const +{ + if (command.size() <= 0) + return false; + + static const QStringList validCommands{QStringLiteral("/me"), + QStringLiteral("/react"), + QStringLiteral("/join"), + QStringLiteral("/knock"), + QStringLiteral("/part"), + QStringLiteral("/leave"), + QStringLiteral("/invite"), + QStringLiteral("/kick"), + QStringLiteral("/ban"), + QStringLiteral("/unban"), + QStringLiteral("/redact"), + QStringLiteral("/roomnick"), + QStringLiteral("/shrug"), + QStringLiteral("/fliptable"), + QStringLiteral("/unfliptable"), + QStringLiteral("/sovietflip"), + QStringLiteral("/clear-timeline"), + QStringLiteral("/reset-state"), + QStringLiteral("/rotate-megolm-session"), + QStringLiteral("/md"), + QStringLiteral("/cmark"), + QStringLiteral("/plain"), + QStringLiteral("/rainbow"), + QStringLiteral("/rainbowme"), + QStringLiteral("/notice"), + QStringLiteral("/rainbownotice"), + QStringLiteral("/confetti"), + QStringLiteral("/rainbowconfetti"), + QStringLiteral("/goto"), + QStringLiteral("/converttodm"), + QStringLiteral("/converttoroom")}; + + if (!command.startsWith('/')) + command.prepend('/'); + return !validCommands.contains(command); +} diff --git a/src/ui/NhekoGlobalObject.h b/src/ui/NhekoGlobalObject.h index b7a7a637..1ea2c109 100644 --- a/src/ui/NhekoGlobalObject.h +++ b/src/ui/NhekoGlobalObject.h @@ -72,6 +72,9 @@ public: Q_INVOKABLE void setTransientParent(QWindow *window, QWindow *parentWindow) const; Q_INVOKABLE void setWindowRole(QWindow *win, QString newRole) const; + Q_INVOKABLE QString getCommandFromText(const QString &text); + Q_INVOKABLE bool isInvalidCommand(QString command) const; + public slots: void updateUserProfile(); -- cgit 1.5.1 From 22ac5d861e487ff39749f5d2bdda9113689e4b63 Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Mon, 27 Feb 2023 18:06:24 -0500 Subject: Move command calculation logic into InputBar --- resources/qml/TimelineView.qml | 13 +----- src/timeline/InputBar.cpp | 94 ++++++++++++++++++++++++++++++++++-------- src/timeline/InputBar.h | 16 +++++-- src/ui/NhekoGlobalObject.cpp | 60 --------------------------- src/ui/NhekoGlobalObject.h | 3 -- 5 files changed, 91 insertions(+), 95 deletions(-) (limited to 'src') diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 5c982270..100ed1d7 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -159,17 +159,8 @@ Item { } MessageInputWarning { - text: qsTr("The command /%1 is not recognized and will be sent as part of your message").arg(Nheko.getCommandFromText(input.text)) - isVisible: { - if (!input.text) - return false; - - let command = Nheko.getCommandFromText(input.text); - if (Nheko.isInvalidCommand(command) && ("/" + command !== input.text)) - return true; - else - return false; - } + text: qsTr("The command /%1 is not recognized and will be sent as part of your message").arg(room ? room.input.currentCommand : "") + isVisible: room ? room.input.containsInvalidCommand : false } ReplyPopup { diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 5184ba94..6c882cd4 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -224,8 +224,9 @@ InputBar::insertMimeData(const QMimeData *md) } void -InputBar::updateAtRoom(const QString &t) +InputBar::updateTextContentProperties(const QString &t) { + // check for @room bool roomMention = false; if (t.size() > 4) { @@ -249,6 +250,54 @@ InputBar::updateAtRoom(const QString &t) this->containsAtRoom_ = roomMention; emit containsAtRoomChanged(); } + + // check for invalid commands + auto commandName = getCommandAndArgs().first; + bool hasInvalidCommand{}; + if (!commandName.isNull() && '/' + commandName != text()) { + static const QStringList validCommands{QStringLiteral("me"), + QStringLiteral("react"), + QStringLiteral("join"), + QStringLiteral("knock"), + QStringLiteral("part"), + QStringLiteral("leave"), + QStringLiteral("invite"), + QStringLiteral("kick"), + QStringLiteral("ban"), + QStringLiteral("unban"), + QStringLiteral("redact"), + QStringLiteral("roomnick"), + QStringLiteral("shrug"), + QStringLiteral("fliptable"), + QStringLiteral("unfliptable"), + QStringLiteral("sovietflip"), + QStringLiteral("clear-timeline"), + QStringLiteral("reset-state"), + QStringLiteral("rotate-megolm-session"), + QStringLiteral("md"), + QStringLiteral("cmark"), + QStringLiteral("plain"), + QStringLiteral("rainbow"), + QStringLiteral("rainbowme"), + QStringLiteral("notice"), + QStringLiteral("rainbownotice"), + QStringLiteral("confetti"), + QStringLiteral("rainbowconfetti"), + QStringLiteral("goto"), + QStringLiteral("converttodm"), + QStringLiteral("converttoroom")}; + hasInvalidCommand = !validCommands.contains(commandName); + } else + hasInvalidCommand = false; + + if (containsInvalidCommand_ != hasInvalidCommand) { + containsInvalidCommand_ = hasInvalidCommand; + emit containsInvalidCommandChanged(); + } + if (currentCommand_ != commandName) { + currentCommand_ = commandName; + emit currentCommandChanged(); + } } void @@ -263,7 +312,7 @@ InputBar::setText(const QString &newText) if (history_.size() == INPUT_HISTORY_SIZE) history_.pop_back(); - updateAtRoom(QLatin1String("")); + updateTextContentProperties(QLatin1String("")); emit textChanged(newText); } void @@ -284,7 +333,7 @@ InputBar::updateState(int selectionStart_, history_.front() = text_; history_index_ = 0; - updateAtRoom(text_); + updateTextContentProperties(text_); // disabled, as it moves the cursor to the end // emit textChanged(text_); } @@ -312,7 +361,7 @@ InputBar::previousText() else if (text().isEmpty()) history_index_--; - updateAtRoom(text()); + updateTextContentProperties(text()); return text(); } @@ -323,7 +372,7 @@ InputBar::nextText() if (history_index_ >= INPUT_HISTORY_SIZE) history_index_ = 0; - updateAtRoom(text()); + updateTextContentProperties(text()); return text(); } @@ -341,20 +390,11 @@ InputBar::send() auto wasEdit = !room->edit().isEmpty(); - if (text().startsWith('/')) { - int command_end = text().indexOf(QRegularExpression(QStringLiteral("\\s"))); - if (command_end == -1) - command_end = text().size(); - auto name = text().mid(1, command_end - 1); - auto args = text().mid(command_end + 1); - if (name.isEmpty() || name == QLatin1String("/")) { - message(args); - } else { - command(name, args); - } - } else { + auto [commandName, args] = getCommandAndArgs(); + if (commandName.isNull()) message(text()); - } + else + command(commandName, args); if (!wasEdit) { history_.push_front(QLatin1String("")); @@ -716,6 +756,24 @@ InputBar::video(const QString &filename, room->sendMessageEvent(video, mtx::events::EventType::RoomMessage); } +QPair +InputBar::getCommandAndArgs() const +{ + if (!text().startsWith('/')) + return {{}, text()}; + + int command_end = text().indexOf(QRegularExpression(QStringLiteral("\\s"))); + if (command_end == -1) + command_end = text().size(); + auto name = text().mid(1, command_end - 1); + auto args = text().mid(command_end + 1); + if (name.isEmpty() || name == QLatin1String("/")) { + return {{}, text()}; + } else { + return {name, args}; + } +} + void InputBar::sticker(CombinedImagePackModel *model, int row) { diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index 80ad7f47..7385d272 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -173,6 +173,9 @@ class InputBar final : public QObject Q_OBJECT Q_PROPERTY(bool uploading READ uploading NOTIFY uploadingChanged) Q_PROPERTY(bool containsAtRoom READ containsAtRoom NOTIFY containsAtRoomChanged) + Q_PROPERTY( + bool containsInvalidCommand READ containsInvalidCommand NOTIFY containsInvalidCommandChanged) + Q_PROPERTY(QString currentCommand READ currentCommand NOTIFY currentCommandChanged) Q_PROPERTY(QString text READ text NOTIFY textChanged) Q_PROPERTY(QVariantList uploads READ uploads NOTIFY uploadsChanged) @@ -198,6 +201,8 @@ public slots: void setText(const QString &newText); [[nodiscard]] bool containsAtRoom() const { return containsAtRoom_; } + bool containsInvalidCommand() const { return containsInvalidCommand_; } + QString currentCommand() const { return currentCommand_; } void send(); bool tryPasteAttachment(bool fromMouse); @@ -225,6 +230,8 @@ signals: void textChanged(QString newText); void uploadingChanged(bool value); void containsAtRoomChanged(); + void containsInvalidCommandChanged(); + void currentCommandChanged(); void uploadsChanged(); private: @@ -267,6 +274,7 @@ private: const QSize &thumbnailDimensions, const QString &blurhash); + QPair getCommandAndArgs() const; mtx::common::Relations generateRelations() const; void startUploadFromPath(const QString &path); @@ -280,7 +288,7 @@ private: } } - void updateAtRoom(const QString &t); + void updateTextContentProperties(const QString &t); QTimer typingRefresh_; QTimer typingTimeout_; @@ -288,8 +296,10 @@ private: std::deque history_; std::size_t history_index_ = 0; int selectionStart = 0, selectionEnd = 0, cursorPosition = 0; - bool uploading_ = false; - bool containsAtRoom_ = false; + bool uploading_ = false; + bool containsAtRoom_ = false; + bool containsInvalidCommand_ = false; + QString currentCommand_; using UploadHandle = std::unique_ptr; std::vector unconfirmedUploads; diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp index 3cb6a8a8..a6f9abe7 100644 --- a/src/ui/NhekoGlobalObject.cpp +++ b/src/ui/NhekoGlobalObject.cpp @@ -190,63 +190,3 @@ Nheko::setWindowRole([[maybe_unused]] QWindow *win, [[maybe_unused]] QString new QXcbWindowFunctions::setWmWindowRole(win, newRole.toUtf8()); #endif } - -QString -Nheko::getCommandFromText(const QString &text) -{ - if (text.startsWith('/')) { - int command_end = text.indexOf(QRegularExpression(QStringLiteral("\\s"))); - if (command_end == -1) - command_end = text.size(); - auto command = text.mid(1, command_end - 1); - if (command.isEmpty() || command == QLatin1String("/")) - return {}; - else { - return command; - } - } else - return {}; -} - -bool -Nheko::isInvalidCommand(QString command) const -{ - if (command.size() <= 0) - return false; - - static const QStringList validCommands{QStringLiteral("/me"), - QStringLiteral("/react"), - QStringLiteral("/join"), - QStringLiteral("/knock"), - QStringLiteral("/part"), - QStringLiteral("/leave"), - QStringLiteral("/invite"), - QStringLiteral("/kick"), - QStringLiteral("/ban"), - QStringLiteral("/unban"), - QStringLiteral("/redact"), - QStringLiteral("/roomnick"), - QStringLiteral("/shrug"), - QStringLiteral("/fliptable"), - QStringLiteral("/unfliptable"), - QStringLiteral("/sovietflip"), - QStringLiteral("/clear-timeline"), - QStringLiteral("/reset-state"), - QStringLiteral("/rotate-megolm-session"), - QStringLiteral("/md"), - QStringLiteral("/cmark"), - QStringLiteral("/plain"), - QStringLiteral("/rainbow"), - QStringLiteral("/rainbowme"), - QStringLiteral("/notice"), - QStringLiteral("/rainbownotice"), - QStringLiteral("/confetti"), - QStringLiteral("/rainbowconfetti"), - QStringLiteral("/goto"), - QStringLiteral("/converttodm"), - QStringLiteral("/converttoroom")}; - - if (!command.startsWith('/')) - command.prepend('/'); - return !validCommands.contains(command); -} diff --git a/src/ui/NhekoGlobalObject.h b/src/ui/NhekoGlobalObject.h index 1ea2c109..b7a7a637 100644 --- a/src/ui/NhekoGlobalObject.h +++ b/src/ui/NhekoGlobalObject.h @@ -72,9 +72,6 @@ public: Q_INVOKABLE void setTransientParent(QWindow *window, QWindow *parentWindow) const; Q_INVOKABLE void setWindowRole(QWindow *win, QString newRole) const; - Q_INVOKABLE QString getCommandFromText(const QString &text); - Q_INVOKABLE bool isInvalidCommand(QString command) const; - public slots: void updateUserProfile(); -- cgit 1.5.1 From b4f8d4947ff517ae1498d5787ebb34ca3803ad13 Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Mon, 27 Feb 2023 18:12:19 -0500 Subject: Simplify code a bit --- resources/qml/TimelineView.qml | 1 - src/CompletionProxyModel.h | 2 -- src/timeline/InputBar.cpp | 3 +-- 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 100ed1d7..cc615fd3 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -167,7 +167,6 @@ Item { } MessageInput { - id: input } } diff --git a/src/CompletionProxyModel.h b/src/CompletionProxyModel.h index 90daf7ad..e0f00788 100644 --- a/src/CompletionProxyModel.h +++ b/src/CompletionProxyModel.h @@ -184,8 +184,6 @@ public slots: void setSearchString(const QString &s); QString searchString() const { return searchString_; } - bool hasCompletion() const { return rowCount() > 0; } - signals: void newSearchString(QString); diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 6c882cd4..2491b5c1 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -390,8 +390,7 @@ InputBar::send() auto wasEdit = !room->edit().isEmpty(); - auto [commandName, args] = getCommandAndArgs(); - if (commandName.isNull()) + if (auto [commandName, args] = getCommandAndArgs(); commandName.isNull()) message(text()); else command(commandName, args); -- cgit 1.5.1 From ec8820ac646ee20547ded7c9783bc5bbe602f92e Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Wed, 1 Mar 2023 17:04:17 -0500 Subject: Fix some nitpicks --- src/timeline/InputBar.cpp | 109 ++++++++++++++++++++++++---------------------- src/timeline/InputBar.h | 2 +- 2 files changed, 58 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 2491b5c1..693fe789 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -253,50 +253,51 @@ InputBar::updateTextContentProperties(const QString &t) // check for invalid commands auto commandName = getCommandAndArgs().first; - bool hasInvalidCommand{}; - if (!commandName.isNull() && '/' + commandName != text()) { - static const QStringList validCommands{QStringLiteral("me"), - QStringLiteral("react"), - QStringLiteral("join"), - QStringLiteral("knock"), - QStringLiteral("part"), - QStringLiteral("leave"), - QStringLiteral("invite"), - QStringLiteral("kick"), - QStringLiteral("ban"), - QStringLiteral("unban"), - QStringLiteral("redact"), - QStringLiteral("roomnick"), - QStringLiteral("shrug"), - QStringLiteral("fliptable"), - QStringLiteral("unfliptable"), - QStringLiteral("sovietflip"), - QStringLiteral("clear-timeline"), - QStringLiteral("reset-state"), - QStringLiteral("rotate-megolm-session"), - QStringLiteral("md"), - QStringLiteral("cmark"), - QStringLiteral("plain"), - QStringLiteral("rainbow"), - QStringLiteral("rainbowme"), - QStringLiteral("notice"), - QStringLiteral("rainbownotice"), - QStringLiteral("confetti"), - QStringLiteral("rainbowconfetti"), - QStringLiteral("goto"), - QStringLiteral("converttodm"), - QStringLiteral("converttoroom")}; - hasInvalidCommand = !validCommands.contains(commandName); - } else - hasInvalidCommand = false; - + static const QStringList validCommands{QStringLiteral("me"), + QStringLiteral("react"), + QStringLiteral("join"), + QStringLiteral("knock"), + QStringLiteral("part"), + QStringLiteral("leave"), + QStringLiteral("invite"), + QStringLiteral("kick"), + QStringLiteral("ban"), + QStringLiteral("unban"), + QStringLiteral("redact"), + QStringLiteral("roomnick"), + QStringLiteral("shrug"), + QStringLiteral("fliptable"), + QStringLiteral("unfliptable"), + QStringLiteral("sovietflip"), + QStringLiteral("clear-timeline"), + QStringLiteral("reset-state"), + QStringLiteral("rotate-megolm-session"), + QStringLiteral("md"), + QStringLiteral("cmark"), + QStringLiteral("plain"), + QStringLiteral("rainbow"), + QStringLiteral("rainbowme"), + QStringLiteral("notice"), + QStringLiteral("rainbownotice"), + QStringLiteral("confetti"), + QStringLiteral("rainbowconfetti"), + QStringLiteral("goto"), + QStringLiteral("converttodm"), + QStringLiteral("converttoroom")}; + bool hasInvalidCommand = !commandName.isNull() && '/' + commandName != text() && !validCommands.contains(commandName); + + bool signalsChanged{false}; if (containsInvalidCommand_ != hasInvalidCommand) { containsInvalidCommand_ = hasInvalidCommand; - emit containsInvalidCommandChanged(); + signalsChanged = true; } if (currentCommand_ != commandName) { currentCommand_ = commandName; + signalsChanged = true; + } + if (signalsChanged) { emit currentCommandChanged(); + emit containsInvalidCommandChanged(); } } @@ -390,10 +391,11 @@ InputBar::send() auto wasEdit = !room->edit().isEmpty(); - if (auto [commandName, args] = getCommandAndArgs(); commandName.isNull()) + if (auto [commandName, args] = getCommandAndArgs(); commandName.isEmpty()) message(text()); else - command(commandName, args); + if (!command(commandName, args)) + message(text()); if (!wasEdit) { history_.push_front(QLatin1String("")); @@ -758,16 +760,17 @@ InputBar::video(const QString &filename, QPair InputBar::getCommandAndArgs() const { - if (!text().startsWith('/')) - return {{}, text()}; + const auto currentText = text(); + if (!currentText.startsWith('/')) + return {{}, currentText}; - int command_end = text().indexOf(QRegularExpression(QStringLiteral("\\s"))); + int command_end = currentText.indexOf(QRegularExpression(QStringLiteral("\\s"))); if (command_end == -1) - command_end = text().size(); - auto name = text().mid(1, command_end - 1); - auto args = text().mid(command_end + 1); + command_end = currentText.size(); + auto name = currentText.mid(1, command_end - 1); + auto args = currentText.mid(command_end + 1); if (name.isEmpty() || name == QLatin1String("/")) { - return {{}, text()}; + return {{}, currentText}; } else { return {name, args}; } @@ -798,7 +801,7 @@ InputBar::sticker(CombinedImagePackModel *model, int row) room->sendMessageEvent(sticker, mtx::events::EventType::Sticker); } -void +bool InputBar::command(const QString &command, QString args) { if (command == QLatin1String("me")) { @@ -886,16 +889,16 @@ InputBar::command(const QString &command, QString args) // 1 - Going directly to a given event ID if (args[0] == '$') { room->showEvent(args); - return; + return true; } // 2 - Going directly to a given message index if (args[0] >= '0' && args[0] <= '9') { room->showEvent(args); - return; + return true; } // 3 - Matrix URI handler, as if you clicked the URI if (ChatPage::instance()->handleMatrixUri(args)) { - return; + return true; } nhlog::net()->error("Could not resolve goto: {}", args.toStdString()); } else if (command == QLatin1String("converttodm")) { @@ -904,8 +907,10 @@ InputBar::command(const QString &command, QString args) } else if (command == QLatin1String("converttoroom")) { utils::removeDirectFromRoom(this->room->roomId()); } else { - message("/" + command + " " + args); + return false; } + + return true; } MediaUpload::MediaUpload(std::unique_ptr source_, diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index 7385d272..94aedaf6 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -238,7 +238,7 @@ private: void emote(const QString &body, bool rainbowify); void notice(const QString &body, bool rainbowify); void confetti(const QString &body, bool rainbowify); - void command(const QString &name, QString args); + bool command(const QString &name, QString args); void image(const QString &filename, const std::optional &file, const QString &url, -- cgit 1.5.1 From 9616ee51b3618838a93444733759e5697c75b371 Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Wed, 1 Mar 2023 18:01:02 -0500 Subject: Use QSet instead of QStringList --- src/timeline/InputBar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 693fe789..b6c37fbc 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -253,7 +253,7 @@ InputBar::updateTextContentProperties(const QString &t) // check for invalid commands auto commandName = getCommandAndArgs().first; - static const QStringList validCommands{QStringLiteral("me"), + static const QSet validCommands{QStringLiteral("me"), QStringLiteral("react"), QStringLiteral("join"), QStringLiteral("knock"), -- cgit 1.5.1 From 2dc7492456b006b6c983ddd7357d29917d45843d Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Wed, 1 Mar 2023 18:04:36 -0500 Subject: make lint --- src/timeline/InputBar.cpp | 72 +++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index b6c37fbc..fb61ce0d 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -254,46 +254,47 @@ InputBar::updateTextContentProperties(const QString &t) // check for invalid commands auto commandName = getCommandAndArgs().first; static const QSet validCommands{QStringLiteral("me"), - QStringLiteral("react"), - QStringLiteral("join"), - QStringLiteral("knock"), - QStringLiteral("part"), - QStringLiteral("leave"), - QStringLiteral("invite"), - QStringLiteral("kick"), - QStringLiteral("ban"), - QStringLiteral("unban"), - QStringLiteral("redact"), - QStringLiteral("roomnick"), - QStringLiteral("shrug"), - QStringLiteral("fliptable"), - QStringLiteral("unfliptable"), - QStringLiteral("sovietflip"), - QStringLiteral("clear-timeline"), - QStringLiteral("reset-state"), - QStringLiteral("rotate-megolm-session"), - QStringLiteral("md"), - QStringLiteral("cmark"), - QStringLiteral("plain"), - QStringLiteral("rainbow"), - QStringLiteral("rainbowme"), - QStringLiteral("notice"), - QStringLiteral("rainbownotice"), - QStringLiteral("confetti"), - QStringLiteral("rainbowconfetti"), - QStringLiteral("goto"), - QStringLiteral("converttodm"), - QStringLiteral("converttoroom")}; - bool hasInvalidCommand = !commandName.isNull() && '/' + commandName != text() && !validCommands.contains(commandName); + QStringLiteral("react"), + QStringLiteral("join"), + QStringLiteral("knock"), + QStringLiteral("part"), + QStringLiteral("leave"), + QStringLiteral("invite"), + QStringLiteral("kick"), + QStringLiteral("ban"), + QStringLiteral("unban"), + QStringLiteral("redact"), + QStringLiteral("roomnick"), + QStringLiteral("shrug"), + QStringLiteral("fliptable"), + QStringLiteral("unfliptable"), + QStringLiteral("sovietflip"), + QStringLiteral("clear-timeline"), + QStringLiteral("reset-state"), + QStringLiteral("rotate-megolm-session"), + QStringLiteral("md"), + QStringLiteral("cmark"), + QStringLiteral("plain"), + QStringLiteral("rainbow"), + QStringLiteral("rainbowme"), + QStringLiteral("notice"), + QStringLiteral("rainbownotice"), + QStringLiteral("confetti"), + QStringLiteral("rainbowconfetti"), + QStringLiteral("goto"), + QStringLiteral("converttodm"), + QStringLiteral("converttoroom")}; + bool hasInvalidCommand = + !commandName.isNull() && '/' + commandName != text() && !validCommands.contains(commandName); bool signalsChanged{false}; if (containsInvalidCommand_ != hasInvalidCommand) { containsInvalidCommand_ = hasInvalidCommand; - signalsChanged = true; + signalsChanged = true; } if (currentCommand_ != commandName) { currentCommand_ = commandName; - signalsChanged = true; + signalsChanged = true; } if (signalsChanged) { emit currentCommandChanged(); @@ -393,9 +394,8 @@ InputBar::send() if (auto [commandName, args] = getCommandAndArgs(); commandName.isEmpty()) message(text()); - else - if (!command(commandName, args)) - message(text()); + else if (!command(commandName, args)) + message(text()); if (!wasEdit) { history_.push_front(QLatin1String("")); -- cgit 1.5.1 From b266185ce83c81f0c120a9083867817a354107c2 Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Tue, 7 Mar 2023 19:10:42 -0500 Subject: Handle incomplete commands better --- resources/qml/MessageInputWarning.qml | 5 +++-- resources/qml/TimelineView.qml | 8 +++++++- src/timeline/InputBar.cpp | 22 ++++++++++++++-------- src/timeline/InputBar.h | 14 ++++++++++---- 4 files changed, 34 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/resources/qml/MessageInputWarning.qml b/resources/qml/MessageInputWarning.qml index af65ebc1..9b0b0907 100644 --- a/resources/qml/MessageInputWarning.qml +++ b/resources/qml/MessageInputWarning.qml @@ -11,6 +11,7 @@ Rectangle { id: warningRoot required property string text + property color bubbleColor: Nheko.theme.error implicitHeight: visible ? warningDisplay.implicitHeight + 4 * Nheko.paddingSmall : 0 height: implicitHeight @@ -22,9 +23,9 @@ Rectangle { visible: warningRoot.visible // TODO: Qt.alpha() would make more sense but it wasn't working... - color: Qt.rgba(Nheko.theme.error.r, Nheko.theme.error.g, Nheko.theme.error.b, 0.3) + color: Qt.rgba(bubbleColor.r, bubbleColor.g, bubbleColor.b, 0.3) border.width: 1 - border.color: Nheko.theme.error + border.color: bubbleColor radius: 3 anchors.fill: parent anchors.margins: visible ? Nheko.paddingSmall : 0 diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index f0e71c60..abda16b9 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -160,7 +160,13 @@ Item { MessageInputWarning { text: qsTr("The command /%1 is not recognized and will be sent as part of your message").arg(room ? room.input.currentCommand : "") - visible: room ? room.input.containsInvalidCommand : false + visible: room ? room.input.containsInvalidCommand && !room.input.containsIncompleteCommand : false + } + + MessageInputWarning { + text: qsTr("/%1 looks like an incomplete command. To send it anyway, add a space to the end of your message.").arg(room ? room.input.currentCommand : "") + visible: room ? room.input.containsIncompleteCommand : false + bubbleColor: Nheko.theme.orange } ReplyPopup { diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index fb61ce0d..b27128e0 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -252,7 +252,7 @@ InputBar::updateTextContentProperties(const QString &t) } // check for invalid commands - auto commandName = getCommandAndArgs().first; + auto commandName = getCommandAndArgs(t).first; static const QSet validCommands{QStringLiteral("me"), QStringLiteral("react"), QStringLiteral("join"), @@ -284,14 +284,18 @@ InputBar::updateTextContentProperties(const QString &t) QStringLiteral("goto"), QStringLiteral("converttodm"), QStringLiteral("converttoroom")}; - bool hasInvalidCommand = - !commandName.isNull() && '/' + commandName != text() && !validCommands.contains(commandName); + bool hasInvalidCommand = !commandName.isNull() && !validCommands.contains(commandName); + bool hasIncompleteCommand = hasInvalidCommand && '/' + commandName == t; bool signalsChanged{false}; if (containsInvalidCommand_ != hasInvalidCommand) { containsInvalidCommand_ = hasInvalidCommand; signalsChanged = true; } + if (containsIncompleteCommand_ != hasIncompleteCommand) { + containsIncompleteCommand_ = hasIncompleteCommand; + signalsChanged = true; + } if (currentCommand_ != commandName) { currentCommand_ = commandName; signalsChanged = true; @@ -299,6 +303,7 @@ InputBar::updateTextContentProperties(const QString &t) if (signalsChanged) { emit currentCommandChanged(); emit containsInvalidCommandChanged(); + emit containsIncompleteCommandChanged(); } } @@ -392,9 +397,11 @@ InputBar::send() auto wasEdit = !room->edit().isEmpty(); - if (auto [commandName, args] = getCommandAndArgs(); commandName.isEmpty()) - message(text()); - else if (!command(commandName, args)) + auto [commandName, args] = getCommandAndArgs(); + updateTextContentProperties(text()); + if (containsIncompleteCommand_) + return; + if (commandName.isEmpty() || !command(commandName, args)) message(text()); if (!wasEdit) { @@ -758,9 +765,8 @@ InputBar::video(const QString &filename, } QPair -InputBar::getCommandAndArgs() const +InputBar::getCommandAndArgs(const QString ¤tText) const { - const auto currentText = text(); if (!currentText.startsWith('/')) return {{}, currentText}; diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index 94aedaf6..acafd964 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -175,6 +175,8 @@ class InputBar final : public QObject Q_PROPERTY(bool containsAtRoom READ containsAtRoom NOTIFY containsAtRoomChanged) Q_PROPERTY( bool containsInvalidCommand READ containsInvalidCommand NOTIFY containsInvalidCommandChanged) + Q_PROPERTY(bool containsIncompleteCommand READ containsIncompleteCommand NOTIFY + containsIncompleteCommandChanged) Q_PROPERTY(QString currentCommand READ currentCommand NOTIFY currentCommandChanged) Q_PROPERTY(QString text READ text NOTIFY textChanged) Q_PROPERTY(QVariantList uploads READ uploads NOTIFY uploadsChanged) @@ -202,6 +204,7 @@ public slots: [[nodiscard]] bool containsAtRoom() const { return containsAtRoom_; } bool containsInvalidCommand() const { return containsInvalidCommand_; } + bool containsIncompleteCommand() const { return containsIncompleteCommand_; } QString currentCommand() const { return currentCommand_; } void send(); @@ -231,6 +234,7 @@ signals: void uploadingChanged(bool value); void containsAtRoomChanged(); void containsInvalidCommandChanged(); + void containsIncompleteCommandChanged(); void currentCommandChanged(); void uploadsChanged(); @@ -274,7 +278,8 @@ private: const QSize &thumbnailDimensions, const QString &blurhash); - QPair getCommandAndArgs() const; + QPair getCommandAndArgs() const { return getCommandAndArgs(text()); } + QPair getCommandAndArgs(const QString ¤tText) const; mtx::common::Relations generateRelations() const; void startUploadFromPath(const QString &path); @@ -296,9 +301,10 @@ private: std::deque history_; std::size_t history_index_ = 0; int selectionStart = 0, selectionEnd = 0, cursorPosition = 0; - bool uploading_ = false; - bool containsAtRoom_ = false; - bool containsInvalidCommand_ = false; + bool uploading_ = false; + bool containsAtRoom_ = false; + bool containsInvalidCommand_ = false; + bool containsIncompleteCommand_ = false; QString currentCommand_; using UploadHandle = std::unique_ptr; -- cgit 1.5.1