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

View file

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

View file

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