diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index 08cbd15b..b1580f97 100644
--- a/src/timeline/InputBar.cpp
+++ b/src/timeline/InputBar.cpp
@@ -19,6 +19,7 @@
#include "MainWindow.h"
#include "MatrixClient.h"
#include "Olm.h"
+#include "RoomsModel.h"
#include "TimelineModel.h"
#include "TimelineViewManager.h"
#include "UserSettingsPage.h"
@@ -122,6 +123,20 @@ InputBar::insertMimeData(const QMimeData *md)
}
void
+InputBar::setText(QString newText)
+{
+ if (history_.empty())
+ history_.push_front(newText);
+ else
+ history_.front() = newText;
+ history_index_ = 0;
+
+ if (history_.size() == INPUT_HISTORY_SIZE)
+ history_.pop_back();
+
+ emit textChanged(newText);
+}
+void
InputBar::updateState(int selectionStart_, int selectionEnd_, int cursorPosition_, QString text_)
{
if (text_.isEmpty())
@@ -186,6 +201,11 @@ InputBar::completerFor(QString completerName)
auto proxy = new CompletionProxyModel(emojiModel);
emojiModel->setParent(proxy);
return proxy;
+ } else if (completerName == "room") {
+ auto roomModel = new RoomsModel(true);
+ auto proxy = new CompletionProxyModel(roomModel);
+ roomModel->setParent(proxy);
+ return proxy;
}
return nullptr;
}
@@ -196,6 +216,10 @@ InputBar::send()
if (text().trimmed().isEmpty())
return;
+ nhlog::ui()->debug("Send: {}", text().toStdString());
+
+ auto wasEdit = !room->edit().isEmpty();
+
if (text().startsWith('/')) {
int command_end = text().indexOf(' ');
if (command_end == -1)
@@ -211,12 +235,10 @@ InputBar::send()
message(text());
}
- nhlog::ui()->debug("Send: {}", text().toStdString());
-
- if (history_.size() == INPUT_HISTORY_SIZE)
- history_.pop_back();
- history_.push_front("");
- history_index_ = 0;
+ if (!wasEdit) {
+ history_.push_front("");
+ setText("");
+ }
}
void
@@ -272,12 +294,10 @@ InputBar::message(QString msg, MarkdownOverride useMarkdown)
if (!room->reply().isEmpty()) {
text.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
text.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
} else if (!room->reply().isEmpty()) {
auto related = room->relatedInfo(room->reply());
@@ -307,7 +327,6 @@ InputBar::message(QString msg, MarkdownOverride useMarkdown)
text.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, related.related_event});
- room->resetReply();
}
room->sendMessageEvent(text, mtx::events::EventType::RoomMessage);
@@ -330,12 +349,10 @@ InputBar::emote(QString msg)
if (!room->reply().isEmpty()) {
emote.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
if (!room->edit().isEmpty()) {
emote.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
}
room->sendMessageEvent(emote, mtx::events::EventType::RoomMessage);
@@ -366,12 +383,10 @@ InputBar::image(const QString &filename,
if (!room->reply().isEmpty()) {
image.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
if (!room->edit().isEmpty()) {
image.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
}
room->sendMessageEvent(image, mtx::events::EventType::RoomMessage);
@@ -397,12 +412,10 @@ InputBar::file(const QString &filename,
if (!room->reply().isEmpty()) {
file.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
if (!room->edit().isEmpty()) {
file.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
}
room->sendMessageEvent(file, mtx::events::EventType::RoomMessage);
@@ -429,12 +442,10 @@ InputBar::audio(const QString &filename,
if (!room->reply().isEmpty()) {
audio.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
if (!room->edit().isEmpty()) {
audio.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
}
room->sendMessageEvent(audio, mtx::events::EventType::RoomMessage);
@@ -460,12 +471,10 @@ InputBar::video(const QString &filename,
if (!room->reply().isEmpty()) {
video.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
if (!room->edit().isEmpty()) {
video.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
}
room->sendMessageEvent(video, mtx::events::EventType::RoomMessage);
diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h
index 696a0dd9..4cb6da7b 100644
--- a/src/timeline/InputBar.h
+++ b/src/timeline/InputBar.h
@@ -41,7 +41,7 @@ public slots:
QString text() const;
QString previousText();
QString nextText();
- void setText(QString newText) { emit textChanged(newText); }
+ void setText(QString newText);
void send();
void paste(bool fromMouse);
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 5c904932..d46a313a 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -362,6 +362,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
const static QRegularExpression replyFallback(
"<mx-reply>.*</mx-reply>", QRegularExpression::DotMatchesEverythingOption);
+ auto ascent = QFontMetrics(UserSettings::instance()->font()).ascent();
+
bool isReply = relations(event).reply_to().has_value();
auto formattedBody_ = QString::fromStdString(formatted_body(event));
@@ -380,8 +382,14 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
formattedBody_ = formattedBody_.remove(replyFallback);
}
- formattedBody_.replace("<img src=\"mxc://", "<img src=\"image://mxcImage/");
- formattedBody_.replace("<img src=\"mxc://", "<img src=\"image://mxcImage/");
+ // TODO(Nico): Don't parse html with a regex
+ const static QRegularExpression matchImgUri(
+ "(<img [^>]*)src=\"mxc://([^\"]*)\"([^>]*>)");
+ formattedBody_.replace(matchImgUri, "\\1 src=\"image://mxcImage/\\2\"\\3");
+ const static QRegularExpression matchEmoticonHeight(
+ "(<img data-mx-emoticon [^>]*)height=\"([^\"]*)\"([^>]*>)");
+ formattedBody_.replace(matchEmoticonHeight,
+ QString("\\1 height=\"%1\"\\3").arg(ascent));
return QVariant(utils::replaceEmoji(
utils::linkifyMessage(utils::escapeBlacklistedHtml(formattedBody_))));
@@ -491,6 +499,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
data(event, static_cast<int>(ProportionalHeight)));
m.insert(names[Id], data(event, static_cast<int>(Id)));
m.insert(names[State], data(event, static_cast<int>(State)));
+ m.insert(names[IsEdited], data(event, static_cast<int>(IsEdited)));
+ m.insert(names[IsEditable], data(event, static_cast<int>(IsEditable)));
m.insert(names[IsEncrypted], data(event, static_cast<int>(IsEncrypted)));
m.insert(names[IsRoomEncrypted], data(event, static_cast<int>(IsRoomEncrypted)));
m.insert(names[ReplyTo], data(event, static_cast<int>(ReplyTo)));
@@ -753,11 +763,6 @@ TimelineModel::setCurrentIndex(int index)
(!oldReadIndex || *oldReadIndex < nextEventIndexAndId->first)) {
readEvent(nextEventIndexAndId->second);
currentReadId = QString::fromStdString(nextEventIndexAndId->second);
-
- nhlog::net()->info("Marked as read {}, index {}, oldReadIndex {}",
- nextEventIndexAndId->second,
- nextEventIndexAndId->first,
- *oldReadIndex);
}
}
}
@@ -834,6 +839,14 @@ TimelineModel::openUserProfile(QString userid, bool global)
}
void
+TimelineModel::openRoomSettings()
+{
+ RoomSettings *settings = new RoomSettings(roomId(), this);
+ connect(this, &TimelineModel::roomAvatarUrlChanged, settings, &RoomSettings::avatarChanged);
+ openRoomSettingsDialog(settings);
+}
+
+void
TimelineModel::replyAction(QString id)
{
setReply(id);
@@ -1539,6 +1552,17 @@ TimelineModel::setEdit(QString newEdit)
if (edit_.startsWith('m'))
return;
+ if (newEdit.isEmpty()) {
+ resetEdit();
+ return;
+ }
+
+ if (edit_.isEmpty()) {
+ this->textBeforeEdit = input()->text();
+ this->replyBeforeEdit = reply_;
+ nhlog::ui()->debug("Stored: {}", textBeforeEdit.toStdString());
+ }
+
if (edit_ != newEdit) {
auto ev = events.get(newEdit.toStdString(), "");
if (ev && mtx::accessors::sender(*ev) == http::client()->user_id().to_string()) {
@@ -1573,8 +1597,14 @@ TimelineModel::resetEdit()
if (!edit_.isEmpty()) {
edit_ = "";
emit editChanged(edit_);
- input()->setText("");
- resetReply();
+ nhlog::ui()->debug("Restoring: {}", textBeforeEdit.toStdString());
+ input()->setText(textBeforeEdit);
+ textBeforeEdit.clear();
+ if (replyBeforeEdit.isEmpty())
+ resetReply();
+ else
+ setReply(replyBeforeEdit);
+ replyBeforeEdit.clear();
}
}
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 83012cd8..e02539bb 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -11,6 +11,7 @@
#include "CacheCryptoStructs.h"
#include "EventStore.h"
#include "InputBar.h"
+#include "ui/RoomSettings.h"
#include "ui/UserProfile.h"
namespace mtx::http {
@@ -216,6 +217,7 @@ public:
Q_INVOKABLE void viewRawMessage(QString id) const;
Q_INVOKABLE void viewDecryptedRawMessage(QString id) const;
Q_INVOKABLE void openUserProfile(QString userid, bool global = false);
+ Q_INVOKABLE void openRoomSettings();
Q_INVOKABLE void editAction(QString id);
Q_INVOKABLE void replyAction(QString id);
Q_INVOKABLE void readReceiptsAction(QString id) const;
@@ -307,6 +309,7 @@ signals:
void newCallEvent(const mtx::events::collections::TimelineEvents &event);
void openProfile(UserProfile *profile);
+ void openRoomSettingsDialog(RoomSettings *settings);
void newMessageToSend(mtx::events::collections::TimelineEvents event);
void addPendingMessageToStore(mtx::events::collections::TimelineEvents event);
@@ -334,6 +337,7 @@ private:
QString currentId, currentReadId;
QString reply_, edit_;
+ QString textBeforeEdit, replyBeforeEdit;
std::vector<QString> typingUsers_;
TimelineViewManager *manager_;
@@ -351,4 +355,6 @@ TimelineModel::sendMessageEvent(const T &content, mtx::events::EventType eventTy
msgCopy.content = content;
msgCopy.type = eventType;
emit newMessageToSend(msgCopy);
+ resetReply();
+ resetEdit();
}
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index b7d2bfb1..f2e6d571 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -128,6 +128,12 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
0,
"UserProfileModel",
"UserProfile needs to be instantiated on the C++ side");
+ qmlRegisterUncreatableType<RoomSettings>(
+ "im.nheko",
+ 1,
+ 0,
+ "RoomSettingsModel",
+ "Room Settings needs to be instantiated on the C++ side");
static auto self = this;
qmlRegisterSingletonType<MainWindow>(
@@ -387,11 +393,6 @@ TimelineViewManager::openLeaveRoomDialog() const
{
MainWindow::instance()->openLeaveRoomDialog(timeline_->roomId());
}
-void
-TimelineViewManager::openRoomSettings() const
-{
- MainWindow::instance()->openRoomSettings(timeline_->roomId());
-}
void
TimelineViewManager::verifyUser(QString userid)
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 7c994a14..61fce574 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -70,7 +70,6 @@ public:
Q_INVOKABLE void openInviteUsersDialog();
Q_INVOKABLE void openMemberListDialog() const;
Q_INVOKABLE void openLeaveRoomDialog() const;
- Q_INVOKABLE void openRoomSettings() const;
Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow);
void verifyUser(QString userid);
|