mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 23:53:58 +02:00
Added ability to select message for reply with Ctrl+Up/Down in sections.
This commit is contained in:
parent
0b98cfbfec
commit
f1236edf5b
6 changed files with 122 additions and 0 deletions
|
@ -40,4 +40,13 @@ struct SetHistoryArgs {
|
|||
rpl::producer<std::optional<QString>> writeRestriction;
|
||||
};
|
||||
|
||||
struct ReplyNextRequest {
|
||||
enum class Direction {
|
||||
Next,
|
||||
Previous,
|
||||
};
|
||||
const FullMsgId replyId;
|
||||
const Direction direction;
|
||||
};
|
||||
|
||||
} // namespace HistoryView::Controls
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/controls/history_view_compose_controls.h"
|
||||
|
||||
#include "base/event_filter.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/qt_signal_producer.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
|
@ -64,6 +65,11 @@ constexpr auto kMouseEvents = {
|
|||
QEvent::MouseButtonRelease
|
||||
};
|
||||
|
||||
constexpr auto kCommonModifiers = 0
|
||||
| Qt::ShiftModifier
|
||||
| Qt::MetaModifier
|
||||
| Qt::ControlModifier;
|
||||
|
||||
using FileChosen = ComposeControls::FileChosen;
|
||||
using PhotoChosen = ComposeControls::PhotoChosen;
|
||||
using MessageToEdit = ComposeControls::MessageToEdit;
|
||||
|
@ -722,6 +728,11 @@ auto ComposeControls::editLastMessageRequests() const
|
|||
return _editLastMessageRequests.events();
|
||||
}
|
||||
|
||||
auto ComposeControls::replyNextRequests() const
|
||||
-> rpl::producer<ReplyNextRequest> {
|
||||
return _replyNextRequests.events();
|
||||
}
|
||||
|
||||
auto ComposeControls::sendContentRequests(SendRequestType requestType) const {
|
||||
auto filter = rpl::filter([=] {
|
||||
const auto type = (_mode == Mode::Normal)
|
||||
|
@ -1077,6 +1088,37 @@ void ComposeControls::initKeyHandler() {
|
|||
_scrollKeyEvents.fire(std::move(keyEvent));
|
||||
}
|
||||
}, _wrap->lifetime());
|
||||
|
||||
base::install_event_filter(_wrap.get(), _field, [=](not_null<QEvent*> e) {
|
||||
using Result = base::EventFilterResult;
|
||||
if (e->type() != QEvent::KeyPress) {
|
||||
return Result::Continue;
|
||||
}
|
||||
const auto k = static_cast<QKeyEvent*>(e.get());
|
||||
|
||||
if ((k->modifiers() & kCommonModifiers) == Qt::ControlModifier) {
|
||||
const auto isUp = (k->key() == Qt::Key_Up);
|
||||
const auto isDown = (k->key() == Qt::Key_Down);
|
||||
if (isUp || isDown) {
|
||||
if (Platform::IsMac()) {
|
||||
// Cmd + Up is used instead of Home.
|
||||
if ((isUp && (!_field->textCursor().atStart()))
|
||||
// Cmd + Down is used instead of End.
|
||||
|| (isDown && (!_field->textCursor().atEnd()))) {
|
||||
return Result::Continue;
|
||||
}
|
||||
}
|
||||
_replyNextRequests.fire({
|
||||
.replyId = replyingToMessage(),
|
||||
.direction = (isDown
|
||||
? ReplyNextRequest::Direction::Next
|
||||
: ReplyNextRequest::Direction::Previous)
|
||||
});
|
||||
return Result::Cancel;
|
||||
}
|
||||
}
|
||||
return Result::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
void ComposeControls::initField() {
|
||||
|
|
|
@ -82,6 +82,7 @@ public:
|
|||
using VoiceToSend = Controls::VoiceToSend;
|
||||
using SendActionUpdate = Controls::SendActionUpdate;
|
||||
using SetHistoryArgs = Controls::SetHistoryArgs;
|
||||
using ReplyNextRequest = Controls::ReplyNextRequest;
|
||||
using FieldHistoryAction = Ui::InputField::HistoryAction;
|
||||
|
||||
enum class Mode {
|
||||
|
@ -125,6 +126,8 @@ public:
|
|||
-> rpl::producer<not_null<QKeyEvent*>>;
|
||||
[[nodiscard]] auto editLastMessageRequests() const
|
||||
-> rpl::producer<not_null<QKeyEvent*>>;
|
||||
[[nodiscard]] auto replyNextRequests() const
|
||||
-> rpl::producer<ReplyNextRequest>;
|
||||
|
||||
using MimeDataHook = Fn<bool(
|
||||
not_null<const QMimeData*> data,
|
||||
|
@ -297,6 +300,7 @@ private:
|
|||
rpl::event_stream<not_null<QKeyEvent*>> _scrollKeyEvents;
|
||||
rpl::event_stream<not_null<QKeyEvent*>> _editLastMessageRequests;
|
||||
rpl::event_stream<> _attachRequests;
|
||||
rpl::event_stream<ReplyNextRequest> _replyNextRequests;
|
||||
|
||||
TextUpdateEvents _textUpdateEvents = TextUpdateEvents()
|
||||
| TextUpdateEvent::SaveDraft
|
||||
|
|
|
@ -525,6 +525,11 @@ void ListWidget::updateHighlightedMessage() {
|
|||
_highlightedMessageId = FullMsgId();
|
||||
}
|
||||
|
||||
void ListWidget::clearHighlightedMessage() {
|
||||
_highlightedMessageId = FullMsgId();
|
||||
updateHighlightedMessage();
|
||||
}
|
||||
|
||||
void ListWidget::checkUnreadBarCreation() {
|
||||
if (!_bar.element) {
|
||||
if (auto data = _delegate->listMessagesBar(_items); data.bar.element) {
|
||||
|
@ -2759,6 +2764,49 @@ rpl::producer<FullMsgId> ListWidget::readMessageRequested() const {
|
|||
return _requestedToReadMessage.events();
|
||||
}
|
||||
|
||||
rpl::producer<FullMsgId> ListWidget::showMessageRequested() const {
|
||||
return _requestedToShowMessage.events();
|
||||
}
|
||||
|
||||
void ListWidget::replyNextMessage(FullMsgId fullId, bool next) {
|
||||
const auto reply = [&](Element *view) {
|
||||
if (view) {
|
||||
const auto newFullId = view->data()->fullId();
|
||||
replyToMessageRequestNotify(newFullId);
|
||||
_requestedToShowMessage.fire_copy(newFullId);
|
||||
} else {
|
||||
replyToMessageRequestNotify(FullMsgId());
|
||||
clearHighlightedMessage();
|
||||
}
|
||||
};
|
||||
const auto replyFirst = [&] {
|
||||
reply(next ? nullptr : _items.back().get());
|
||||
};
|
||||
if (!fullId) {
|
||||
replyFirst();
|
||||
return;
|
||||
}
|
||||
|
||||
auto proj = [&](not_null<Element*> view) {
|
||||
return view->data()->fullId() == fullId;
|
||||
};
|
||||
const auto &list = ranges::view::reverse(_items);
|
||||
const auto it = ranges::find_if(list, std::move(proj));
|
||||
if (it == end(list)) {
|
||||
replyFirst();
|
||||
return;
|
||||
} else {
|
||||
const auto nextIt = it + (next ? -1 : 1);
|
||||
if (nextIt == end(list)) {
|
||||
return;
|
||||
} else if (next && (it == begin(list))) {
|
||||
reply(nullptr);
|
||||
} else {
|
||||
reply(nextIt->get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListWidget::~ListWidget() = default;
|
||||
|
||||
void ConfirmDeleteSelectedItems(not_null<ListWidget*> widget) {
|
||||
|
|
|
@ -211,6 +211,8 @@ public:
|
|||
[[nodiscard]] rpl::producer<FullMsgId> replyToMessageRequested() const;
|
||||
void replyToMessageRequestNotify(FullMsgId item);
|
||||
[[nodiscard]] rpl::producer<FullMsgId> readMessageRequested() const;
|
||||
[[nodiscard]] rpl::producer<FullMsgId> showMessageRequested() const;
|
||||
void replyNextMessage(FullMsgId fullId, bool next = true);
|
||||
|
||||
// ElementDelegate interface.
|
||||
Context elementContext() override;
|
||||
|
@ -448,6 +450,7 @@ private:
|
|||
void scrollToAnimationCallback(FullMsgId attachToId, int relativeTo);
|
||||
|
||||
void updateHighlightedMessage();
|
||||
void clearHighlightedMessage();
|
||||
|
||||
// This function finds all history items that are displayed and calls template method
|
||||
// for each found message (in given direction) in the passed history with passed top offset.
|
||||
|
@ -555,6 +558,7 @@ private:
|
|||
rpl::event_stream<FullMsgId> _requestedToEditMessage;
|
||||
rpl::event_stream<FullMsgId> _requestedToReplyToMessage;
|
||||
rpl::event_stream<FullMsgId> _requestedToReadMessage;
|
||||
rpl::event_stream<FullMsgId> _requestedToShowMessage;
|
||||
|
||||
rpl::lifetime _viewerLifetime;
|
||||
|
||||
|
|
|
@ -221,6 +221,13 @@ RepliesWidget::RepliesWidget(
|
|||
replyToMessage(fullId);
|
||||
}, _inner->lifetime());
|
||||
|
||||
_inner->showMessageRequested(
|
||||
) | rpl::start_with_next([=](auto fullId) {
|
||||
if (const auto item = session().data().message(fullId)) {
|
||||
showAtPosition(item->position());
|
||||
}
|
||||
}, _inner->lifetime());
|
||||
|
||||
_composeControls->sendActionUpdates(
|
||||
) | rpl::start_with_next([=](ComposeControls::SendActionUpdate &&data) {
|
||||
session().sendProgressManager().update(
|
||||
|
@ -500,6 +507,14 @@ void RepliesWidget::setupComposeControls() {
|
|||
}
|
||||
}, lifetime());
|
||||
|
||||
_composeControls->replyNextRequests(
|
||||
) | rpl::start_with_next([=](ComposeControls::ReplyNextRequest &&data) {
|
||||
using Direction = ComposeControls::ReplyNextRequest::Direction;
|
||||
_inner->replyNextMessage(
|
||||
data.replyId,
|
||||
data.direction == Direction::Next);
|
||||
}, lifetime());
|
||||
|
||||
_composeControls->setMimeDataHook([=](
|
||||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action) {
|
||||
|
|
Loading…
Add table
Reference in a new issue