Support replying to a different chat.

This commit is contained in:
John Preston 2023-10-10 14:00:04 +04:00
parent 4240568ea5
commit 394883b986
5 changed files with 173 additions and 18 deletions

View file

@ -325,7 +325,7 @@ bool HistoryMessageReply::updateData(
bool force) { bool force) {
const auto guard = gsl::finally([&] { refreshReplyToMedia(); }); const auto guard = gsl::finally([&] { refreshReplyToMedia(); });
if (!force) { if (!force) {
if (resolvedMessage || resolvedStory || _deleted) { if (resolvedMessage || resolvedStory || _unavailable) {
return true; return true;
} }
} }
@ -365,7 +365,9 @@ bool HistoryMessageReply::updateData(
const auto external = _fields.externalSenderId const auto external = _fields.externalSenderId
|| !_fields.externalSenderName.isEmpty(); || !_fields.externalSenderName.isEmpty();
if (resolvedMessage || resolvedStory || (external && force)) { if (resolvedMessage
|| resolvedStory
|| (external && (!_fields.messageId || force))) {
const auto repaint = [=] { holder->customEmojiRepaint(); }; const auto repaint = [=] { holder->customEmojiRepaint(); };
const auto context = Core::MarkedTextContext{ const auto context = Core::MarkedTextContext{
.session = &holder->history()->session(), .session = &holder->history()->session(),
@ -403,8 +405,8 @@ bool HistoryMessageReply::updateData(
&& resolvedMessage->from()->isUser()) && resolvedMessage->from()->isUser())
? resolvedMessage->from()->id ? resolvedMessage->from()->id
: PeerId(); : PeerId();
} else { } else if (!resolvedStory) {
resolvedMessage = 0; _unavailable = true;
} }
const auto media = resolvedMessage const auto media = resolvedMessage
@ -417,7 +419,7 @@ bool HistoryMessageReply::updateData(
} }
} else if (force) { } else if (force) {
if (_fields.messageId || _fields.storyId) { if (_fields.messageId || _fields.storyId) {
_deleted = true; _unavailable = true;
} }
_colorKey = 0; _colorKey = 0;
spoiler = nullptr; spoiler = nullptr;
@ -428,7 +430,7 @@ bool HistoryMessageReply::updateData(
return resolvedMessage return resolvedMessage
|| resolvedStory || resolvedStory
|| (external && !_fields.messageId) || (external && !_fields.messageId)
|| _deleted; || _unavailable;
} }
void HistoryMessageReply::set(ReplyFields fields) { void HistoryMessageReply::set(ReplyFields fields) {
@ -500,7 +502,7 @@ void HistoryMessageReply::clearData(not_null<HistoryItem*> holder) {
resolvedStory.get()); resolvedStory.get());
resolvedStory = nullptr; resolvedStory = nullptr;
} }
_deleted = true; _unavailable = true;
refreshReplyToMedia(); refreshReplyToMedia();
} }
@ -693,7 +695,7 @@ void HistoryMessageReply::paint(
const auto pausedSpoiler = context.paused const auto pausedSpoiler = context.paused
|| On(PowerSaving::kChatSpoiler); || On(PowerSaving::kChatSpoiler);
if (w > st::msgReplyBarSkip) { if (w > st::msgReplyBarSkip) {
if (resolvedMessage || resolvedStory) { if (resolvedMessage || resolvedStory || !_text.isEmpty()) {
const auto media = resolvedMessage ? resolvedMessage->media() : nullptr; const auto media = resolvedMessage ? resolvedMessage->media() : nullptr;
auto hasPreview = (media && media->hasReplyPreview()) auto hasPreview = (media && media->hasReplyPreview())
|| (resolvedStory && resolvedStory->hasReplyPreview()); || (resolvedStory && resolvedStory->hasReplyPreview());
@ -791,7 +793,7 @@ void HistoryMessageReply::unloadPersistentAnimation() {
} }
QString HistoryMessageReply::statePhrase() const { QString HistoryMessageReply::statePhrase() const {
return ((_fields.messageId || _fields.storyId) && !_deleted) return ((_fields.messageId || _fields.storyId) && !_unavailable)
? tr::lng_profile_loading(tr::now) ? tr::lng_profile_loading(tr::now)
: _fields.storyId : _fields.storyId
? tr::lng_deleted_story(tr::now) ? tr::lng_deleted_story(tr::now)

View file

@ -344,7 +344,7 @@ private:
mutable PeerData *_externalSender = nullptr; mutable PeerData *_externalSender = nullptr;
mutable int _maxWidth = 0; mutable int _maxWidth = 0;
mutable int _nameVersion = 0; mutable int _nameVersion = 0;
bool _deleted = false; bool _unavailable = false;
}; };

View file

@ -1656,7 +1656,9 @@ void HistoryWidget::saveDraft(bool delayed) {
} }
void HistoryWidget::saveFieldToHistoryLocalDraft() { void HistoryWidget::saveFieldToHistoryLocalDraft() {
if (!_history) return; if (!_history) {
return;
}
const auto topicRootId = MsgId(); const auto topicRootId = MsgId();
if (_editMsgId) { if (_editMsgId) {
@ -6219,13 +6221,16 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
} else { } else {
_forwardPanel->editOptions(controller()->uiShow()); _forwardPanel->editOptions(controller()->uiShow());
} }
} else if (replyTo() && replyTo().messageId.peer != _peer->id) { } else if (const auto reply = replyTo()) {
// edit options HistoryView::Controls::EditReplyOptions(
} else { controller(),
reply,
_history);
} else if (_editMsgId) {
controller()->showPeerHistory( controller()->showPeerHistory(
_peer, _peer,
Window::SectionShow::Way::Forward, Window::SectionShow::Way::Forward,
_editMsgId ? _editMsgId : replyTo().messageId.msg); _editMsgId);
} }
} }
} }
@ -7096,6 +7101,7 @@ void HistoryWidget::processReply() {
_processingReplyTo.messageId.msg, _processingReplyTo.messageId.msg,
processContinue()); processContinue());
return; return;
#if 0 // Now we can "reply" to old legacy group messages.
} else if (_processingReplyItem->history() == _migrated) { } else if (_processingReplyItem->history() == _migrated) {
if (_processingReplyItem->isService()) { if (_processingReplyItem->isService()) {
controller()->showToast(tr::lng_reply_cant(tr::now)); controller()->showToast(tr::lng_reply_cant(tr::now));
@ -7113,10 +7119,11 @@ void HistoryWidget::processReply() {
})); }));
} }
return processCancel(); return processCancel();
} else if (_processingReplyItem->history() != _history #endif
|| !_processingReplyItem->isRegular()) { } else if (!_processingReplyItem->isRegular()) {
return processCancel(); return processCancel();
} else if (const auto forum = _peer->forum()) { } else if (const auto forum = _peer->forum()
; forum && _processingReplyItem->history() == _history) {
const auto topicRootId = _processingReplyItem->topicRootId(); const auto topicRootId = _processingReplyItem->topicRootId();
if (forum->topicDeleted(topicRootId)) { if (forum->topicDeleted(topicRootId)) {
return processCancel(); return processCancel();

View file

@ -29,6 +29,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_chat.h" #include "styles/style_chat.h"
#include "styles/style_chat_helpers.h" #include "styles/style_chat_helpers.h"
#include "apiwrap.h"
#include "boxes/peer_list_controllers.h"
#include "data/data_changes.h"
#include "settings/settings_common.h"
#include "ui/widgets/buttons.h"
#include "styles/style_menu_icons.h"
#include "styles/style_settings.h"
namespace HistoryView::Controls { namespace HistoryView::Controls {
namespace { namespace {
@ -395,4 +403,137 @@ void ForwardPanel::paint(
}); });
} }
void ShowReplyToChatBox(
not_null<Window::SessionController*> window,
FullReplyTo reply,
base::weak_ptr<Data::Thread> oldThread) {
class Controller final : public ChooseRecipientBoxController {
public:
using Chosen = not_null<Data::Thread*>;
Controller(not_null<Main::Session*> session)
: ChooseRecipientBoxController(
session,
[=](Chosen thread) mutable { _singleChosen.fire_copy(thread); },
nullptr) {
}
void rowClicked(not_null<PeerListRow*> row) override final {
ChooseRecipientBoxController::rowClicked(row);
}
[[nodiscard]] rpl::producer<Chosen> singleChosen() const{
return _singleChosen.events();
}
private:
rpl::event_stream<Chosen> _singleChosen;
};
struct State {
not_null<PeerListBox*> box;
not_null<Controller*> controller;
base::unique_qptr<Ui::PopupMenu> menu;
};
const auto session = &window->session();
const auto state = [&] {
auto controller = std::make_unique<Controller>(session);
const auto controllerRaw = controller.get();
auto box = Box<PeerListBox>(std::move(controller), nullptr);
const auto boxRaw = box.data();
window->uiShow()->show(std::move(box));
auto state = State{ boxRaw, controllerRaw };
return boxRaw->lifetime().make_state<State>(std::move(state));
}();
auto chosen = [=](not_null<Data::Thread*> thread) mutable {
const auto history = thread->owningHistory();
const auto topicRootId = thread->topicRootId();
const auto draft = history->localDraft(topicRootId);
const auto textWithTags = draft
? draft->textWithTags
: TextWithTags();
const auto cursor = draft ? draft->cursor : MessageCursor();
reply.topicRootId = topicRootId;
history->setLocalDraft(std::make_unique<Data::Draft>(
textWithTags,
reply,
cursor,
Data::PreviewState::Allowed));
history->clearLocalEditDraft(topicRootId);
history->session().changes().entryUpdated(
thread,
Data::EntryUpdate::Flag::LocalDraftSet);
// Clear old one.
crl::on_main(oldThread, [=] {
const auto old = oldThread.get();
const auto history = old->owningHistory();
const auto topicRootId = old->topicRootId();
if (const auto local = history->localDraft(topicRootId)) {
if (local->reply.messageId == reply.messageId) {
auto draft = *local;
draft.reply = { .topicRootId = topicRootId };
if (Data::DraftIsNull(&draft)) {
history->clearLocalDraft(topicRootId);
} else {
history->setLocalDraft(
std::make_unique<Data::Draft>(
std::move(draft)));
}
old->session().api().saveDraftToCloudDelayed(old);
}
}
});
return true;
};
auto callback = [=, chosen = std::move(chosen)](
Controller::Chosen thread) mutable {
const auto weak = Ui::MakeWeak(state->box);
if (!chosen(thread)) {
return;
} else if (const auto strong = weak.data()) {
strong->closeBox();
}
};
state->controller->singleChosen(
) | rpl::start_with_next(std::move(callback), state->box->lifetime());
}
void EditReplyOptions(
not_null<Window::SessionController*> controller,
FullReplyTo reply,
not_null<Data::Thread*> thread) {
const auto weak = base::make_weak(thread);
controller->uiShow()->show(Box([=](not_null<Ui::GenericBox*> box) {
box->setTitle(rpl::single(u"Reply to Message"_q));
Settings::AddButton(
box->verticalLayout(),
rpl::single(u"Reply in another chat"_q),
st::settingsButton,
{ &st::menuIconReply }
)->setClickedCallback([=] {
ShowReplyToChatBox(controller, reply, weak);
});
Settings::AddButton(
box->verticalLayout(),
rpl::single(u"Show message"_q),
st::settingsButton,
{ &st::menuIconShowInChat }
)->setClickedCallback([=] {
controller->showPeerHistory(
reply.messageId.peer,
Window::SectionShow::Way::Forward,
reply.messageId.msg);
});
box->addButton(tr::lng_box_ok(), [=] {
box->closeBox();
});
}));
}
} // namespace HistoryView::Controls } // namespace HistoryView::Controls

View file

@ -71,4 +71,9 @@ private:
}; };
void EditReplyOptions(
not_null<Window::SessionController*> controller,
FullReplyTo reply,
not_null<Data::Thread*> thread);
} // namespace HistoryView::Controls } // namespace HistoryView::Controls