Update API scheme, rich preview drafts.

This commit is contained in:
John Preston 2023-10-19 18:20:27 +04:00
parent b2e8e0431e
commit b1823d981b
21 changed files with 268 additions and 174 deletions

View File

@ -2135,8 +2135,10 @@ void ApiWrap::saveDraftsToCloud() {
auto flags = MTPmessages_SaveDraft::Flags(0); auto flags = MTPmessages_SaveDraft::Flags(0);
auto &textWithTags = cloudDraft->textWithTags; auto &textWithTags = cloudDraft->textWithTags;
if (cloudDraft->previewState != Data::PreviewState::Allowed) { if (cloudDraft->webpage.removed) {
flags |= MTPmessages_SaveDraft::Flag::f_no_webpage; flags |= MTPmessages_SaveDraft::Flag::f_no_webpage;
} else if (!cloudDraft->webpage.url.isEmpty()) {
flags |= MTPmessages_SaveDraft::Flag::f_media;
} }
if (cloudDraft->reply.messageId || cloudDraft->reply.topicRootId) { if (cloudDraft->reply.messageId || cloudDraft->reply.topicRootId) {
flags |= MTPmessages_SaveDraft::Flag::f_reply_to; flags |= MTPmessages_SaveDraft::Flag::f_reply_to;
@ -2149,6 +2151,7 @@ void ApiWrap::saveDraftsToCloud() {
TextUtilities::ConvertTextTagsToEntities(textWithTags.tags), TextUtilities::ConvertTextTagsToEntities(textWithTags.tags),
Api::ConvertOption::SkipLocal); Api::ConvertOption::SkipLocal);
using PageFlag = MTPDinputMediaWebPage::Flag;
history->startSavingCloudDraft(topicRootId); history->startSavingCloudDraft(topicRootId);
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft( cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
MTP_flags(flags), MTP_flags(flags),
@ -2156,7 +2159,15 @@ void ApiWrap::saveDraftsToCloud() {
history->peer->input, history->peer->input,
MTP_string(textWithTags.text), MTP_string(textWithTags.text),
entities, entities,
MTPInputMedia() MTP_inputMediaWebPage(
MTP_flags(PageFlag::f_optional
| (cloudDraft->webpage.forceLargeMedia
? PageFlag::f_force_large_media
: PageFlag())
| (cloudDraft->webpage.forceSmallMedia
? PageFlag::f_force_small_media
: PageFlag())),
MTP_string(cloudDraft->webpage.url))
)).done([=](const MTPBool &result, const MTP::Response &response) { )).done([=](const MTPBool &result, const MTP::Response &response) {
const auto requestId = response.requestId; const auto requestId = response.requestId;
history->finishSavingCloudDraft( history->finishSavingCloudDraft(
@ -2243,7 +2254,7 @@ void ApiWrap::gotStickerSet(
} }
void ApiWrap::requestWebPageDelayed(not_null<WebPageData*> page) { void ApiWrap::requestWebPageDelayed(not_null<WebPageData*> page) {
if (page->pendingTill <= 0) { if (page->failed || !page->pendingTill) {
return; return;
} }
_webPagesPending.emplace(page, 0); _webPagesPending.emplace(page, 0);
@ -2548,7 +2559,8 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &resu
for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend();) { for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend();) {
if (i->second == req) { if (i->second == req) {
if (i->first->pendingTill > 0) { if (i->first->pendingTill > 0) {
i->first->pendingTill = -1; i->first->pendingTill = 0;
i->first->failed = 1;
_session->data().notifyWebPageUpdateDelayed(i->first); _session->data().notifyWebPageUpdateDelayed(i->first);
} }
i = _webPagesPending.erase(i); i = _webPagesPending.erase(i);

View File

@ -15,33 +15,53 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item_components.h" #include "history/history_item_components.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_web_page.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "storage/localstorage.h" #include "storage/localstorage.h"
namespace Data { namespace Data {
WebPageDraft WebPageDraft::FromItem(not_null<HistoryItem*> item) {
const auto previewMedia = item->media();
const auto previewPage = previewMedia
? previewMedia->webpage()
: nullptr;
using PageFlag = MediaWebPageFlag;
const auto previewFlags = previewMedia
? previewMedia->webpageFlags()
: PageFlag();
return {
.id = previewPage ? previewPage->id : 0,
.url = previewPage ? previewPage->url : QString(),
.forceLargeMedia = !!(previewFlags & PageFlag::ForceLargeMedia),
.forceSmallMedia = !!(previewFlags & PageFlag::ForceSmallMedia),
.invert = item->invertMedia(),
.manual = !!(previewFlags & PageFlag::Manual),
};
}
Draft::Draft( Draft::Draft(
const TextWithTags &textWithTags, const TextWithTags &textWithTags,
FullReplyTo reply, FullReplyTo reply,
const MessageCursor &cursor, const MessageCursor &cursor,
PreviewState previewState, WebPageDraft webpage,
mtpRequestId saveRequestId) mtpRequestId saveRequestId)
: textWithTags(textWithTags) : textWithTags(textWithTags)
, reply(std::move(reply)) , reply(std::move(reply))
, cursor(cursor) , cursor(cursor)
, previewState(previewState) , webpage(webpage)
, saveRequestId(saveRequestId) { , saveRequestId(saveRequestId) {
} }
Draft::Draft( Draft::Draft(
not_null<const Ui::InputField*> field, not_null<const Ui::InputField*> field,
FullReplyTo reply, FullReplyTo reply,
PreviewState previewState, WebPageDraft webpage,
mtpRequestId saveRequestId) mtpRequestId saveRequestId)
: textWithTags(field->getTextWithTags()) : textWithTags(field->getTextWithTags())
, reply(std::move(reply)) , reply(std::move(reply))
, cursor(field) , cursor(field)
, previewState(previewState) { , webpage(webpage) {
} }
void ApplyPeerCloudDraft( void ApplyPeerCloudDraft(
@ -67,6 +87,23 @@ void ApplyPeerCloudDraft(
const auto replyPeerId = reply.externalPeerId const auto replyPeerId = reply.externalPeerId
? reply.externalPeerId ? reply.externalPeerId
: peerId; : peerId;
auto webpage = WebPageDraft{
.invert = draft.is_invert_media(),
.removed = draft.is_no_webpage(),
};
if (const auto media = draft.vmedia()) {
media->match([&](const MTPDmessageMediaWebPage &data) {
const auto parsed = session->data().processWebpage(
data.vwebpage());
if (!parsed->failed) {
webpage.forceLargeMedia = data.is_force_large_media();
webpage.forceSmallMedia = data.is_force_small_media();
webpage.manual = data.is_manual();
webpage.url = parsed->url;
webpage.id = parsed->id;
}
}, [](const auto &) {});
}
auto cloudDraft = std::make_unique<Draft>( auto cloudDraft = std::make_unique<Draft>(
textWithTags, textWithTags,
FullReplyTo{ FullReplyTo{
@ -78,9 +115,7 @@ void ApplyPeerCloudDraft(
.topicRootId = topicRootId, .topicRootId = topicRootId,
}, },
MessageCursor(Ui::kQFixedMax, Ui::kQFixedMax, Ui::kQFixedMax), MessageCursor(Ui::kQFixedMax, Ui::kQFixedMax, Ui::kQFixedMax),
(draft.is_no_webpage() std::move(webpage));
? Data::PreviewState::Cancelled
: Data::PreviewState::Allowed));
cloudDraft->date = date; cloudDraft->date = date;
history->setCloudDraft(std::move(cloudDraft)); history->setCloudDraft(std::move(cloudDraft));

View File

@ -30,10 +30,19 @@ void ClearPeerCloudDraft(
MsgId topicRootId, MsgId topicRootId,
TimeId date); TimeId date);
enum class PreviewState : char { struct WebPageDraft {
Allowed, [[nodiscard]] static WebPageDraft FromItem(not_null<HistoryItem*> item);
Cancelled,
EmptyOnEdit, WebPageId id = 0;
QString url;
bool forceLargeMedia : 1 = false;
bool forceSmallMedia : 1 = false;
bool invert : 1 = false;
bool manual : 1 = false;
bool removed : 1 = false;
friend inline bool operator==(const WebPageDraft&, const WebPageDraft&)
= default;
}; };
struct Draft { struct Draft {
@ -42,19 +51,19 @@ struct Draft {
const TextWithTags &textWithTags, const TextWithTags &textWithTags,
FullReplyTo reply, FullReplyTo reply,
const MessageCursor &cursor, const MessageCursor &cursor,
PreviewState previewState, WebPageDraft webpage,
mtpRequestId saveRequestId = 0); mtpRequestId saveRequestId = 0);
Draft( Draft(
not_null<const Ui::InputField*> field, not_null<const Ui::InputField*> field,
FullReplyTo reply, FullReplyTo reply,
PreviewState previewState, WebPageDraft webpage,
mtpRequestId saveRequestId = 0); mtpRequestId saveRequestId = 0);
TimeId date = 0; TimeId date = 0;
TextWithTags textWithTags; TextWithTags textWithTags;
FullReplyTo reply; // reply.messageId.msg is editMsgId for edit draft. FullReplyTo reply; // reply.messageId.msg is editMsgId for edit draft.
MessageCursor cursor; MessageCursor cursor;
PreviewState previewState = PreviewState::Allowed; WebPageDraft webpage;
mtpRequestId saveRequestId = 0; mtpRequestId saveRequestId = 0;
}; };
@ -180,7 +189,7 @@ using HistoryDrafts = base::flat_map<DraftKey, std::unique_ptr<Draft>>;
} }
return (a->textWithTags == b->textWithTags) return (a->textWithTags == b->textWithTags)
&& (a->reply == b->reply) && (a->reply == b->reply)
&& (a->previewState == b->previewState); && (a->webpage == b->webpage);
} }
} // namespace Data } // namespace Data

View File

@ -404,6 +404,10 @@ WebPageData *Media::webpage() const {
return nullptr; return nullptr;
} }
MediaWebPageFlags Media::webpageFlags() const {
return {};
}
const SharedContact *Media::sharedContact() const { const SharedContact *Media::sharedContact() const {
return nullptr; return nullptr;
} }
@ -1462,6 +1466,10 @@ WebPageData *MediaWebPage::webpage() const {
return _page; return _page;
} }
MediaWebPageFlags MediaWebPage::webpageFlags() const {
return _flags;
}
bool MediaWebPage::hasReplyPreview() const { bool MediaWebPage::hasReplyPreview() const {
if (const auto document = MediaWebPage::document()) { if (const auto document = MediaWebPage::document()) {
return document->hasThumbnail() return document->hasThumbnail()

View File

@ -122,6 +122,7 @@ public:
virtual DocumentData *document() const; virtual DocumentData *document() const;
virtual PhotoData *photo() const; virtual PhotoData *photo() const;
virtual WebPageData *webpage() const; virtual WebPageData *webpage() const;
virtual MediaWebPageFlags webpageFlags() const;
virtual const SharedContact *sharedContact() const; virtual const SharedContact *sharedContact() const;
virtual const Call *call() const; virtual const Call *call() const;
virtual GameData *game() const; virtual GameData *game() const;
@ -381,6 +382,7 @@ public:
DocumentData *document() const override; DocumentData *document() const override;
PhotoData *photo() const override; PhotoData *photo() const override;
WebPageData *webpage() const override; WebPageData *webpage() const override;
MediaWebPageFlags webpageFlags() const override;
bool hasReplyPreview() const override; bool hasReplyPreview() const override;
Image *replyPreview() const override; Image *replyPreview() const override;

View File

@ -3261,7 +3261,8 @@ not_null<WebPageData*> Session::processWebpage(const MTPWebPage &data) {
case mtpc_webPageEmpty: { case mtpc_webPageEmpty: {
const auto result = webpage(data.c_webPageEmpty().vid().v); const auto result = webpage(data.c_webPageEmpty().vid().v);
if (result->pendingTill > 0) { if (result->pendingTill > 0) {
result->pendingTill = -1; // failed result->pendingTill = 0;
result->failed = 1;
notifyWebPageUpdateDelayed(result); notifyWebPageUpdateDelayed(result);
} }
return result; return result;

View File

@ -227,7 +227,7 @@ bool WebPageData::applyChanges(
const QString &newAuthor, const QString &newAuthor,
int newPendingTill) { int newPendingTill) {
if (newPendingTill != 0 if (newPendingTill != 0
&& (!url.isEmpty() || pendingTill < 0) && (!url.isEmpty() || failed)
&& (!pendingTill && (!pendingTill
|| pendingTill == newPendingTill || pendingTill == newPendingTill
|| newPendingTill < -1)) { || newPendingTill < -1)) {

View File

@ -100,8 +100,9 @@ struct WebPageData {
DocumentData *document = nullptr; DocumentData *document = nullptr;
WebPageCollage collage; WebPageCollage collage;
int duration = 0; int duration = 0;
int pendingTill = 0; TimeId pendingTill = 0;
int version = 0; uint32 version : 31 = 0;
uint32 failed : 1 = 0;
private: private:
void replaceDocumentGoodThumbnail(); void replaceDocumentGoodThumbnail();

View File

@ -203,13 +203,13 @@ void History::createLocalDraftFromCloud(MsgId topicRootId) {
draft->textWithTags, draft->textWithTags,
draft->reply, draft->reply,
draft->cursor, draft->cursor,
draft->previewState)); draft->webpage));
existing = localDraft(topicRootId); existing = localDraft(topicRootId);
} else if (existing != draft) { } else if (existing != draft) {
existing->textWithTags = draft->textWithTags; existing->textWithTags = draft->textWithTags;
existing->reply = draft->reply; existing->reply = draft->reply;
existing->cursor = draft->cursor; existing->cursor = draft->cursor;
existing->previewState = draft->previewState; existing->webpage = draft->webpage;
} }
existing->date = draft->date; existing->date = draft->date;
} }
@ -277,7 +277,7 @@ Data::Draft *History::createCloudDraft(
TextWithTags(), TextWithTags(),
FullReplyTo(), FullReplyTo(),
MessageCursor(), MessageCursor(),
Data::PreviewState::Allowed)); Data::WebPageDraft()));
cloudDraft(topicRootId)->date = TimeId(0); cloudDraft(topicRootId)->date = TimeId(0);
} else { } else {
auto existing = cloudDraft(topicRootId); auto existing = cloudDraft(topicRootId);
@ -286,13 +286,13 @@ Data::Draft *History::createCloudDraft(
fromDraft->textWithTags, fromDraft->textWithTags,
fromDraft->reply, fromDraft->reply,
fromDraft->cursor, fromDraft->cursor,
fromDraft->previewState)); fromDraft->webpage));
existing = cloudDraft(topicRootId); existing = cloudDraft(topicRootId);
} else if (existing != fromDraft) { } else if (existing != fromDraft) {
existing->textWithTags = fromDraft->textWithTags; existing->textWithTags = fromDraft->textWithTags;
existing->reply = fromDraft->reply; existing->reply = fromDraft->reply;
existing->cursor = fromDraft->cursor; existing->cursor = fromDraft->cursor;
existing->previewState = fromDraft->previewState; existing->webpage = fromDraft->webpage;
} }
existing->date = base::unixtime::now(); existing->date = base::unixtime::now();
existing->reply.topicRootId = topicRootId; existing->reply.topicRootId = topicRootId;

View File

@ -206,7 +206,6 @@ HistoryWidget::HistoryWidget(
, _updateEditTimeLeftDisplay([=] { updateField(); }) , _updateEditTimeLeftDisplay([=] { updateField(); })
, _fieldBarCancel(this, st::historyReplyCancel) , _fieldBarCancel(this, st::historyReplyCancel)
, _previewTimer([=] { requestPreview(); }) , _previewTimer([=] { requestPreview(); })
, _previewState(Data::PreviewState::Allowed)
, _topBar(this, controller) , _topBar(this, controller)
, _scroll( , _scroll(
this, this,
@ -443,10 +442,6 @@ HistoryWidget::HistoryWidget(
_fieldLinksParser = std::make_unique<MessageLinksParser>(_field); _fieldLinksParser = std::make_unique<MessageLinksParser>(_field);
_fieldLinksParser->list().changes( _fieldLinksParser->list().changes(
) | rpl::start_with_next([=](QStringList &&parsed) { ) | rpl::start_with_next([=](QStringList &&parsed) {
if (_previewState == Data::PreviewState::EmptyOnEdit
&& _parsedLinks != parsed) {
_previewState = Data::PreviewState::Allowed;
}
_parsedLinks = std::move(parsed); _parsedLinks = std::move(parsed);
checkPreview(); checkPreview();
}, lifetime()); }, lifetime());
@ -1604,7 +1599,7 @@ void HistoryWidget::fieldChanged() {
updateSendButtonType(); updateSendButtonType();
if (!HasSendText(_field)) { if (!HasSendText(_field)) {
_previewState = Data::PreviewState::Allowed; _previewDraft = {};
_fieldIsEmpty = true; _fieldIsEmpty = true;
} else if (_fieldIsEmpty) { } else if (_fieldIsEmpty) {
_fieldIsEmpty = false; _fieldIsEmpty = false;
@ -1668,14 +1663,14 @@ void HistoryWidget::saveFieldToHistoryLocalDraft() {
.messageId = FullMsgId(_history->peer->id, _editMsgId), .messageId = FullMsgId(_history->peer->id, _editMsgId),
.topicRootId = topicRootId, .topicRootId = topicRootId,
}, },
_previewState, _previewDraft,
_saveEditMsgRequestId)); _saveEditMsgRequestId));
} else { } else {
if (_replyTo || !_field->empty()) { if (_replyTo || !_field->empty()) {
_history->setLocalDraft(std::make_unique<Data::Draft>( _history->setLocalDraft(std::make_unique<Data::Draft>(
_field, _field,
_replyTo, _replyTo,
_previewState)); _previewDraft));
} else { } else {
_history->clearLocalDraft(topicRootId); _history->clearLocalDraft(topicRootId);
} }
@ -1783,7 +1778,7 @@ bool HistoryWidget::notify_switchInlineBotButtonReceived(
textWithTags, textWithTags,
FullReplyTo(), FullReplyTo(),
cursor, cursor,
Data::PreviewState::Allowed)); Data::WebPageDraft()));
applyDraft(); applyDraft();
return true; return true;
} }
@ -1935,7 +1930,7 @@ bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
} }
// Save links from _field to _parsedLinks without generating preview. // Save links from _field to _parsedLinks without generating preview.
_previewState = Data::PreviewState::Cancelled; _previewDraft = { .removed = true };
if (_editMsgId) { if (_editMsgId) {
_fieldLinksParser->setDisabled(!_replyEditMsg _fieldLinksParser->setDisabled(!_replyEditMsg
|| (_replyEditMsg->media() || (_replyEditMsg->media()
@ -1943,7 +1938,7 @@ bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
} }
_fieldLinksParser->parseNow(); _fieldLinksParser->parseNow();
_parsedLinks = _fieldLinksParser->list().current(); _parsedLinks = _fieldLinksParser->list().current();
_previewState = draft->previewState; _previewDraft = draft->webpage;
checkPreview(); checkPreview();
return true; return true;
@ -2471,7 +2466,7 @@ void HistoryWidget::registerDraftSource() {
? FullReplyTo{ FullMsgId(peerId, editMsgId) } ? FullReplyTo{ FullMsgId(peerId, editMsgId) }
: _replyTo), : _replyTo),
_field->getTextWithTags(), _field->getTextWithTags(),
_previewState, _previewDraft,
}; };
}; };
auto draftSource = Storage::MessageDraftSource{ auto draftSource = Storage::MessageDraftSource{
@ -2909,7 +2904,7 @@ void HistoryWidget::updateControlsVisibility() {
if (_editMsgId if (_editMsgId
|| _replyTo || _replyTo
|| readyToForward() || readyToForward()
|| (_previewData && _previewData->pendingTill >= 0) || (_previewData && !_previewData->failed)
|| _kbReplyTo) { || _kbReplyTo) {
if (_fieldBarCancel->isHidden()) { if (_fieldBarCancel->isHidden()) {
_fieldBarCancel->show(); _fieldBarCancel->show();
@ -3766,11 +3761,11 @@ void HistoryWidget::saveEditMsg() {
cancelEdit(); cancelEdit();
return; return;
} }
const auto webPageId = (_previewState != Data::PreviewState::Allowed) const auto webPageId = _previewDraft.removed
? CancelledWebPageId ? CancelledWebPageId
: ((_previewData && _previewData->pendingTill >= 0) : (_previewData && !_previewData->failed)
? _previewData->id ? _previewData->id
: WebPageId(0)); : WebPageId();
const auto textWithTags = _field->getTextWithAppliedMarkdown(); const auto textWithTags = _field->getTextWithAppliedMarkdown();
const auto prepareFlags = Ui::ItemTextOptions( const auto prepareFlags = Ui::ItemTextOptions(
@ -3925,11 +3920,11 @@ void HistoryWidget::send(Api::SendOptions options) {
_cornerButtons.clearReplyReturns(); _cornerButtons.clearReplyReturns();
} }
const auto webPageId = (_previewState != Data::PreviewState::Allowed) const auto webPageId = _previewDraft.removed
? CancelledWebPageId ? CancelledWebPageId
: ((_previewData && _previewData->pendingTill >= 0) : (_previewData && !_previewData->failed)
? _previewData->id ? _previewData->id
: WebPageId(0)); : WebPageId();
auto message = Api::MessageToSend(prepareSendAction(options)); auto message = Api::MessageToSend(prepareSendAction(options));
message.textWithTags = _field->getTextWithAppliedMarkdown(); message.textWithTags = _field->getTextWithAppliedMarkdown();
@ -3950,7 +3945,9 @@ void HistoryWidget::send(Api::SendOptions options) {
hideSelectorControlsAnimated(); hideSelectorControlsAnimated();
if (_previewData && _previewData->pendingTill) previewCancel(); if (_previewData && _previewData->pendingTill) {
previewCancel();
}
setInnerFocus(); setInnerFocus();
if (!_keyboard->hasMarkup() && _keyboard->forceReply() && !_kbReplyTo) { if (!_keyboard->hasMarkup() && _keyboard->forceReply() && !_kbReplyTo) {
@ -4790,7 +4787,10 @@ void HistoryWidget::toggleKeyboard(bool manual) {
_field->setMaxHeight(computeMaxFieldHeight()); _field->setMaxHeight(computeMaxFieldHeight());
_kbReplyTo = nullptr; _kbReplyTo = nullptr;
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_editMsgId && !_replyTo) { if (!readyToForward()
&& (!_previewData || _previewData->failed)
&& !_editMsgId
&& !_replyTo) {
_fieldBarCancel->hide(); _fieldBarCancel->hide();
updateMouseTracking(); updateMouseTracking();
} }
@ -5775,7 +5775,10 @@ void HistoryWidget::updateHistoryGeometry(
} else if (writeRestriction().has_value()) { } else if (writeRestriction().has_value()) {
newScrollHeight -= _unblock->height(); newScrollHeight -= _unblock->height();
} }
if (_editMsgId || replyTo() || readyToForward() || (_previewData && _previewData->pendingTill >= 0)) { if (_editMsgId
|| replyTo()
|| readyToForward()
|| (_previewData && !_previewData->failed)) {
newScrollHeight -= st::historyReplyHeight; newScrollHeight -= st::historyReplyHeight;
} }
if (_kbShown) { if (_kbShown) {
@ -6077,7 +6080,9 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
_field->setMaxHeight(computeMaxFieldHeight()); _field->setMaxHeight(computeMaxFieldHeight());
_kbShown = false; _kbShown = false;
_kbReplyTo = nullptr; _kbReplyTo = nullptr;
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyTo) { if (!readyToForward()
&& (!_previewData || _previewData->failed)
&& !_replyTo) {
_fieldBarCancel->hide(); _fieldBarCancel->hide();
updateMouseTracking(); updateMouseTracking();
} }
@ -6093,7 +6098,10 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
_field->setMaxHeight(computeMaxFieldHeight()); _field->setMaxHeight(computeMaxFieldHeight());
_kbShown = false; _kbShown = false;
_kbReplyTo = nullptr; _kbReplyTo = nullptr;
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyTo && !_editMsgId) { if (!readyToForward()
&& (!_previewData || _previewData->failed)
&& !_replyTo
&& !_editMsgId) {
_fieldBarCancel->hide(); _fieldBarCancel->hide();
updateMouseTracking(); updateMouseTracking();
} }
@ -6138,7 +6146,7 @@ int HistoryWidget::computeMaxFieldHeight() const {
- ((_editMsgId - ((_editMsgId
|| replyTo() || replyTo()
|| readyToForward() || readyToForward()
|| (_previewData && _previewData->pendingTill >= 0)) || (_previewData && !_previewData->failed))
? st::historyReplyHeight ? st::historyReplyHeight
: 0) : 0)
- (2 * st::historySendPadding) - (2 * st::historySendPadding)
@ -6242,6 +6250,15 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
_peer, _peer,
Window::SectionShow::Way::Forward, Window::SectionShow::Way::Forward,
_editMsgId); _editMsgId);
} else if (_previewData
&& !_previewData->failed
&& !_previewData->pendingTill) {
//const auto history = _history;
//using namespace HistoryView::Controls;
//EditWebPageOptions(
// controller()->uiShow(),
// _previewData,
// _previewDraft);
} }
} }
} }
@ -7057,7 +7074,7 @@ void HistoryWidget::setFieldText(
| TextUpdateEvent::SendTyping; | TextUpdateEvent::SendTyping;
previewCancel(); previewCancel();
_previewState = Data::PreviewState::Allowed; _previewDraft = {};
} }
void HistoryWidget::clearFieldText( void HistoryWidget::clearFieldText(
@ -7171,7 +7188,7 @@ void HistoryWidget::setReplyFieldsFromProcessing() {
TextWithTags(), TextWithTags(),
id, id,
MessageCursor(), MessageCursor(),
Data::PreviewState::Allowed)); Data::WebPageDraft()));
} }
} else { } else {
_replyEditMsg = item; _replyEditMsg = item;
@ -7218,7 +7235,7 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
_history->setLocalDraft(std::make_unique<Data::Draft>( _history->setLocalDraft(std::make_unique<Data::Draft>(
_field, _field,
_replyTo, _replyTo,
_previewState)); _previewDraft));
} else { } else {
_history->clearLocalDraft({}); _history->clearLocalDraft({});
} }
@ -7230,23 +7247,17 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
int(editData.text.size()), int(editData.text.size()),
Ui::kQFixedMax Ui::kQFixedMax
}; };
const auto previewPage = [&]() -> WebPageData* { const auto previewDraft = Data::WebPageDraft::FromItem(item);
if (const auto media = item->media()) {
return media->webpage();
}
return nullptr;
}();
const auto previewState = previewPage
? Data::PreviewState::Allowed
: Data::PreviewState::EmptyOnEdit;
_history->setLocalEditDraft(std::make_unique<Data::Draft>( _history->setLocalEditDraft(std::make_unique<Data::Draft>(
editData, editData,
FullReplyTo{ item->fullId() }, FullReplyTo{ item->fullId() },
cursor, cursor,
previewState)); previewDraft));
applyDraft(); applyDraft();
_previewData = previewPage; _previewData = previewDraft.id
? session().data().webpage(previewDraft.id).get()
: nullptr;
if (_previewData) { if (_previewData) {
updatePreview(); updatePreview();
} }
@ -7316,7 +7327,9 @@ bool HistoryWidget::cancelReply(bool lastKeyboardUsed) {
_processingReplyItem = _replyEditMsg = nullptr; _processingReplyItem = _replyEditMsg = nullptr;
_processingReplyTo = _replyTo = FullReplyTo(); _processingReplyTo = _replyTo = FullReplyTo();
mouseMoveEvent(0); mouseMoveEvent(0);
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_kbReplyTo) { if (!readyToForward()
&& (!_previewData || _previewData->failed)
&& !_kbReplyTo) {
_fieldBarCancel->hide(); _fieldBarCancel->hide();
updateMouseTracking(); updateMouseTracking();
} }
@ -7387,7 +7400,9 @@ void HistoryWidget::cancelEdit() {
saveDraft(); saveDraft();
mouseMoveEvent(nullptr); mouseMoveEvent(nullptr);
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !replyTo()) { if (!readyToForward()
&& (!_previewData || _previewData->failed)
&& !replyTo()) {
_fieldBarCancel->hide(); _fieldBarCancel->hide();
updateMouseTracking(); updateMouseTracking();
} }
@ -7408,8 +7423,8 @@ void HistoryWidget::cancelEdit() {
void HistoryWidget::cancelFieldAreaState() { void HistoryWidget::cancelFieldAreaState() {
controller()->hideLayer(); controller()->hideLayer();
_replyForwardPressed = false; _replyForwardPressed = false;
if (_previewData && _previewData->pendingTill >= 0) { if (_previewData && !_previewData->failed) {
_previewState = Data::PreviewState::Cancelled; _previewDraft = { .removed = true };
previewCancel(); previewCancel();
_saveDraftText = true; _saveDraftText = true;
@ -7437,7 +7452,7 @@ void HistoryWidget::checkPreview() {
const auto previewRestricted = [&] { const auto previewRestricted = [&] {
return _peer && _peer->amRestricted(ChatRestriction::EmbedLinks); return _peer && _peer->amRestricted(ChatRestriction::EmbedLinks);
}(); }();
if (_previewState != Data::PreviewState::Allowed || previewRestricted) { if (_previewDraft.removed || previewRestricted) {
previewCancel(); previewCancel();
return; return;
} }
@ -7446,7 +7461,7 @@ void HistoryWidget::checkPreview() {
_api.request(base::take(_previewRequest)).cancel(); _api.request(base::take(_previewRequest)).cancel();
_previewLinks = links; _previewLinks = links;
if (_previewLinks.isEmpty()) { if (_previewLinks.isEmpty()) {
if (_previewData && _previewData->pendingTill >= 0) { if (_previewData && !_previewData->failed) {
previewCancel(); previewCancel();
} }
} else { } else {
@ -7462,7 +7477,7 @@ void HistoryWidget::checkPreview() {
} else if (i.value()) { } else if (i.value()) {
_previewData = session().data().webpage(i.value()); _previewData = session().data().webpage(i.value());
updatePreview(); updatePreview();
} else if (_previewData && _previewData->pendingTill >= 0) { } else if (_previewData && !_previewData->failed) {
previewCancel(); previewCancel();
} }
} }
@ -7470,9 +7485,7 @@ void HistoryWidget::checkPreview() {
} }
void HistoryWidget::requestPreview() { void HistoryWidget::requestPreview() {
if (!_previewData if (!_previewData || _previewData->failed || _previewLinks.isEmpty()) {
|| (_previewData->pendingTill <= 0)
|| _previewLinks.isEmpty()) {
return; return;
} }
const auto links = _previewLinks; const auto links = _previewLinks;
@ -7498,11 +7511,11 @@ void HistoryWidget::gotPreview(
_previewCache.insert(links, page->id); _previewCache.insert(links, page->id);
if (page->pendingTill > 0 if (page->pendingTill > 0
&& page->pendingTill <= base::unixtime::now()) { && page->pendingTill <= base::unixtime::now()) {
page->pendingTill = -1; page->pendingTill = 0;
page->failed = true;
} }
if (links == _previewLinks if (links == _previewLinks && !_previewDraft.removed) {
&& _previewState == Data::PreviewState::Allowed) { _previewData = (page->id && !page->failed)
_previewData = (page->id && page->pendingTill >= 0)
? page.get() ? page.get()
: nullptr; : nullptr;
updatePreview(); updatePreview();
@ -7510,8 +7523,7 @@ void HistoryWidget::gotPreview(
session().data().sendWebPageGamePollNotifications(); session().data().sendWebPageGamePollNotifications();
} else if (result.type() == mtpc_messageMediaEmpty) { } else if (result.type() == mtpc_messageMediaEmpty) {
_previewCache.insert(links, 0); _previewCache.insert(links, 0);
if (links == _previewLinks if (links == _previewLinks && !_previewDraft.removed) {
&& _previewState == Data::PreviewState::Allowed) {
_previewData = nullptr; _previewData = nullptr;
updatePreview(); updatePreview();
} }
@ -7520,7 +7532,7 @@ void HistoryWidget::gotPreview(
void HistoryWidget::updatePreview() { void HistoryWidget::updatePreview() {
_previewTimer.cancel(); _previewTimer.cancel();
if (_previewData && _previewData->pendingTill >= 0) { if (_previewData && !_previewData->failed) {
_fieldBarCancel->show(); _fieldBarCancel->show();
updateMouseTracking(); updateMouseTracking();
if (_previewData->pendingTill) { if (_previewData->pendingTill) {
@ -7924,11 +7936,12 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
} else if (hasForward) { } else if (hasForward) {
backy -= st::historyReplyHeight; backy -= st::historyReplyHeight;
backh += st::historyReplyHeight; backh += st::historyReplyHeight;
} else if (_previewData && _previewData->pendingTill >= 0) { } else if (_previewData && !_previewData->failed) {
backy -= st::historyReplyHeight; backy -= st::historyReplyHeight;
backh += st::historyReplyHeight; backh += st::historyReplyHeight;
} }
auto drawWebPagePreview = (_previewData && _previewData->pendingTill >= 0) && !_replyForwardPressed; auto drawWebPagePreview = (_previewData && !_previewData->failed)
&& !_replyForwardPressed;
p.setInactive( p.setInactive(
controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any)); controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any));
p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg); p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg);

View File

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h" #include "history/history.h"
#include "chat_helpers/bot_command.h" #include "chat_helpers/bot_command.h"
#include "chat_helpers/field_autocomplete.h" #include "chat_helpers/field_autocomplete.h"
#include "data/data_drafts.h"
#include "window/section_widget.h" #include "window/section_widget.h"
#include "ui/widgets/fields/input_field.h" #include "ui/widgets/fields/input_field.h"
#include "mtproto/sender.h" #include "mtproto/sender.h"
@ -30,7 +31,6 @@ class Error;
} // namespace MTP } // namespace MTP
namespace Data { namespace Data {
enum class PreviewState : char;
class PhotoMedia; class PhotoMedia;
} // namespace Data } // namespace Data
@ -682,7 +682,7 @@ private:
Ui::Text::String _previewTitle; Ui::Text::String _previewTitle;
Ui::Text::String _previewDescription; Ui::Text::String _previewDescription;
base::Timer _previewTimer; base::Timer _previewTimer;
Data::PreviewState _previewState = Data::PreviewState(); Data::WebPageDraft _previewDraft;
bool _replyForwardPressed = false; bool _replyForwardPressed = false;

View File

@ -102,7 +102,7 @@ using VoiceRecordBar = Controls::VoiceRecordBar;
using ForwardPanel = Controls::ForwardPanel; using ForwardPanel = Controls::ForwardPanel;
[[nodiscard]] auto ShowWebPagePreview(WebPageData *page) { [[nodiscard]] auto ShowWebPagePreview(WebPageData *page) {
return page && (page->pendingTill >= 0); return page && !page->failed;
} }
WebPageText ProcessWebPageData(WebPageData *page) { WebPageText ProcessWebPageData(WebPageData *page) {
@ -128,9 +128,9 @@ public:
void cancel(); void cancel();
void checkPreview(); void checkPreview();
[[nodiscard]] Data::PreviewState state() const; [[nodiscard]] Data::WebPageDraft draft() const;
void setState(Data::PreviewState value); void setAllowed(bool allowed);
void refreshState(Data::PreviewState value, bool disable); void refreshDraft(Data::WebPageDraft draft, bool disable);
[[nodiscard]] rpl::producer<> paintRequests() const; [[nodiscard]] rpl::producer<> paintRequests() const;
[[nodiscard]] rpl::producer<QString> titleChanges() const; [[nodiscard]] rpl::producer<QString> titleChanges() const;
@ -145,7 +145,7 @@ private:
MTP::Sender _api; MTP::Sender _api;
MessageLinksParser _fieldLinksParser; MessageLinksParser _fieldLinksParser;
Data::PreviewState _previewState = Data::PreviewState(); Data::WebPageDraft _previewDraft;
QStringList _parsedLinks; QStringList _parsedLinks;
QString _previewLinks; QString _previewLinks;
@ -172,7 +172,6 @@ WebpageProcessor::WebpageProcessor(
: _history(history) : _history(history)
, _api(&history->session().mtp()) , _api(&history->session().mtp())
, _fieldLinksParser(field) , _fieldLinksParser(field)
, _previewState(Data::PreviewState::Allowed)
, _timer([=] { , _timer([=] {
if (!ShowWebPagePreview(_previewData) if (!ShowWebPagePreview(_previewData)
|| _previewLinks.isEmpty()) { || _previewLinks.isEmpty()) {
@ -198,12 +197,7 @@ WebpageProcessor::WebpageProcessor(
_fieldLinksParser.list().changes( _fieldLinksParser.list().changes(
) | rpl::start_with_next([=](QStringList &&parsed) { ) | rpl::start_with_next([=](QStringList &&parsed) {
if (_previewState == Data::PreviewState::EmptyOnEdit
&& _parsedLinks != parsed) {
_previewState = Data::PreviewState::Allowed;
}
_parsedLinks = std::move(parsed); _parsedLinks = std::move(parsed);
checkPreview(); checkPreview();
}, _lifetime); }, _lifetime);
} }
@ -212,23 +206,23 @@ rpl::producer<> WebpageProcessor::paintRequests() const {
return _paintRequests.events(); return _paintRequests.events();
} }
Data::PreviewState WebpageProcessor::state() const { Data::WebPageDraft WebpageProcessor::draft() const {
return _previewState; return _previewDraft;
} }
void WebpageProcessor::setState(Data::PreviewState value) { void WebpageProcessor::setAllowed(bool allowed) {
_previewState = value; _previewDraft.removed = !allowed;
} }
void WebpageProcessor::refreshState( void WebpageProcessor::refreshDraft(
Data::PreviewState value, Data::WebPageDraft draft,
bool disable) { bool disable) {
// Save links from _field to _parsedLinks without generating preview. // Save links from _field to _parsedLinks without generating preview.
_previewState = Data::PreviewState::Cancelled; _previewDraft = { .removed = true };
_fieldLinksParser.setDisabled(disable); _fieldLinksParser.setDisabled(disable);
_fieldLinksParser.parseNow(); _fieldLinksParser.parseNow();
_parsedLinks = _fieldLinksParser.list().current(); _parsedLinks = _fieldLinksParser.list().current();
_previewState = value; _previewDraft = draft;
checkPreview(); checkPreview();
} }
@ -275,21 +269,20 @@ void WebpageProcessor::getWebPagePreview() {
result.match([=](const MTPDmessageMediaWebPage &d) { result.match([=](const MTPDmessageMediaWebPage &d) {
const auto page = _history->owner().processWebpage(d.vwebpage()); const auto page = _history->owner().processWebpage(d.vwebpage());
_previewCache.insert({ links, page->id }); _previewCache.insert({ links, page->id });
auto &till = page->pendingTill; if (page->pendingTill > 0
if (till > 0 && till <= base::unixtime::now()) { && page->pendingTill <= base::unixtime::now()) {
till = -1; page->pendingTill = 0;
page->failed = true;
} }
if (links == _previewLinks if (links == _previewLinks && !_previewDraft.removed) {
&& _previewState == Data::PreviewState::Allowed) { _previewData = (page->id && !page->failed)
_previewData = (page->id && page->pendingTill >= 0)
? page.get() ? page.get()
: nullptr; : nullptr;
updatePreview(); updatePreview();
} }
}, [=](const MTPDmessageMediaEmpty &d) { }, [=](const MTPDmessageMediaEmpty &d) {
_previewCache.insert({ links, 0 }); _previewCache.insert({ links, 0 });
if (links == _previewLinks if (links == _previewLinks && !_previewDraft.removed) {
&& _previewState == Data::PreviewState::Allowed) {
_previewData = nullptr; _previewData = nullptr;
updatePreview(); updatePreview();
} }
@ -303,8 +296,7 @@ void WebpageProcessor::getWebPagePreview() {
void WebpageProcessor::checkPreview() { void WebpageProcessor::checkPreview() {
const auto previewRestricted = _history->peer const auto previewRestricted = _history->peer
&& _history->peer->amRestricted(ChatRestriction::EmbedLinks); && _history->peer->amRestricted(ChatRestriction::EmbedLinks);
if (_previewState != Data::PreviewState::Allowed if (_previewDraft.removed || previewRestricted) {
|| previewRestricted) {
cancel(); cancel();
return; return;
} }
@ -1476,7 +1468,7 @@ void ComposeControls::setFieldText(
if (_preview) { if (_preview) {
_preview->cancel(); _preview->cancel();
_preview->setState(Data::PreviewState::Allowed); _preview->setAllowed(true);
} }
} }
@ -1490,7 +1482,7 @@ void ComposeControls::saveFieldToHistoryLocalDraft() {
const auto key = draftKeyCurrent(); const auto key = draftKeyCurrent();
_history->setDraft( _history->setDraft(
key, key,
std::make_unique<Data::Draft>(_field, id, _preview->state())); std::make_unique<Data::Draft>(_field, id, _preview->draft()));
} else { } else {
_history->clearDraft(draftKeyCurrent()); _history->clearDraft(draftKeyCurrent());
} }
@ -1625,7 +1617,7 @@ void ComposeControls::init() {
_header->previewCancelled( _header->previewCancelled(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
if (_preview) { if (_preview) {
_preview->setState(Data::PreviewState::Cancelled); _preview->setAllowed(false);
} }
_saveDraftText = true; _saveDraftText = true;
_saveDraftStart = crl::now(); _saveDraftStart = crl::now();
@ -2009,7 +2001,7 @@ void ComposeControls::fieldChanged() {
updateSendButtonType(); updateSendButtonType();
_hasSendText = HasSendText(_field); _hasSendText = HasSendText(_field);
if (!_hasSendText.current() && _preview) { if (!_hasSendText.current() && _preview) {
_preview->setState(Data::PreviewState::Allowed); _preview->setAllowed(true);
} }
if (updateBotCommandShown() || updateLikeShown()) { if (updateBotCommandShown() || updateLikeShown()) {
updateControlsVisibility(); updateControlsVisibility();
@ -2113,7 +2105,7 @@ void ComposeControls::registerDraftSource() {
return Storage::MessageDraft{ return Storage::MessageDraft{
_header->getDraftReply(), _header->getDraftReply(),
_field->getTextWithTags(), _field->getTextWithTags(),
_preview->state(), _preview->draft(),
}; };
}; };
auto draftSource = Storage::MessageDraftSource{ auto draftSource = Storage::MessageDraftSource{
@ -2179,7 +2171,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
} }
_header->editMessage({}); _header->editMessage({});
_header->replyToMessage({}); _header->replyToMessage({});
_preview->refreshState(Data::PreviewState::Allowed, false); _preview->refreshDraft({}, false);
_canReplaceMedia = false; _canReplaceMedia = false;
_photoEditMedia = nullptr; _photoEditMedia = nullptr;
return; return;
@ -2194,7 +2186,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
_textUpdateEvents = TextUpdateEvent::SaveDraft | TextUpdateEvent::SendTyping; _textUpdateEvents = TextUpdateEvent::SaveDraft | TextUpdateEvent::SendTyping;
if (_preview) { if (_preview) {
const auto disablePreview = (editDraft != nullptr); const auto disablePreview = (editDraft != nullptr);
_preview->refreshState(draft->previewState, disablePreview); _preview->refreshDraft(draft->webpage, disablePreview);
} }
if (draft == editDraft) { if (draft == editDraft) {
@ -2215,7 +2207,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
item->fullId()); item->fullId());
} }
_header->editMessage(editingId, _photoEditMedia != nullptr); _header->editMessage(editingId, _photoEditMedia != nullptr);
_preview->refreshState(_preview->state(), disablePreview); _preview->refreshDraft(_preview->draft(), disablePreview);
return true; return true;
} }
_canReplaceMedia = false; _canReplaceMedia = false;
@ -2892,15 +2884,6 @@ void ComposeControls::editMessage(not_null<HistoryItem*> item) {
int(editData.text.size()), int(editData.text.size()),
Ui::kQFixedMax Ui::kQFixedMax
}; };
const auto previewPage = [&]() -> WebPageData* {
if (const auto media = item->media()) {
return media->webpage();
}
return nullptr;
}();
const auto previewState = previewPage
? Data::PreviewState::Allowed
: Data::PreviewState::EmptyOnEdit;
const auto key = draftKey(DraftType::Edit); const auto key = draftKey(DraftType::Edit);
_history->setDraft( _history->setDraft(
key, key,
@ -2911,7 +2894,7 @@ void ComposeControls::editMessage(not_null<HistoryItem*> item) {
.topicRootId = key.topicRootId(), .topicRootId = key.topicRootId(),
}, },
cursor, cursor,
previewState)); Data::WebPageDraft::FromItem(item)));
applyDraft(); applyDraft();
if (updateReplaceMediaButton()) { if (updateReplaceMediaButton()) {
updateControlsVisibility(); updateControlsVisibility();
@ -2997,7 +2980,7 @@ void ComposeControls::replyToMessage(FullReplyTo id) {
TextWithTags(), TextWithTags(),
id, id,
MessageCursor(), MessageCursor(),
Data::PreviewState::Allowed)); Data::WebPageDraft()));
} }
} else { } else {
_header->replyToMessage(id); _header->replyToMessage(id);

View File

@ -43,7 +43,6 @@ namespace Data {
struct MessagePosition; struct MessagePosition;
struct Draft; struct Draft;
class DraftKey; class DraftKey;
enum class PreviewState : char;
class PhotoMedia; class PhotoMedia;
} // namespace Data } // namespace Data

View File

@ -493,7 +493,7 @@ void ShowReplyToChatBox(
textWithTags, textWithTags,
reply, reply,
cursor, cursor,
Data::PreviewState::Allowed)); Data::WebPageDraft()));
history->clearLocalEditDraft(topicRootId); history->clearLocalEditDraft(topicRootId);
history->session().changes().entryUpdated( history->session().changes().entryUpdated(
thread, thread,

View File

@ -604,7 +604,7 @@ bool MainWidget::shareUrl(
textWithTags, textWithTags,
FullReplyTo{ .topicRootId = topicRootId }, FullReplyTo{ .topicRootId = topicRootId },
cursor, cursor,
Data::PreviewState::Allowed)); Data::WebPageDraft()));
history->clearLocalEditDraft(topicRootId); history->clearLocalEditDraft(topicRootId);
history->session().changes().entryUpdated( history->session().changes().entryUpdated(
thread, thread,

View File

@ -575,7 +575,7 @@ chatInviteExported#ab4a819 flags:# revoked:flags.0?true permanent:flags.5?true r
chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite; chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite;
chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
chatInvite#3033e855 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector<User> color:flags.10?int = ChatInvite; chatInvite#cde0ec40 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector<User> color:int = ChatInvite;
chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite;
inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetEmpty#ffb62b95 = InputStickerSet;
@ -589,7 +589,7 @@ inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet;
inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet;
inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet;
stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true text_color:flags.9?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;
messages.stickerSet#6e153f16 set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = messages.StickerSet; messages.stickerSet#6e153f16 set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = messages.StickerSet;
messages.stickerSetNotModified#d3f924eb = messages.StickerSet; messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
@ -705,7 +705,7 @@ botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period
botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true message:string entities:flags.1?Vector<MessageEntity> url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector<MessageEntity> url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult;
botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult;
@ -1586,7 +1586,7 @@ payments.giveawayInfoResults#cd5570 flags:# winner:flags.0?true refunded:flags.1
prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway;
boost#53c300c8 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string = Boost; boost#2a1c8c71 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int = Boost;
premium.boostsList#86f8613c flags:# count:int boosts:Vector<Boost> next_offset:flags.0?string users:Vector<User> = premium.BoostsList; premium.boostsList#86f8613c flags:# count:int boosts:Vector<Boost> next_offset:flags.0?string users:Vector<User> = premium.BoostsList;
@ -1594,7 +1594,7 @@ myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldow
premium.myBoosts#9ae228e2 my_boosts:Vector<MyBoost> chats:Vector<Chat> users:Vector<User> = premium.MyBoosts; premium.myBoosts#9ae228e2 my_boosts:Vector<MyBoost> chats:Vector<Chat> users:Vector<User> = premium.MyBoosts;
premium.boostsStatus#3d5daae6 flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.3?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector<PrepaidGiveaway> my_boost_slots:flags.2?Vector<int> = premium.BoostsStatus; premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector<PrepaidGiveaway> my_boost_slots:flags.2?Vector<int> = premium.BoostsStatus;
---functions--- ---functions---
@ -2168,5 +2168,5 @@ stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool;
premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList;
premium.getMyBoosts#be77b4a = premium.MyBoosts; premium.getMyBoosts#be77b4a = premium.MyBoosts;
premium.applyBoost#184bc3b9 flags:# slots:flags.0?Vector<int> peer:InputPeer = Bool; premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector<int> peer:InputPeer = premium.MyBoosts;
premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus;

View File

@ -1044,7 +1044,7 @@ void EnumerateDrafts(
key, key,
draft->reply, draft->reply,
draft->textWithTags, draft->textWithTags,
draft->previewState, draft->webpage,
draft->cursor); draft->cursor);
} }
for (const auto &[key, source] : sources) { for (const auto &[key, source] : sources) {
@ -1057,7 +1057,7 @@ void EnumerateDrafts(
key, key,
draft.reply, draft.reply,
draft.textWithTags, draft.textWithTags,
draft.previewState, draft.webpage,
cursor); cursor);
} }
} }
@ -1122,13 +1122,18 @@ void Account::writeDrafts(not_null<History*> history) {
auto&&, // key auto&&, // key
const FullReplyTo &reply, const FullReplyTo &reply,
const TextWithTags &text, const TextWithTags &text,
Data::PreviewState, const Data::WebPageDraft &webpage,
auto&&) { // cursor auto&&) { // cursor
size += sizeof(qint64) // key size += sizeof(qint64) // key
+ Serialize::stringSize(text.text) + Serialize::stringSize(text.text)
+ TextUtilities::SerializeTagsSize(text.tags) + TextUtilities::SerializeTagsSize(text.tags)
+ sizeof(qint64) + sizeof(qint64) // messageId + sizeof(qint64) + sizeof(qint64) // messageId
+ sizeof(qint32); // previewState + Serialize::stringSize(webpage.url)
+ sizeof(qint32) // webpage.forceLargeMedia
+ sizeof(qint32) // webpage.forceSmallMedia
+ sizeof(qint32) // webpage.invert
+ sizeof(qint32) // webpage.manual
+ sizeof(qint32); // webpage.removed
}; };
EnumerateDrafts( EnumerateDrafts(
map, map,
@ -1146,7 +1151,7 @@ void Account::writeDrafts(not_null<History*> history) {
const Data::DraftKey &key, const Data::DraftKey &key,
const FullReplyTo &reply, const FullReplyTo &reply,
const TextWithTags &text, const TextWithTags &text,
Data::PreviewState previewState, const Data::WebPageDraft &webpage,
auto&&) { // cursor auto&&) { // cursor
data.stream data.stream
<< key.serialize() << key.serialize()
@ -1154,7 +1159,12 @@ void Account::writeDrafts(not_null<History*> history) {
<< TextUtilities::SerializeTags(text.tags) << TextUtilities::SerializeTags(text.tags)
<< qint64(reply.messageId.peer.value) << qint64(reply.messageId.peer.value)
<< qint64(reply.messageId.msg.bare) << qint64(reply.messageId.msg.bare)
<< qint32(previewState); << webpage.url
<< qint32(webpage.forceLargeMedia ? 1 : 0)
<< qint32(webpage.forceSmallMedia ? 1 : 0)
<< qint32(webpage.invert ? 1 : 0)
<< qint32(webpage.manual ? 1 : 0)
<< qint32(webpage.removed ? 1 : 0);
}; };
EnumerateDrafts( EnumerateDrafts(
map, map,
@ -1206,7 +1216,7 @@ void Account::writeDraftCursors(not_null<History*> history) {
const Data::DraftKey &key, const Data::DraftKey &key,
auto&&, // reply auto&&, // reply
auto&&, // text auto&&, // text
Data::PreviewState, auto&&, // webpage
const MessageCursor &cursor) { // cursor const MessageCursor &cursor) { // cursor
data.stream data.stream
<< key.serialize() << key.serialize()
@ -1370,18 +1380,33 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
QByteArray textTagsSerialized; QByteArray textTagsSerialized;
qint64 keyValue = 0; qint64 keyValue = 0;
qint64 messageIdPeer = 0, messageIdMsg = 0; qint64 messageIdPeer = 0, messageIdMsg = 0;
qint32 keyValueOld = 0, uncheckedPreviewState = 0; qint32 keyValueOld = 0;
QString webpageUrl;
qint32 webpageForceLargeMedia = 0;
qint32 webpageForceSmallMedia = 0;
qint32 webpageInvert = 0;
qint32 webpageManual = 0;
qint32 webpageRemoved = 0;
if (keysOld) { if (keysOld) {
draft.stream >> keyValueOld; draft.stream >> keyValueOld;
} else { } else {
draft.stream >> keyValue; draft.stream >> keyValue;
} }
if (!rich) { if (!rich) {
qint32 uncheckedPreviewState = 0;
draft.stream draft.stream
>> text.text >> text.text
>> textTagsSerialized >> textTagsSerialized
>> messageIdMsg >> messageIdMsg
>> uncheckedPreviewState; >> uncheckedPreviewState;
enum class PreviewState : char {
Allowed,
Cancelled,
EmptyOnEdit,
};
if (uncheckedPreviewState == int(PreviewState::Cancelled)) {
webpageRemoved = 1;
}
messageIdPeer = peerId.value; messageIdPeer = peerId.value;
} else { } else {
draft.stream draft.stream
@ -1389,17 +1414,16 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
>> textTagsSerialized >> textTagsSerialized
>> messageIdPeer >> messageIdPeer
>> messageIdMsg >> messageIdMsg
>> uncheckedPreviewState; >> webpageUrl
>> webpageForceLargeMedia
>> webpageForceSmallMedia
>> webpageInvert
>> webpageManual
>> webpageRemoved;
} }
text.tags = TextUtilities::DeserializeTags( text.tags = TextUtilities::DeserializeTags(
textTagsSerialized, textTagsSerialized,
text.text.size()); text.text.size());
auto previewState = Data::PreviewState::Allowed;
switch (static_cast<Data::PreviewState>(uncheckedPreviewState)) {
case Data::PreviewState::Cancelled:
case Data::PreviewState::EmptyOnEdit:
previewState = Data::PreviewState(uncheckedPreviewState);
}
const auto key = keysOld const auto key = keysOld
? Data::DraftKey::FromSerializedOld(keyValueOld) ? Data::DraftKey::FromSerializedOld(keyValueOld)
: Data::DraftKey::FromSerialized(keyValue); : Data::DraftKey::FromSerialized(keyValue);
@ -1413,7 +1437,14 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
.topicRootId = key.topicRootId(), .topicRootId = key.topicRootId(),
}, },
MessageCursor(), MessageCursor(),
previewState)); Data::WebPageDraft{
.url = webpageUrl,
.forceLargeMedia = (webpageForceLargeMedia == 1),
.forceSmallMedia = (webpageForceSmallMedia == 1),
.invert = (webpageInvert == 1),
.manual = (webpageManual == 1),
.removed = (webpageRemoved == 1),
}));
} }
} }
if (draft.stream.status() != QDataStream::Ok) { if (draft.stream.status() != QDataStream::Ok) {
@ -1478,9 +1509,9 @@ void Account::readDraftsWithCursorsLegacy(
msgData, msgData,
FullReplyTo{ FullMsgId(peerId, MsgId(msgReplyTo)) }, FullReplyTo{ FullMsgId(peerId, MsgId(msgReplyTo)) },
MessageCursor(), MessageCursor(),
(msgPreviewCancelled Data::WebPageDraft{
? Data::PreviewState::Cancelled .removed = (msgPreviewCancelled == 1),
: Data::PreviewState::Allowed))); }));
} }
if (editMsgId) { if (editMsgId) {
map.emplace( map.emplace(
@ -1489,9 +1520,9 @@ void Account::readDraftsWithCursorsLegacy(
editData, editData,
FullReplyTo{ FullMsgId(peerId, editMsgId) }, FullReplyTo{ FullMsgId(peerId, editMsgId) },
MessageCursor(), MessageCursor(),
(editPreviewCancelled Data::WebPageDraft{
? Data::PreviewState::Cancelled .removed = (editPreviewCancelled == 1),
: Data::PreviewState::Allowed))); }));
} }
readDraftCursors(peerId, map); readDraftCursors(peerId, map);
history->setDraftsMap(std::move(map)); history->setDraftsMap(std::move(map));

View File

@ -53,7 +53,7 @@ enum class StartResult : uchar;
struct MessageDraft { struct MessageDraft {
FullReplyTo reply; FullReplyTo reply;
TextWithTags textWithTags; TextWithTags textWithTags;
Data::PreviewState previewState = Data::PreviewState::Allowed; Data::WebPageDraft webpage;
}; };
struct MessageDraftSource { struct MessageDraftSource {

View File

@ -161,7 +161,7 @@ Data::Draft OccupiedDraft(const QString &normalizedName) {
+ normalizedName }, + normalizedName },
FullReplyTo(), FullReplyTo(),
MessageCursor(), MessageCursor(),
Data::PreviewState::Allowed Data::WebPageDraft()
}; };
} }

View File

@ -1073,7 +1073,7 @@ void Manager::notificationActivated(
int(reply.text.size()), int(reply.text.size()),
Ui::kQFixedMax, Ui::kQFixedMax,
}, },
Data::PreviewState::Allowed); Data::WebPageDraft());
history->setLocalDraft(std::move(draft)); history->setLocalDraft(std::move(draft));
} }
window->widget()->showFromTray(); window->widget()->showFromTray();

View File

@ -787,7 +787,7 @@ void SessionNavigation::applyBoostChecked(
MTP_flags(0), MTP_flags(0),
MTPVector<MTPint>(), // slots MTPVector<MTPint>(), // slots
channel->input channel->input
)).done([=](const MTPBool &result) { )).done([=](const MTPpremium_MyBoosts &result) {
done(true); done(true);
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
showToast(u"Error: "_q + error.type()); showToast(u"Error: "_q + error.type());
@ -1556,7 +1556,7 @@ bool SessionController::switchInlineQuery(
textWithTags, textWithTags,
to.currentReplyTo, to.currentReplyTo,
cursor, cursor,
Data::PreviewState::Allowed); Data::WebPageDraft());
auto params = Window::SectionShow(); auto params = Window::SectionShow();
params.reapplyLocalDraft = true; params.reapplyLocalDraft = true;