mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-25 01:50:36 +00:00
Allow sending custom webpage previews.
This commit is contained in:
parent
b1823d981b
commit
8b42161898
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_drafts.h"
|
||||
|
||||
class History;
|
||||
|
||||
namespace Data {
|
||||
@ -22,7 +24,6 @@ struct SendOptions {
|
||||
TimeId scheduled = 0;
|
||||
bool silent = false;
|
||||
bool handleSupportSwitch = false;
|
||||
bool removeWebPageId = false;
|
||||
bool hideViaBot = false;
|
||||
};
|
||||
[[nodiscard]] SendOptions DefaultSendWhenOnlineOptions();
|
||||
@ -54,7 +55,7 @@ struct MessageToSend {
|
||||
|
||||
SendAction action;
|
||||
TextWithTags textWithTags;
|
||||
WebPageId webPageId = 0;
|
||||
Data::WebPageDraft webPage;
|
||||
};
|
||||
|
||||
struct RemoteFileInfo {
|
||||
|
@ -11,8 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_media.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "lang/lang_keys.h"
|
||||
@ -45,6 +47,7 @@ template <typename DoneCallback, typename FailCallback>
|
||||
mtpRequestId EditMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
const TextWithEntities &textWithEntities,
|
||||
Data::WebPageDraft webpage,
|
||||
SendOptions options,
|
||||
DoneCallback &&done,
|
||||
FailCallback &&fail,
|
||||
@ -71,9 +74,15 @@ mtpRequestId EditMessage(
|
||||
| ((media && inputMedia.has_value())
|
||||
? MTPmessages_EditMessage::Flag::f_media
|
||||
: emptyFlag)
|
||||
| (options.removeWebPageId
|
||||
| (webpage.removed
|
||||
? MTPmessages_EditMessage::Flag::f_no_webpage
|
||||
: emptyFlag)
|
||||
| ((!webpage.removed && !webpage.url.isEmpty())
|
||||
? MTPmessages_EditMessage::Flag::f_media
|
||||
: emptyFlag)
|
||||
| ((!webpage.removed && !webpage.url.isEmpty() && webpage.invert)
|
||||
? MTPmessages_EditMessage::Flag::f_invert_media
|
||||
: emptyFlag)
|
||||
| (!sentEntities.v.isEmpty()
|
||||
? MTPmessages_EditMessage::Flag::f_entities
|
||||
: emptyFlag)
|
||||
@ -89,7 +98,7 @@ mtpRequestId EditMessage(
|
||||
item->history()->peer->input,
|
||||
MTP_int(id),
|
||||
MTP_string(text),
|
||||
inputMedia.value_or(MTPInputMedia()),
|
||||
inputMedia.value_or(Data::WebPageForMTP(webpage)),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(options.scheduled)
|
||||
@ -133,9 +142,15 @@ mtpRequestId EditMessage(
|
||||
FailCallback &&fail,
|
||||
std::optional<MTPInputMedia> inputMedia = std::nullopt) {
|
||||
const auto &text = item->originalText();
|
||||
const auto webpage = (!item->media() || !item->media()->webpage())
|
||||
? Data::WebPageDraft{ .removed = true }
|
||||
: Data::WebPageDraft{
|
||||
.id = item->media()->webpage()->id,
|
||||
};
|
||||
return EditMessage(
|
||||
item,
|
||||
text,
|
||||
webpage,
|
||||
options,
|
||||
std::forward<DoneCallback>(done),
|
||||
std::forward<FailCallback>(fail),
|
||||
@ -216,12 +231,19 @@ mtpRequestId EditCaption(
|
||||
SendOptions options,
|
||||
Fn<void()> done,
|
||||
Fn<void(const QString &)> fail) {
|
||||
return EditMessage(item, caption, options, done, fail);
|
||||
return EditMessage(
|
||||
item,
|
||||
caption,
|
||||
Data::WebPageDraft(),
|
||||
options,
|
||||
done,
|
||||
fail);
|
||||
}
|
||||
|
||||
mtpRequestId EditTextMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
const TextWithEntities &caption,
|
||||
Data::WebPageDraft webpage,
|
||||
SendOptions options,
|
||||
Fn<void(mtpRequestId requestId)> done,
|
||||
Fn<void(const QString &, mtpRequestId requestId)> fail) {
|
||||
@ -229,7 +251,7 @@ mtpRequestId EditTextMessage(
|
||||
applyUpdates();
|
||||
done(id);
|
||||
};
|
||||
return EditMessage(item, caption, options, callback, fail);
|
||||
return EditMessage(item, caption, webpage, options, callback, fail);
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
class HistoryItem;
|
||||
|
||||
namespace Data {
|
||||
struct WebPageDraft;
|
||||
} // namespace Data
|
||||
|
||||
namespace MTP {
|
||||
class Error;
|
||||
} // namespace MTP
|
||||
@ -48,6 +52,7 @@ mtpRequestId EditCaption(
|
||||
mtpRequestId EditTextMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
const TextWithEntities &caption,
|
||||
Data::WebPageDraft webpage,
|
||||
SendOptions options,
|
||||
Fn<void(mtpRequestId requestId)> done,
|
||||
Fn<void(const QString &error, mtpRequestId requestId)> fail);
|
||||
|
@ -2159,15 +2159,7 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
history->peer->input,
|
||||
MTP_string(textWithTags.text),
|
||||
entities,
|
||||
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))
|
||||
Data::WebPageForMTP(cloudDraft->webpage)
|
||||
)).done([=](const MTPBool &result, const MTP::Response &response) {
|
||||
const auto requestId = response.requestId;
|
||||
history->finishSavingCloudDraft(
|
||||
@ -3630,29 +3622,48 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
MTPstring msgText(MTP_string(sending.text));
|
||||
auto flags = NewMessageFlags(peer);
|
||||
auto sendFlags = MTPmessages_SendMessage::Flags(0);
|
||||
auto mediaFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (action.replyTo) {
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to;
|
||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
||||
}
|
||||
const auto replyHeader = NewMessageReplyHeader(action);
|
||||
MTPMessageMedia media = MTP_messageMediaEmpty();
|
||||
if (message.webPageId == CancelledWebPageId) {
|
||||
if (message.webPage.removed) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage;
|
||||
} else if (message.webPageId) {
|
||||
auto page = _session->data().webpage(message.webPageId);
|
||||
} else if (const auto fields = message.webPage; fields.id) {
|
||||
using PageFlag = MTPDmessageMediaWebPage::Flag;
|
||||
using PendingFlag = MTPDwebPagePending::Flag;
|
||||
const auto page = _session->data().webpage(fields.id);
|
||||
media = MTP_messageMediaWebPage(
|
||||
MTP_flags(0),
|
||||
MTP_flags(PageFlag()
|
||||
| (fields.manual ? PageFlag::f_manual : PageFlag())
|
||||
| (fields.forceLargeMedia
|
||||
? PageFlag::f_force_large_media
|
||||
: PageFlag())
|
||||
| (fields.forceSmallMedia
|
||||
? PageFlag::f_force_small_media
|
||||
: PageFlag())),
|
||||
MTP_webPagePending(
|
||||
MTP_flags(0),
|
||||
MTP_flags(page->url.isEmpty()
|
||||
? PendingFlag()
|
||||
: PendingFlag::f_url),
|
||||
MTP_long(page->id),
|
||||
MTPstring(), // url
|
||||
MTP_string(page->url),
|
||||
MTP_int(page->pendingTill)));
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (message.webPage.id && message.webPage.invert) {
|
||||
flags |= MessageFlag::InvertMedia;
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_invert_media;
|
||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
||||
}
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
|
||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
const auto sentEntities = Api::EntitiesToMTP(
|
||||
_session,
|
||||
@ -3665,6 +3676,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
const auto topicRootId = action.replyTo.topicRootId;
|
||||
if (clearCloudDraft) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
|
||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
||||
history->clearCloudDraft(topicRootId);
|
||||
history->startSavingCloudDraft(topicRootId);
|
||||
}
|
||||
@ -3676,6 +3688,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
: _session->userPeerId();
|
||||
if (sendAs) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_send_as;
|
||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||
}
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? _session->user()->name()
|
||||
@ -3683,6 +3696,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
if (action.options.scheduled) {
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
|
||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||
}
|
||||
const auto viaBotId = UserId();
|
||||
lastMessage = history->addNewLocalMessage(
|
||||
@ -3696,27 +3710,18 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
sending,
|
||||
media,
|
||||
HistoryMessageMarkupData());
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
action.replyTo,
|
||||
randomId,
|
||||
Data::Histories::PrepareMessage<MTPmessages_SendMessage>(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
Data::Histories::ReplyToPlaceholder(),
|
||||
msgText,
|
||||
MTP_long(randomId),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
const auto done = [=](
|
||||
const MTPUpdates &result,
|
||||
const MTP::Response &response) {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
};
|
||||
const auto fail = [=](
|
||||
const MTP::Error &error,
|
||||
const MTP::Response &response) {
|
||||
if (error.type() == u"MESSAGE_EMPTY"_q) {
|
||||
lastMessage->destroy();
|
||||
} else {
|
||||
@ -3727,7 +3732,44 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
topicRootId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
});
|
||||
};
|
||||
if (!message.webPage.removed
|
||||
&& (message.webPage.manual || sending.empty())
|
||||
&& !message.webPage.url.isEmpty()) {
|
||||
using PageFlag = MTPDinputMediaWebPage::Flag;
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
action.replyTo,
|
||||
randomId,
|
||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||
MTP_flags(mediaFlags),
|
||||
peer->input,
|
||||
Data::Histories::ReplyToPlaceholder(),
|
||||
Data::WebPageForMTP(message.webPage),
|
||||
msgText,
|
||||
MTP_long(randomId),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(message.action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||
), done, fail);
|
||||
} else {
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
action.replyTo,
|
||||
randomId,
|
||||
Data::Histories::PrepareMessage<MTPmessages_SendMessage>(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
Data::Histories::ReplyToPlaceholder(),
|
||||
msgText,
|
||||
MTP_long(randomId),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||
), done, fail);
|
||||
}
|
||||
}
|
||||
|
||||
finishForwarding(action);
|
||||
|
@ -74,6 +74,15 @@ MTPInputReplyTo ReplyToForMTP(
|
||||
return MTPInputReplyTo();
|
||||
}
|
||||
|
||||
MTPInputMedia WebPageForMTP(const Data::WebPageDraft &draft) {
|
||||
using Flag = MTPDinputMediaWebPage::Flag;
|
||||
return MTP_inputMediaWebPage(
|
||||
MTP_flags(Flag::f_optional
|
||||
| (draft.forceLargeMedia ? Flag::f_force_large_media : Flag())
|
||||
| (draft.forceSmallMedia ? Flag::f_force_small_media : Flag())),
|
||||
MTP_string(draft.url));
|
||||
}
|
||||
|
||||
Histories::Histories(not_null<Session*> owner)
|
||||
: _owner(owner)
|
||||
, _readRequestsTimer([=] { sendReadRequests(); }) {
|
||||
|
@ -25,10 +25,12 @@ namespace Data {
|
||||
|
||||
class Session;
|
||||
class Folder;
|
||||
struct WebPageDraft;
|
||||
|
||||
[[nodiscard]] MTPInputReplyTo ReplyToForMTP(
|
||||
not_null<History*> history,
|
||||
FullReplyTo replyTo);
|
||||
[[nodiscard]] MTPInputMedia WebPageForMTP(const Data::WebPageDraft &draft);
|
||||
|
||||
class Histories final {
|
||||
public:
|
||||
|
@ -1500,10 +1500,13 @@ bool MediaWebPage::replyPreviewLoaded() const {
|
||||
}
|
||||
|
||||
ItemPreview MediaWebPage::toPreview(ToPreviewOptions options) const {
|
||||
return { .text = options.translated
|
||||
auto text = options.translated
|
||||
? parent()->translatedText()
|
||||
: parent()->originalText()
|
||||
};
|
||||
: parent()->originalText();
|
||||
if (text.empty()) {
|
||||
text = Ui::Text::Colorized(_page->url);
|
||||
}
|
||||
return { .text = text };
|
||||
}
|
||||
|
||||
TextWithEntities MediaWebPage::notificationText() const {
|
||||
|
@ -3260,6 +3260,7 @@ not_null<WebPageData*> Session::processWebpage(const MTPWebPage &data) {
|
||||
return processWebpage(data.c_webPage());
|
||||
case mtpc_webPageEmpty: {
|
||||
const auto result = webpage(data.c_webPageEmpty().vid().v);
|
||||
result->type = WebPageType::None;
|
||||
if (result->pendingTill > 0) {
|
||||
result->pendingTill = 0;
|
||||
result->failed = 1;
|
||||
@ -3283,13 +3284,13 @@ not_null<WebPageData*> Session::processWebpage(const MTPDwebPage &data) {
|
||||
return result;
|
||||
}
|
||||
|
||||
not_null<WebPageData*> Session::processWebpage(const MTPDwebPagePending &data) {
|
||||
not_null<WebPageData*> Session::processWebpage(
|
||||
const MTPDwebPagePending &data) {
|
||||
constexpr auto kDefaultPendingTimeout = 60;
|
||||
const auto result = webpage(data.vid().v);
|
||||
webpageApplyFields(
|
||||
result,
|
||||
WebPageType::Article,
|
||||
false,
|
||||
WebPageType::None,
|
||||
QString(),
|
||||
QString(),
|
||||
QString(),
|
||||
@ -3301,6 +3302,7 @@ not_null<WebPageData*> Session::processWebpage(const MTPDwebPagePending &data) {
|
||||
WebPageCollage(),
|
||||
0,
|
||||
QString(),
|
||||
false,
|
||||
data.vdate().v
|
||||
? data.vdate().v
|
||||
: (base::unixtime::now() + kDefaultPendingTimeout));
|
||||
@ -3314,7 +3316,6 @@ not_null<WebPageData*> Session::webpage(
|
||||
return webpage(
|
||||
id,
|
||||
WebPageType::Article,
|
||||
false,
|
||||
QString(),
|
||||
QString(),
|
||||
siteName,
|
||||
@ -3325,13 +3326,13 @@ not_null<WebPageData*> Session::webpage(
|
||||
WebPageCollage(),
|
||||
0,
|
||||
QString(),
|
||||
false,
|
||||
TimeId(0));
|
||||
}
|
||||
|
||||
not_null<WebPageData*> Session::webpage(
|
||||
WebPageId id,
|
||||
WebPageType type,
|
||||
bool hasLargeMedia,
|
||||
const QString &url,
|
||||
const QString &displayUrl,
|
||||
const QString &siteName,
|
||||
@ -3342,12 +3343,12 @@ not_null<WebPageData*> Session::webpage(
|
||||
WebPageCollage &&collage,
|
||||
int duration,
|
||||
const QString &author,
|
||||
bool hasLargeMedia,
|
||||
TimeId pendingTill) {
|
||||
const auto result = webpage(id);
|
||||
webpageApplyFields(
|
||||
result,
|
||||
type,
|
||||
hasLargeMedia,
|
||||
url,
|
||||
displayUrl,
|
||||
siteName,
|
||||
@ -3359,6 +3360,7 @@ not_null<WebPageData*> Session::webpage(
|
||||
std::move(collage),
|
||||
duration,
|
||||
author,
|
||||
hasLargeMedia,
|
||||
pendingTill);
|
||||
return result;
|
||||
}
|
||||
@ -3439,7 +3441,6 @@ void Session::webpageApplyFields(
|
||||
webpageApplyFields(
|
||||
page,
|
||||
(story ? WebPageType::Story : ParseWebPageType(data)),
|
||||
data.is_has_large_media(),
|
||||
qs(data.vurl()),
|
||||
qs(data.vdisplay_url()),
|
||||
siteName,
|
||||
@ -3459,13 +3460,13 @@ void Session::webpageApplyFields(
|
||||
WebPageCollage(this, data),
|
||||
data.vduration().value_or_empty(),
|
||||
qs(data.vauthor().value_or_empty()),
|
||||
data.is_has_large_media(),
|
||||
pendingTill);
|
||||
}
|
||||
|
||||
void Session::webpageApplyFields(
|
||||
not_null<WebPageData*> page,
|
||||
WebPageType type,
|
||||
bool hasLargeMedia,
|
||||
const QString &url,
|
||||
const QString &displayUrl,
|
||||
const QString &siteName,
|
||||
@ -3477,11 +3478,11 @@ void Session::webpageApplyFields(
|
||||
WebPageCollage &&collage,
|
||||
int duration,
|
||||
const QString &author,
|
||||
bool hasLargeMedia,
|
||||
TimeId pendingTill) {
|
||||
const auto requestPending = (!page->pendingTill && pendingTill > 0);
|
||||
const auto changed = page->applyChanges(
|
||||
type,
|
||||
hasLargeMedia,
|
||||
url,
|
||||
displayUrl,
|
||||
siteName,
|
||||
@ -3493,6 +3494,7 @@ void Session::webpageApplyFields(
|
||||
std::move(collage),
|
||||
duration,
|
||||
author,
|
||||
hasLargeMedia,
|
||||
pendingTill);
|
||||
if (requestPending) {
|
||||
_session->api().requestWebPageDelayed(page);
|
||||
|
@ -552,7 +552,6 @@ public:
|
||||
[[nodiscard]] not_null<WebPageData*> webpage(
|
||||
WebPageId id,
|
||||
WebPageType type,
|
||||
bool hasLargeMedia,
|
||||
const QString &url,
|
||||
const QString &displayUrl,
|
||||
const QString &siteName,
|
||||
@ -563,6 +562,7 @@ public:
|
||||
WebPageCollage &&collage,
|
||||
int duration,
|
||||
const QString &author,
|
||||
bool hasLargeMedia,
|
||||
TimeId pendingTill);
|
||||
|
||||
[[nodiscard]] not_null<GameData*> game(GameId id);
|
||||
@ -814,7 +814,6 @@ private:
|
||||
void webpageApplyFields(
|
||||
not_null<WebPageData*> page,
|
||||
WebPageType type,
|
||||
bool hasLargeMedia,
|
||||
const QString &url,
|
||||
const QString &displayUrl,
|
||||
const QString &siteName,
|
||||
@ -826,6 +825,7 @@ private:
|
||||
WebPageCollage &&collage,
|
||||
int duration,
|
||||
const QString &author,
|
||||
bool hasLargeMedia,
|
||||
TimeId pendingTill);
|
||||
|
||||
void gameApplyFields(
|
||||
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_document.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/text/text_entity.h"
|
||||
|
||||
@ -213,7 +214,6 @@ Main::Session &WebPageData::session() const {
|
||||
|
||||
bool WebPageData::applyChanges(
|
||||
WebPageType newType,
|
||||
bool newHasLargeMedia,
|
||||
const QString &newUrl,
|
||||
const QString &newDisplayUrl,
|
||||
const QString &newSiteName,
|
||||
@ -225,6 +225,7 @@ bool WebPageData::applyChanges(
|
||||
WebPageCollage &&newCollage,
|
||||
int newDuration,
|
||||
const QString &newAuthor,
|
||||
bool newHasLargeMedia,
|
||||
int newPendingTill) {
|
||||
if (newPendingTill != 0
|
||||
&& (!url.isEmpty() || failed)
|
||||
@ -255,7 +256,6 @@ bool WebPageData::applyChanges(
|
||||
}();
|
||||
|
||||
if (type == newType
|
||||
&& hasLargeMedia == newHasLargeMedia
|
||||
&& url == resultUrl
|
||||
&& displayUrl == resultDisplayUrl
|
||||
&& siteName == resultSiteName
|
||||
@ -267,6 +267,7 @@ bool WebPageData::applyChanges(
|
||||
&& collage.items == newCollage.items
|
||||
&& duration == newDuration
|
||||
&& author == resultAuthor
|
||||
&& hasLargeMedia == (newHasLargeMedia ? 1 : 0)
|
||||
&& pendingTill == newPendingTill) {
|
||||
return false;
|
||||
}
|
||||
@ -274,7 +275,7 @@ bool WebPageData::applyChanges(
|
||||
_owner->session().api().clearWebPageRequest(this);
|
||||
}
|
||||
type = newType;
|
||||
hasLargeMedia = newHasLargeMedia;
|
||||
hasLargeMedia = newHasLargeMedia ? 1 : 0;
|
||||
url = resultUrl;
|
||||
displayUrl = resultDisplayUrl;
|
||||
siteName = resultSiteName;
|
||||
@ -346,3 +347,11 @@ void WebPageData::ApplyChanges(
|
||||
}
|
||||
session->data().sendWebPageGamePollNotifications();
|
||||
}
|
||||
|
||||
QString WebPageData::displayedSiteName() const {
|
||||
return (document && document->isWallPaper())
|
||||
? tr::lng_media_chat_background(tr::now)
|
||||
: (document && document->isTheme())
|
||||
? tr::lng_media_color_theme(tr::now)
|
||||
: siteName;
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ class Session;
|
||||
} // namespace Data
|
||||
|
||||
enum class WebPageType : uint8 {
|
||||
None,
|
||||
|
||||
Message,
|
||||
|
||||
Group,
|
||||
@ -67,7 +69,6 @@ struct WebPageData {
|
||||
|
||||
bool applyChanges(
|
||||
WebPageType newType,
|
||||
bool newHasLargeMedia,
|
||||
const QString &newUrl,
|
||||
const QString &newDisplayUrl,
|
||||
const QString &newSiteName,
|
||||
@ -79,6 +80,7 @@ struct WebPageData {
|
||||
WebPageCollage &&newCollage,
|
||||
int newDuration,
|
||||
const QString &newAuthor,
|
||||
bool newHasLargeMedia,
|
||||
int newPendingTill);
|
||||
|
||||
static void ApplyChanges(
|
||||
@ -86,9 +88,10 @@ struct WebPageData {
|
||||
ChannelData *channel,
|
||||
const MTPmessages_Messages &result);
|
||||
|
||||
WebPageId id = 0;
|
||||
WebPageType type = WebPageType::Article;
|
||||
bool hasLargeMedia = false;
|
||||
[[nodiscard]] QString displayedSiteName() const;
|
||||
|
||||
const WebPageId id = 0;
|
||||
WebPageType type = WebPageType::None;
|
||||
QString url;
|
||||
QString displayUrl;
|
||||
QString siteName;
|
||||
@ -101,7 +104,8 @@ struct WebPageData {
|
||||
WebPageCollage collage;
|
||||
int duration = 0;
|
||||
TimeId pendingTill = 0;
|
||||
uint32 version : 31 = 0;
|
||||
uint32 version : 30 = 0;
|
||||
uint32 hasLargeMedia : 1 = 0;
|
||||
uint32 failed : 1 = 0;
|
||||
|
||||
private:
|
||||
|
@ -1509,6 +1509,11 @@ void HistoryItem::applyEdition(HistoryMessageEdition &&edition) {
|
||||
} else {
|
||||
_flags &= ~MessageFlag::HideEdited;
|
||||
}
|
||||
if (edition.invertMedia) {
|
||||
_flags |= MessageFlag::InvertMedia;
|
||||
} else {
|
||||
_flags &= ~MessageFlag::InvertMedia;
|
||||
}
|
||||
|
||||
if (edition.editDate != -1) {
|
||||
//_flags |= MTPDmessage::Flag::f_edit_date;
|
||||
|
@ -29,6 +29,7 @@ HistoryMessageEdition::HistoryMessageEdition(
|
||||
if (const auto mtpReplies = message.vreplies()) {
|
||||
replies = HistoryMessageRepliesData(mtpReplies);
|
||||
}
|
||||
invertMedia = message.is_invert_media();
|
||||
|
||||
const auto period = message.vttl_period();
|
||||
ttl = (period && period->v > 0) ? (message.vdate().v + period->v) : 0;
|
||||
|
@ -30,6 +30,7 @@ struct HistoryMessageEdition {
|
||||
bool useSameMarkup = false;
|
||||
bool useSameReactions = false;
|
||||
bool savePreviousMedia = false;
|
||||
bool invertMedia = false;
|
||||
TextWithEntities textWithEntities;
|
||||
HistoryMessageMarkupData replyMarkup;
|
||||
HistoryMessageRepliesData replies;
|
||||
|
@ -2149,6 +2149,7 @@ void HistoryWidget::showHistory(
|
||||
_photoEditMedia = nullptr;
|
||||
updateReplaceMediaButton();
|
||||
_previewData = nullptr;
|
||||
_previewDraft = {};
|
||||
_previewCache.clear();
|
||||
_fieldBarCancel->hide();
|
||||
|
||||
@ -3761,12 +3762,6 @@ void HistoryWidget::saveEditMsg() {
|
||||
cancelEdit();
|
||||
return;
|
||||
}
|
||||
const auto webPageId = _previewDraft.removed
|
||||
? CancelledWebPageId
|
||||
: (_previewData && !_previewData->failed)
|
||||
? _previewData->id
|
||||
: WebPageId();
|
||||
|
||||
const auto textWithTags = _field->getTextWithAppliedMarkdown();
|
||||
const auto prepareFlags = Ui::ItemTextOptions(
|
||||
_history,
|
||||
@ -3833,10 +3828,10 @@ void HistoryWidget::saveEditMsg() {
|
||||
};
|
||||
|
||||
auto options = Api::SendOptions();
|
||||
options.removeWebPageId = (webPageId == CancelledWebPageId);
|
||||
_saveEditMsgRequestId = Api::EditTextMessage(
|
||||
item,
|
||||
sending,
|
||||
_previewDraft,
|
||||
options,
|
||||
done,
|
||||
fail);
|
||||
@ -3920,15 +3915,9 @@ void HistoryWidget::send(Api::SendOptions options) {
|
||||
_cornerButtons.clearReplyReturns();
|
||||
}
|
||||
|
||||
const auto webPageId = _previewDraft.removed
|
||||
? CancelledWebPageId
|
||||
: (_previewData && !_previewData->failed)
|
||||
? _previewData->id
|
||||
: WebPageId();
|
||||
|
||||
auto message = Api::MessageToSend(prepareSendAction(options));
|
||||
message.textWithTags = _field->getTextWithAppliedMarkdown();
|
||||
message.webPageId = webPageId;
|
||||
message.webPage = _previewDraft;
|
||||
|
||||
const auto ignoreSlowmodeCountdown = (options.scheduled != 0);
|
||||
if (showSendMessageError(
|
||||
@ -4338,23 +4327,23 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
|
||||
void HistoryWidget::updateOverStates(QPoint pos) {
|
||||
const auto isReadyToForward = readyToForward();
|
||||
const auto skip = isReadyToForward ? 0 : st::historyReplySkip;
|
||||
const auto replyEditForwardInfoRect = QRect(
|
||||
const auto detailsRect = QRect(
|
||||
skip,
|
||||
_field->y() - st::historySendPadding - st::historyReplyHeight,
|
||||
width() - skip - _fieldBarCancel->width(),
|
||||
st::historyReplyHeight);
|
||||
auto inReplyEditForward = (_editMsgId || replyTo() || isReadyToForward)
|
||||
&& replyEditForwardInfoRect.contains(pos);
|
||||
auto inPhotoEdit = inReplyEditForward
|
||||
const auto hasWebPage = _previewData && !_previewData->failed;
|
||||
const auto inDetails = detailsRect.contains(pos)
|
||||
&& (_editMsgId || replyTo() || isReadyToForward || hasWebPage);
|
||||
const auto inPhotoEdit = inDetails
|
||||
&& _photoEditMedia
|
||||
&& QRect(
|
||||
replyEditForwardInfoRect.x(),
|
||||
(replyEditForwardInfoRect.y()
|
||||
+ (replyEditForwardInfoRect.height()
|
||||
- st::historyReplyPreview) / 2),
|
||||
detailsRect.x(),
|
||||
(detailsRect.y()
|
||||
+ (detailsRect.height() - st::historyReplyPreview) / 2),
|
||||
st::historyReplyPreview,
|
||||
st::historyReplyPreview).contains(pos);
|
||||
auto inClickable = inReplyEditForward;
|
||||
const auto inClickable = inDetails;
|
||||
if (_inPhotoEdit != inPhotoEdit) {
|
||||
_inPhotoEdit = inPhotoEdit;
|
||||
if (_photoEditMedia) {
|
||||
@ -4367,7 +4356,7 @@ void HistoryWidget::updateOverStates(QPoint pos) {
|
||||
_inPhotoEditOver.stop();
|
||||
}
|
||||
}
|
||||
_inReplyEditForward = inReplyEditForward && !inPhotoEdit;
|
||||
_inDetails = inDetails && !inPhotoEdit;
|
||||
if (inClickable != _inClickable) {
|
||||
_inClickable = inClickable;
|
||||
setCursor(_inClickable ? style::cur_pointer : style::cur_default);
|
||||
@ -4605,6 +4594,9 @@ bool HistoryWidget::showRecordButton() const {
|
||||
&& !_voiceRecordBar->isListenState()
|
||||
&& !_voiceRecordBar->isRecordingByAnotherBar()
|
||||
&& !HasSendText(_field)
|
||||
&& (!_previewData
|
||||
|| _previewData->failed
|
||||
|| _previewData->pendingTill)
|
||||
&& !readyToForward()
|
||||
&& !_editMsgId;
|
||||
}
|
||||
@ -6224,42 +6216,43 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
||||
{ _history->peer->id, _editMsgId },
|
||||
_field->getTextWithTags(),
|
||||
crl::guard(_list, [=] { cancelEdit(); }));
|
||||
} else if (_inReplyEditForward) {
|
||||
if (isReadyToForward) {
|
||||
if (e->button() != Qt::LeftButton) {
|
||||
_forwardPanel->editToNextOption();
|
||||
} else {
|
||||
_forwardPanel->editOptions(controller()->uiShow());
|
||||
}
|
||||
} else if (const auto reply = replyTo()) {
|
||||
const auto highlight = [=] {
|
||||
controller()->showPeerHistory(
|
||||
reply.messageId.peer,
|
||||
Window::SectionShow::Way::Forward,
|
||||
reply.messageId.msg);
|
||||
};
|
||||
const auto history = _history;
|
||||
using namespace HistoryView::Controls;
|
||||
EditReplyOptions(
|
||||
controller()->uiShow(),
|
||||
reply,
|
||||
highlight,
|
||||
[=] { ClearDraftReplyTo(history, reply.messageId); });
|
||||
} else if (_editMsgId) {
|
||||
controller()->showPeerHistory(
|
||||
_peer,
|
||||
Window::SectionShow::Way::Forward,
|
||||
_editMsgId);
|
||||
} else if (_previewData
|
||||
&& !_previewData->failed
|
||||
&& !_previewData->pendingTill) {
|
||||
//const auto history = _history;
|
||||
//using namespace HistoryView::Controls;
|
||||
//EditWebPageOptions(
|
||||
// controller()->uiShow(),
|
||||
// _previewData,
|
||||
// _previewDraft);
|
||||
} else if (!_inDetails) {
|
||||
return;
|
||||
} else if (_previewData
|
||||
&& !_previewData->failed
|
||||
&& !_previewData->pendingTill) {
|
||||
const auto history = _history;
|
||||
using namespace HistoryView::Controls;
|
||||
EditWebPageOptions(
|
||||
controller()->uiShow(),
|
||||
_previewData,
|
||||
_previewDraft,
|
||||
[=](Data::WebPageDraft draft) { applyPreview(draft); });
|
||||
} else if (isReadyToForward) {
|
||||
if (e->button() != Qt::LeftButton) {
|
||||
_forwardPanel->editToNextOption();
|
||||
} else {
|
||||
_forwardPanel->editOptions(controller()->uiShow());
|
||||
}
|
||||
} else if (const auto reply = replyTo()) {
|
||||
const auto highlight = [=] {
|
||||
controller()->showPeerHistory(
|
||||
reply.messageId.peer,
|
||||
Window::SectionShow::Way::Forward,
|
||||
reply.messageId.msg);
|
||||
};
|
||||
const auto history = _history;
|
||||
using namespace HistoryView::Controls;
|
||||
EditReplyOptions(
|
||||
controller()->uiShow(),
|
||||
reply,
|
||||
highlight,
|
||||
[=] { ClearDraftReplyTo(history, reply.messageId); });
|
||||
} else if (_editMsgId) {
|
||||
controller()->showPeerHistory(
|
||||
_peer,
|
||||
Window::SectionShow::Way::Forward,
|
||||
_editMsgId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7073,8 +7066,10 @@ void HistoryWidget::setFieldText(
|
||||
_textUpdateEvents = TextUpdateEvent::SaveDraft
|
||||
| TextUpdateEvent::SendTyping;
|
||||
|
||||
previewCancel();
|
||||
_previewDraft = {};
|
||||
if (!_previewDraft.manual) {
|
||||
previewCancel();
|
||||
_previewDraft = {};
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::clearFieldText(
|
||||
@ -7424,12 +7419,7 @@ void HistoryWidget::cancelFieldAreaState() {
|
||||
controller()->hideLayer();
|
||||
_replyForwardPressed = false;
|
||||
if (_previewData && !_previewData->failed) {
|
||||
_previewDraft = { .removed = true };
|
||||
previewCancel();
|
||||
|
||||
_saveDraftText = true;
|
||||
_saveDraftStart = crl::now();
|
||||
saveDraft();
|
||||
applyPreview({ .removed = true });
|
||||
} else if (_editMsgId) {
|
||||
cancelEdit();
|
||||
} else if (readyToForward()) {
|
||||
@ -7441,6 +7431,20 @@ void HistoryWidget::cancelFieldAreaState() {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::applyPreview(Data::WebPageDraft draft) {
|
||||
_previewDraft = draft;
|
||||
if (draft.removed) {
|
||||
previewCancel();
|
||||
} else if (draft.id) {
|
||||
_previewData = session().data().webpage(draft.id).get();
|
||||
requestPreview();
|
||||
}
|
||||
|
||||
_saveDraftText = true;
|
||||
_saveDraftStart = crl::now();
|
||||
saveDraft();
|
||||
}
|
||||
|
||||
void HistoryWidget::previewCancel() {
|
||||
_api.request(base::take(_previewRequest)).cancel();
|
||||
_previewData = nullptr;
|
||||
@ -7455,6 +7459,8 @@ void HistoryWidget::checkPreview() {
|
||||
if (_previewDraft.removed || previewRestricted) {
|
||||
previewCancel();
|
||||
return;
|
||||
} else if (_previewDraft.manual) {
|
||||
return;
|
||||
}
|
||||
const auto links = _parsedLinks.join(' ');
|
||||
if (_previewLinks != links) {
|
||||
@ -7476,6 +7482,8 @@ void HistoryWidget::checkPreview() {
|
||||
}).send();
|
||||
} else if (i.value()) {
|
||||
_previewData = session().data().webpage(i.value());
|
||||
_previewDraft.id = _previewData->id;
|
||||
_previewDraft.url = _previewData->url;
|
||||
updatePreview();
|
||||
} else if (_previewData && !_previewData->failed) {
|
||||
previewCancel();
|
||||
@ -7518,6 +7526,12 @@ void HistoryWidget::gotPreview(
|
||||
_previewData = (page->id && !page->failed)
|
||||
? page.get()
|
||||
: nullptr;
|
||||
if (_previewData) {
|
||||
_previewDraft.id = _previewData->id;
|
||||
_previewDraft.url = _previewData->url;
|
||||
} else {
|
||||
_previewDraft = {};
|
||||
}
|
||||
updatePreview();
|
||||
}
|
||||
session().data().sendWebPageGamePollNotifications();
|
||||
@ -7525,6 +7539,7 @@ void HistoryWidget::gotPreview(
|
||||
_previewCache.insert(links, 0);
|
||||
if (links == _previewLinks && !_previewDraft.removed) {
|
||||
_previewData = nullptr;
|
||||
_previewDraft = {};
|
||||
updatePreview();
|
||||
}
|
||||
}
|
||||
|
@ -406,6 +406,7 @@ private:
|
||||
void startBotCommand();
|
||||
void hidePinnedMessage();
|
||||
void cancelFieldAreaState();
|
||||
void applyPreview(Data::WebPageDraft draft);
|
||||
void unblockUser();
|
||||
void sendBotStartCommand();
|
||||
void joinChannel();
|
||||
@ -759,7 +760,7 @@ private:
|
||||
object_ptr<Ui::InputField> _field;
|
||||
base::unique_qptr<Ui::RpWidget> _fieldDisabled;
|
||||
Ui::Animations::Simple _inPhotoEditOver;
|
||||
bool _inReplyEditForward = false;
|
||||
bool _inDetails = false;
|
||||
bool _inPhotoEdit = false;
|
||||
bool _inClickable = false;
|
||||
|
||||
|
@ -365,7 +365,7 @@ public:
|
||||
[[nodiscard]] rpl::producer<FullMsgId> scrollToItemRequests() const;
|
||||
[[nodiscard]] rpl::producer<> editPhotoRequests() const;
|
||||
[[nodiscard]] MessageToEdit queryToEdit();
|
||||
[[nodiscard]] WebPageId webPageId() const;
|
||||
[[nodiscard]] Data::WebPageDraft webPageDraft() const;
|
||||
|
||||
[[nodiscard]] FullReplyTo getDraftReply() const;
|
||||
[[nodiscard]] rpl::producer<> editCancelled() const {
|
||||
@ -399,6 +399,7 @@ private:
|
||||
|
||||
struct Preview {
|
||||
WebPageData *data = nullptr;
|
||||
Data::WebPageDraft draft;
|
||||
Ui::Text::String title;
|
||||
Ui::Text::String description;
|
||||
bool cancelled = false;
|
||||
@ -958,8 +959,10 @@ bool FieldHeader::hasPreview() const {
|
||||
return ShowWebPagePreview(_preview.data);
|
||||
}
|
||||
|
||||
WebPageId FieldHeader::webPageId() const {
|
||||
return hasPreview() ? _preview.data->id : CancelledWebPageId;
|
||||
Data::WebPageDraft FieldHeader::webPageDraft() const {
|
||||
return hasPreview()
|
||||
? Data::WebPageDraft{ .id = _preview.data->id }
|
||||
: Data::WebPageDraft{ .removed = true };
|
||||
}
|
||||
|
||||
FullReplyTo FieldHeader::getDraftReply() const {
|
||||
@ -1027,10 +1030,7 @@ MessageToEdit FieldHeader::queryToEdit() {
|
||||
}
|
||||
return {
|
||||
.fullId = item->fullId(),
|
||||
.options = {
|
||||
.scheduled = item->isScheduled() ? item->date() : 0,
|
||||
.removeWebPageId = !hasPreview(),
|
||||
},
|
||||
.options = { .scheduled = item->isScheduled() ? item->date() : 0 },
|
||||
};
|
||||
}
|
||||
|
||||
@ -3119,8 +3119,8 @@ void ComposeControls::initForwardProcess() {
|
||||
updateForwarding();
|
||||
}
|
||||
|
||||
WebPageId ComposeControls::webPageId() const {
|
||||
return _header->webPageId();
|
||||
Data::WebPageDraft ComposeControls::webPageDraft() const {
|
||||
return _header->webPageDraft();
|
||||
}
|
||||
|
||||
rpl::producer<Data::MessagePosition> ComposeControls::scrollRequests() const {
|
||||
|
@ -44,6 +44,7 @@ struct MessagePosition;
|
||||
struct Draft;
|
||||
class DraftKey;
|
||||
class PhotoMedia;
|
||||
struct WebPageDraft;
|
||||
} // namespace Data
|
||||
|
||||
namespace InlineBots {
|
||||
@ -207,7 +208,7 @@ public:
|
||||
void tryProcessKeyInput(not_null<QKeyEvent*> e);
|
||||
|
||||
[[nodiscard]] TextWithTags getTextWithAppliedMarkdown() const;
|
||||
[[nodiscard]] WebPageId webPageId() const;
|
||||
[[nodiscard]] Data::WebPageDraft webPageDraft() const;
|
||||
void setText(const TextWithTags &text);
|
||||
void clear();
|
||||
void hidePanelsAnimated();
|
||||
|
@ -547,4 +547,87 @@ void EditReplyOptions(
|
||||
}));
|
||||
}
|
||||
|
||||
void EditWebPageOptions(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<WebPageData*> webpage,
|
||||
Data::WebPageDraft draft,
|
||||
Fn<void(Data::WebPageDraft)> done) {
|
||||
show->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
box->setTitle(rpl::single(u"Link Preview"_q));
|
||||
|
||||
struct State {
|
||||
rpl::variable<Data::WebPageDraft> result;
|
||||
Ui::SettingsButton *large = nullptr;
|
||||
Ui::SettingsButton *small = nullptr;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>(State{
|
||||
.result = draft,
|
||||
});
|
||||
|
||||
state->large = Settings::AddButton(
|
||||
box->verticalLayout(),
|
||||
rpl::single(u"Force large media"_q),
|
||||
st::settingsButton,
|
||||
{ &st::menuIconMakeBig });
|
||||
state->large->setClickedCallback([=] {
|
||||
auto copy = state->result.current();
|
||||
copy.forceLargeMedia = true;
|
||||
copy.forceSmallMedia = false;
|
||||
state->result = copy;
|
||||
});
|
||||
|
||||
state->small = Settings::AddButton(
|
||||
box->verticalLayout(),
|
||||
rpl::single(u"Force small media"_q),
|
||||
st::settingsButton,
|
||||
{ &st::menuIconMakeSmall });
|
||||
state->small->setClickedCallback([=] {
|
||||
auto copy = state->result.current();
|
||||
copy.forceSmallMedia = true;
|
||||
copy.forceLargeMedia = false;
|
||||
state->result = copy;
|
||||
});
|
||||
|
||||
state->result.value(
|
||||
) | rpl::start_with_next([=](const Data::WebPageDraft &draft) {
|
||||
state->large->setColorOverride(draft.forceLargeMedia
|
||||
? st::windowActiveTextFg->c
|
||||
: std::optional<QColor>());
|
||||
state->small->setColorOverride(draft.forceSmallMedia
|
||||
? st::windowActiveTextFg->c
|
||||
: std::optional<QColor>());
|
||||
}, box->lifetime());
|
||||
|
||||
Settings::AddButton(
|
||||
box->verticalLayout(),
|
||||
state->result.value(
|
||||
) | rpl::map([=](const Data::WebPageDraft &draft) {
|
||||
return draft.invert
|
||||
? u"Above message"_q
|
||||
: u"Below message"_q;
|
||||
}),
|
||||
st::settingsButton,
|
||||
{ &st::menuIconChangeOrder }
|
||||
)->setClickedCallback([=] {
|
||||
auto copy = state->result.current();
|
||||
copy.invert = !copy.invert;
|
||||
state->result = copy;
|
||||
});
|
||||
|
||||
box->addButton(tr::lng_settings_save(), [=] {
|
||||
const auto weak = Ui::MakeWeak(box.get());
|
||||
auto result = state->result.current();
|
||||
result.manual = true;
|
||||
done(result);
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] {
|
||||
box->closeBox();
|
||||
});
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
} // namespace HistoryView::Controls
|
||||
|
@ -20,6 +20,7 @@ class SpoilerAnimation;
|
||||
|
||||
namespace Data {
|
||||
class Thread;
|
||||
struct WebPageDraft;
|
||||
} // namespace Data
|
||||
|
||||
namespace Window {
|
||||
@ -88,4 +89,10 @@ void EditReplyOptions(
|
||||
Fn<void()> highlight,
|
||||
Fn<void()> clearOldDraft = nullptr);
|
||||
|
||||
void EditWebPageOptions(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<WebPageData*> webpage,
|
||||
Data::WebPageDraft draft,
|
||||
Fn<void(Data::WebPageDraft)> done);
|
||||
|
||||
} // namespace HistoryView::Controls
|
||||
|
@ -539,9 +539,6 @@ bool AddRescheduleAction(
|
||||
if (!item || !item->isScheduled()) {
|
||||
continue;
|
||||
}
|
||||
if (!item->media() || !item->media()->webpage()) {
|
||||
options.removeWebPageId = true;
|
||||
}
|
||||
Api::RescheduleMessage(item, options);
|
||||
// Increase the scheduled date by 1s to keep the order.
|
||||
options.scheduled += 1;
|
||||
|
@ -2568,25 +2568,38 @@ void Message::updatePressed(QPoint point) {
|
||||
TextForMimeData Message::selectedText(TextSelection selection) const {
|
||||
const auto media = this->media();
|
||||
auto logEntryOriginalResult = TextForMimeData();
|
||||
const auto mediaDisplayed = (media && media->isDisplayed());
|
||||
const auto textSelection = (mediaDisplayed && invertMedia())
|
||||
? media->skipSelection(selection)
|
||||
: selection;
|
||||
const auto mediaSelection = !invertMedia()
|
||||
? skipTextSelection(selection)
|
||||
: selection;
|
||||
auto textResult = hasVisibleText()
|
||||
? text().toTextForMimeData(selection)
|
||||
? text().toTextForMimeData(textSelection)
|
||||
: TextForMimeData();
|
||||
auto skipped = skipTextSelection(selection);
|
||||
auto mediaDisplayed = (media && media->isDisplayed());
|
||||
auto mediaResult = (mediaDisplayed || isHiddenByGroup())
|
||||
? media->selectedText(skipped)
|
||||
? media->selectedText(mediaSelection)
|
||||
: TextForMimeData();
|
||||
if (auto entry = logEntryOriginal()) {
|
||||
const auto originalSelection = mediaDisplayed
|
||||
? media->skipSelection(skipped)
|
||||
: skipped;
|
||||
const auto originalSelection = (mediaDisplayed && invertMedia())
|
||||
? skipTextSelection(textSelection)
|
||||
: mediaDisplayed
|
||||
? media->skipSelection(mediaSelection)
|
||||
: skipTextSelection(selection);
|
||||
logEntryOriginalResult = entry->selectedText(originalSelection);
|
||||
}
|
||||
auto result = textResult;
|
||||
auto &first = (mediaDisplayed && invertMedia())
|
||||
? mediaResult
|
||||
: textResult;
|
||||
auto &second = (mediaDisplayed && invertMedia())
|
||||
? textResult
|
||||
: mediaResult;
|
||||
auto result = first;
|
||||
if (result.empty()) {
|
||||
result = std::move(mediaResult);
|
||||
} else if (!mediaResult.empty()) {
|
||||
result.append(u"\n\n"_q).append(std::move(mediaResult));
|
||||
result = std::move(second);
|
||||
} else if (!second.empty()) {
|
||||
result.append(u"\n\n"_q).append(std::move(second));
|
||||
}
|
||||
if (result.empty()) {
|
||||
result = std::move(logEntryOriginalResult);
|
||||
|
@ -1170,11 +1170,9 @@ void RepliesWidget::send(Api::SendOptions options) {
|
||||
_cornerButtons.clearReplyReturns();
|
||||
}
|
||||
|
||||
const auto webPageId = _composeControls->webPageId();
|
||||
|
||||
auto message = Api::MessageToSend(prepareSendAction(options));
|
||||
message.textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
||||
message.webPageId = webPageId;
|
||||
message.webPage = _composeControls->webPageDraft();
|
||||
|
||||
const auto error = GetErrorTextForSending(
|
||||
_history->peer,
|
||||
@ -1213,6 +1211,7 @@ void RepliesWidget::edit(
|
||||
return;
|
||||
}
|
||||
const auto textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
||||
const auto webpage = _composeControls->webPageDraft();
|
||||
const auto prepareFlags = Ui::ItemTextOptions(
|
||||
_history,
|
||||
session().user()).flags;
|
||||
@ -1274,6 +1273,7 @@ void RepliesWidget::edit(
|
||||
*saveEditMsgRequestId = Api::EditTextMessage(
|
||||
item,
|
||||
sending,
|
||||
webpage,
|
||||
options,
|
||||
crl::guard(this, done),
|
||||
crl::guard(this, fail));
|
||||
|
@ -585,11 +585,11 @@ void ScheduledWidget::send() {
|
||||
}
|
||||
|
||||
void ScheduledWidget::send(Api::SendOptions options) {
|
||||
const auto webPageId = _composeControls->webPageId();
|
||||
const auto webPageDraft = _composeControls->webPageDraft();
|
||||
|
||||
auto message = Api::MessageToSend(prepareSendAction(options));
|
||||
message.textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
||||
message.webPageId = webPageId;
|
||||
message.webPage = webPageDraft;
|
||||
|
||||
session().api().sendMessage(std::move(message));
|
||||
|
||||
@ -635,6 +635,7 @@ void ScheduledWidget::edit(
|
||||
return;
|
||||
}
|
||||
const auto textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
||||
const auto webpage = _composeControls->webPageDraft();
|
||||
const auto prepareFlags = Ui::ItemTextOptions(
|
||||
_history,
|
||||
session().user()).flags;
|
||||
@ -696,6 +697,7 @@ void ScheduledWidget::edit(
|
||||
*saveEditMsgRequestId = Api::EditTextMessage(
|
||||
item,
|
||||
sending,
|
||||
webpage,
|
||||
options,
|
||||
crl::guard(this, done),
|
||||
crl::guard(this, fail));
|
||||
|
@ -308,11 +308,12 @@ QSize WebPage::countOptimalSize() {
|
||||
Ui::WebpageTextDescriptionOptions(),
|
||||
context);
|
||||
}
|
||||
if (!displayedSiteName().isEmpty()) {
|
||||
const auto siteName = _data->displayedSiteName();
|
||||
if (!siteName.isEmpty()) {
|
||||
_siteNameLines = 1;
|
||||
_siteName.setMarkedText(
|
||||
st::webPageTitleStyle,
|
||||
Ui::Text::Link(displayedSiteName(), _data->url),
|
||||
Ui::Text::Link(siteName, _data->url),
|
||||
Ui::WebpageTextTitleOptions());
|
||||
}
|
||||
if (_title.isEmpty() && !title.isEmpty()) {
|
||||
@ -868,6 +869,10 @@ TextSelection WebPage::adjustSelection(TextSelection selection, TextSelectType t
|
||||
return { siteNameSelection.from, fromDescriptionSelection(descriptionSelection).to };
|
||||
}
|
||||
|
||||
uint16 WebPage::fullSelectionLength() const {
|
||||
return _siteName.length() + _title.length() + _description.length();
|
||||
}
|
||||
|
||||
void WebPage::clickHandlerActiveChanged(
|
||||
const ClickHandlerPtr &p,
|
||||
bool active) {
|
||||
@ -994,14 +999,6 @@ int WebPage::bottomInfoPadding() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
QString WebPage::displayedSiteName() const {
|
||||
return (_data->document && _data->document->isWallPaper())
|
||||
? tr::lng_media_chat_background(tr::now)
|
||||
: (_data->document && _data->document->isTheme())
|
||||
? tr::lng_media_color_theme(tr::now)
|
||||
: _data->siteName;
|
||||
}
|
||||
|
||||
WebPage::~WebPage() {
|
||||
history()->owner().unregisterWebPageView(_data, _parent);
|
||||
if (_photoMedia) {
|
||||
|
@ -41,9 +41,7 @@ public:
|
||||
[[nodiscard]] TextSelection adjustSelection(
|
||||
TextSelection selection,
|
||||
TextSelectType type) const override;
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _title.length() + _description.length();
|
||||
}
|
||||
uint16 fullSelectionLength() const override;
|
||||
bool hasTextForCopy() const override {
|
||||
// We do not add _title and _description in FullSelection text copy.
|
||||
return false;
|
||||
@ -119,7 +117,6 @@ private:
|
||||
[[nodiscard]] int bottomInfoPadding() const;
|
||||
[[nodiscard]] bool isLogEntryOriginal() const;
|
||||
|
||||
[[nodiscard]] QString displayedSiteName() const;
|
||||
[[nodiscard]] ClickHandlerPtr replaceAttachLink(
|
||||
const ClickHandlerPtr &link) const;
|
||||
[[nodiscard]] bool asArticle() const;
|
||||
|
@ -193,11 +193,11 @@ void ReplyArea::sendReaction(const Data::ReactionId &id) {
|
||||
}
|
||||
|
||||
void ReplyArea::send(Api::SendOptions options) {
|
||||
const auto webPageId = _controls->webPageId();
|
||||
const auto webPageDraft = _controls->webPageDraft();
|
||||
|
||||
auto message = Api::MessageToSend(prepareSendAction(options));
|
||||
message.textWithTags = _controls->getTextWithAppliedMarkdown();
|
||||
message.webPageId = webPageId;
|
||||
message.webPage = webPageDraft;
|
||||
|
||||
send(std::move(message), options);
|
||||
}
|
||||
|
@ -202,3 +202,7 @@ mediaSpeedVeryFast: icon {{ "player/speed/audiospeed_menu_1.7", mediaviewMenuFg
|
||||
mediaSpeedVeryFastActive: icon {{ "player/speed/audiospeed_menu_1.7", mediaviewTextLinkFg }};
|
||||
mediaSpeedSuperFast: icon {{ "player/speed/audiospeed_menu_2.0", mediaviewMenuFg }};
|
||||
mediaSpeedSuperFastActive: icon {{ "player/speed/audiospeed_menu_2.0", mediaviewTextLinkFg }};
|
||||
|
||||
menuIconMakeBig: icon {{ "player/player_fullscreen", menuIconColor }};
|
||||
menuIconMakeSmall: icon {{ "player/player_minimize", menuIconColor }};
|
||||
menuIconChangeOrder: icon {{ "player/player_order", menuIconColor }};
|
||||
|
Loading…
Reference in New Issue
Block a user