mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-27 07:52:57 +02:00
PoC suggesting posts to channels.
This commit is contained in:
parent
8dbc175c02
commit
7e5a29a5cc
42 changed files with 712 additions and 58 deletions
|
@ -898,6 +898,8 @@ PRIVATE
|
|||
history/view/history_view_sticker_toast.h
|
||||
history/view/history_view_subsection_tabs.cpp
|
||||
history/view/history_view_subsection_tabs.h
|
||||
history/view/history_view_suggest_options.cpp
|
||||
history/view/history_view_suggest_options.h
|
||||
history/view/history_view_text_helper.cpp
|
||||
history/view/history_view_text_helper.h
|
||||
history/view/history_view_transcribe_button.cpp
|
||||
|
|
|
@ -4415,6 +4415,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_preview_reply_to" = "Reply to {name}";
|
||||
"lng_preview_reply_to_quote" = "Reply to quote from {name}";
|
||||
|
||||
"lng_suggest_bar_title" = "Suggest a Post Below";
|
||||
"lng_suggest_bar_text" = "Click to offer a price for publishing.";
|
||||
"lng_suggest_bar_priced" = "{amount} for publishing anytime.";
|
||||
"lng_suggest_bar_priced_dated" = "{amount} {date}";
|
||||
"lng_suggest_bar_dated" = "Publish on {date}";
|
||||
"lng_suggest_options_title" = "Suggest a Message";
|
||||
"lng_suggest_options_price" = "Enter Price in Stars";
|
||||
"lng_suggest_options_price_about" = "Choose how many Stars you want to offer {channel} to publish this message.";
|
||||
"lng_suggest_options_date" = "Time";
|
||||
"lng_suggest_options_date_any" = "Anytime";
|
||||
"lng_suggest_options_date_about" = "Select the date and time you want the message to be published.";
|
||||
"lng_suggest_options_offer" = "Offer {amount}";
|
||||
|
||||
"lng_reply_in_another_title" = "Reply in...";
|
||||
"lng_reply_in_another_chat" = "Reply in Another Chat";
|
||||
"lng_reply_in_author" = "Message author";
|
||||
|
|
|
@ -399,10 +399,12 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
|||
}
|
||||
}
|
||||
const auto replyTo = FullReplyTo();
|
||||
const auto suggest = SuggestPostOptions();
|
||||
Window::PeerMenuCreatePoll(
|
||||
controller,
|
||||
item->history()->peer,
|
||||
replyTo,
|
||||
suggest,
|
||||
chosen,
|
||||
disabled);
|
||||
} break;
|
||||
|
|
|
@ -14,13 +14,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Api {
|
||||
|
||||
MTPSuggestedPost SuggestToMTP(const std::optional<SuggestOptions> &suggest) {
|
||||
MTPSuggestedPost SuggestToMTP(SuggestPostOptions suggest) {
|
||||
using Flag = MTPDsuggestedPost::Flag;
|
||||
return suggest
|
||||
return suggest.exists
|
||||
? MTP_suggestedPost(
|
||||
MTP_flags(suggest->date ? Flag::f_schedule_date : Flag()),
|
||||
MTP_long(suggest->stars),
|
||||
MTP_int(suggest->date))
|
||||
MTP_flags(suggest.date ? Flag::f_schedule_date : Flag()),
|
||||
MTP_long(suggest.stars),
|
||||
MTP_int(suggest.date))
|
||||
: MTPSuggestedPost();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,17 +19,7 @@ namespace Api {
|
|||
|
||||
inline constexpr auto kScheduledUntilOnlineTimestamp = TimeId(0x7FFFFFFE);
|
||||
|
||||
struct SuggestOptions {
|
||||
int stars = 0;
|
||||
TimeId date = 0;
|
||||
|
||||
friend inline bool operator==(
|
||||
const SuggestOptions &,
|
||||
const SuggestOptions &) = default;
|
||||
};
|
||||
|
||||
[[nodiscard]] MTPSuggestedPost SuggestToMTP(
|
||||
const std::optional<SuggestOptions> &suggest);
|
||||
[[nodiscard]] MTPSuggestedPost SuggestToMTP(SuggestPostOptions suggest);
|
||||
|
||||
struct SendOptions {
|
||||
uint64 price = 0;
|
||||
|
@ -43,7 +33,7 @@ struct SendOptions {
|
|||
bool invertCaption = false;
|
||||
bool hideViaBot = false;
|
||||
crl::time ttlSeconds = 0;
|
||||
std::optional<SuggestOptions> suggest;
|
||||
SuggestPostOptions suggest;
|
||||
|
||||
friend inline bool operator==(
|
||||
const SendOptions &,
|
||||
|
|
|
@ -239,6 +239,7 @@ void SendExistingMedia(
|
|||
.starsPaid = starsPaid,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
}, media, caption);
|
||||
|
||||
const auto performRequest = [=](const auto &repeatRequest) -> void {
|
||||
|
@ -426,6 +427,7 @@ bool SendDice(MessageToSend &message) {
|
|||
.starsPaid = starsPaid,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
}, TextWithEntities(), MTP_messageMediaDice(
|
||||
MTP_int(0),
|
||||
MTP_string(emoji)));
|
||||
|
@ -652,6 +654,7 @@ void SendConfirmedFile(
|
|||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.groupedId = groupId,
|
||||
.effectId = file->to.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(file->to.options),
|
||||
}, caption, media);
|
||||
}
|
||||
|
||||
|
|
|
@ -2170,7 +2170,7 @@ void ApiWrap::saveDraftsToCloud() {
|
|||
cloudDraft->webpage,
|
||||
textWithTags.text.isEmpty()),
|
||||
MTP_long(0), // effect
|
||||
MTPSuggestedPost() //
|
||||
Api::SuggestToMTP(cloudDraft->suggest)
|
||||
)).done([=](const MTPBool &result, const MTP::Response &response) {
|
||||
const auto requestId = response.requestId;
|
||||
history->finishSavingCloudDraft(
|
||||
|
@ -3508,7 +3508,7 @@ void ApiWrap::forwardMessages(
|
|||
.shortcutId = action.options.shortcutId,
|
||||
.starsPaid = action.options.starsApproved,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
// forwarded messages don't have effects
|
||||
//.effectId = action.options.effectId,
|
||||
}, item);
|
||||
|
@ -3603,6 +3603,7 @@ void ApiWrap::sendSharedContact(
|
|||
.starsPaid = action.options.starsApproved,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
}, TextWithEntities(), MTP_messageMediaContact(
|
||||
MTP_string(phone),
|
||||
MTP_string(firstName),
|
||||
|
@ -3986,6 +3987,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
|||
.starsPaid = starsPaid,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
}, sending, media);
|
||||
const auto done = [=](
|
||||
const MTPUpdates &result,
|
||||
|
@ -4036,7 +4038,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
|||
mtpShortcut,
|
||||
MTP_long(action.options.effectId),
|
||||
MTP_long(starsPaid),
|
||||
SuggestToMTP(action.options.suggest)
|
||||
Api::SuggestToMTP(action.options.suggest)
|
||||
), done, fail);
|
||||
} else {
|
||||
histories.sendPreparedMessage(
|
||||
|
@ -4056,7 +4058,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
|||
mtpShortcut,
|
||||
MTP_long(action.options.effectId),
|
||||
MTP_long(starsPaid),
|
||||
SuggestToMTP(action.options.suggest)
|
||||
Api::SuggestToMTP(action.options.suggest)
|
||||
), done, fail);
|
||||
}
|
||||
isFirst = false;
|
||||
|
@ -4392,7 +4394,7 @@ void ApiWrap::sendMediaWithRandomId(
|
|||
Data::ShortcutIdToMTP(_session, options.shortcutId),
|
||||
MTP_long(options.effectId),
|
||||
MTP_long(starsPaid),
|
||||
SuggestToMTP(options.suggest)
|
||||
Api::SuggestToMTP(options.suggest)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (done) done(true);
|
||||
if (updateRecentStickers) {
|
||||
|
@ -4476,7 +4478,7 @@ void ApiWrap::sendMultiPaidMedia(
|
|||
Data::ShortcutIdToMTP(_session, options.shortcutId),
|
||||
MTP_long(options.effectId),
|
||||
MTP_long(starsPaid),
|
||||
SuggestToMTP(options.suggest)
|
||||
Api::SuggestToMTP(options.suggest)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (const auto album = _sendingAlbums.take(groupId)) {
|
||||
const auto copy = (*album)->items;
|
||||
|
|
|
@ -1144,6 +1144,30 @@ historyGiftToUser: IconButton(historyAttach) {
|
|||
icon: icon {{ "chat/input_gift", historyComposeIconFg }};
|
||||
iconOver: icon {{ "chat/input_gift", historyComposeIconFgOver }};
|
||||
}
|
||||
historySuggestPostToggle: IconButton(historyDirectMessage) {
|
||||
icon: icon{{ "menu/chat_discuss", historyComposeIconFg }};
|
||||
iconOver: icon{{ "menu/chat_discuss", historyComposeIconFgOver }};
|
||||
}
|
||||
historySuggestIconPosition: point(12px, 12px);
|
||||
|
||||
suggestOptionsPrice: InputField(defaultInputField) {
|
||||
textBg: transparent;
|
||||
textMargins: margins(2px, 20px, 2px, 0px);
|
||||
|
||||
placeholderFg: placeholderFg;
|
||||
placeholderFgActive: placeholderFgActive;
|
||||
placeholderFgError: placeholderFgActive;
|
||||
placeholderMargins: margins(2px, 0px, 2px, 0px);
|
||||
placeholderScale: 0.;
|
||||
placeholderFont: normalFont;
|
||||
|
||||
border: 0px;
|
||||
borderActive: 0px;
|
||||
|
||||
heightMin: 32px;
|
||||
|
||||
style: defaultTextStyle;
|
||||
}
|
||||
|
||||
historyAttachEmojiInner: IconButton(historyAttach) {
|
||||
icon: icon {{ "chat/input_smile_face", historyComposeIconFg }};
|
||||
|
|
|
@ -21,6 +21,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "storage/localstorage.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxSuggestStars = 1'000'000'000;
|
||||
|
||||
} // namespace
|
||||
|
||||
WebPageDraft WebPageDraft::FromItem(not_null<HistoryItem*> item) {
|
||||
const auto previewMedia = item->media();
|
||||
|
@ -45,6 +50,7 @@ WebPageDraft WebPageDraft::FromItem(not_null<HistoryItem*> item) {
|
|||
Draft::Draft(
|
||||
const TextWithTags &textWithTags,
|
||||
FullReplyTo reply,
|
||||
SuggestPostOptions suggest,
|
||||
const MessageCursor &cursor,
|
||||
WebPageDraft webpage,
|
||||
mtpRequestId saveRequestId)
|
||||
|
@ -58,6 +64,7 @@ Draft::Draft(
|
|||
Draft::Draft(
|
||||
not_null<const Ui::InputField*> field,
|
||||
FullReplyTo reply,
|
||||
SuggestPostOptions suggest,
|
||||
WebPageDraft webpage,
|
||||
mtpRequestId saveRequestId)
|
||||
: textWithTags(field->getTextWithTags())
|
||||
|
@ -106,9 +113,22 @@ void ApplyPeerCloudDraft(
|
|||
}
|
||||
}, [](const auto &) {});
|
||||
}
|
||||
auto suggest = SuggestPostOptions();
|
||||
if (!history->suggestDraftAllowed()) {
|
||||
// Don't apply suggest options in unsupported chats.
|
||||
} else if (const auto suggested = draft.vsuggested_post()) {
|
||||
const auto &data = suggested->data();
|
||||
suggest.exists = 1;
|
||||
suggest.date = data.vschedule_date().value_or_empty();
|
||||
suggest.stars = uint32(std::clamp(
|
||||
data.vstars_amount().v,
|
||||
uint64(),
|
||||
uint64(kMaxSuggestStars)));
|
||||
}
|
||||
auto cloudDraft = std::make_unique<Draft>(
|
||||
textWithTags,
|
||||
replyTo,
|
||||
suggest,
|
||||
MessageCursor(Ui::kQFixedMax, Ui::kQFixedMax, Ui::kQFixedMax),
|
||||
std::move(webpage));
|
||||
cloudDraft->date = date;
|
||||
|
@ -150,18 +170,19 @@ void SetChatLinkDraft(not_null<PeerData*> peer, TextWithEntities draft) {
|
|||
const auto history = peer->owner().history(peer->id);
|
||||
const auto topicRootId = MsgId();
|
||||
const auto monoforumPeerId = PeerId();
|
||||
history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||
history->setLocalDraft(std::make_unique<Draft>(
|
||||
textWithTags,
|
||||
FullReplyTo{
|
||||
.topicRootId = topicRootId,
|
||||
.monoforumPeerId = monoforumPeerId,
|
||||
},
|
||||
SuggestPostOptions(),
|
||||
cursor,
|
||||
Data::WebPageDraft()));
|
||||
WebPageDraft()));
|
||||
history->clearLocalEditDraft(topicRootId, monoforumPeerId);
|
||||
history->session().changes().entryUpdated(
|
||||
history,
|
||||
Data::EntryUpdate::Flag::LocalDraftSet);
|
||||
EntryUpdate::Flag::LocalDraftSet);
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -52,18 +52,21 @@ struct Draft {
|
|||
Draft(
|
||||
const TextWithTags &textWithTags,
|
||||
FullReplyTo reply,
|
||||
SuggestPostOptions suggest,
|
||||
const MessageCursor &cursor,
|
||||
WebPageDraft webpage,
|
||||
mtpRequestId saveRequestId = 0);
|
||||
Draft(
|
||||
not_null<const Ui::InputField*> field,
|
||||
FullReplyTo reply,
|
||||
SuggestPostOptions suggest,
|
||||
WebPageDraft webpage,
|
||||
mtpRequestId saveRequestId = 0);
|
||||
|
||||
TimeId date = 0;
|
||||
TextWithTags textWithTags;
|
||||
FullReplyTo reply; // reply.messageId.msg is editMsgId for edit draft.
|
||||
SuggestPostOptions suggest;
|
||||
MessageCursor cursor;
|
||||
WebPageDraft webpage;
|
||||
mtpRequestId saveRequestId = 0;
|
||||
|
@ -240,6 +243,7 @@ using HistoryDrafts = base::flat_map<DraftKey, std::unique_ptr<Draft>>;
|
|||
[[nodiscard]] inline bool DraftIsNull(const Draft *draft) {
|
||||
return !draft
|
||||
|| (!draft->reply.messageId
|
||||
&& !draft->suggest.exists
|
||||
&& DraftStringIsEmpty(draft->textWithTags.text));
|
||||
}
|
||||
|
||||
|
|
|
@ -190,6 +190,23 @@ struct FullReplyTo {
|
|||
friend inline bool operator==(FullReplyTo, FullReplyTo) = default;
|
||||
};
|
||||
|
||||
struct SuggestPostOptions {
|
||||
uint32 exists : 1 = 0;
|
||||
uint32 stars : 31 = 0;
|
||||
TimeId date = 0;
|
||||
|
||||
explicit operator bool() const {
|
||||
return exists != 0;
|
||||
}
|
||||
|
||||
friend inline auto operator<=>(
|
||||
SuggestPostOptions,
|
||||
SuggestPostOptions) = default;
|
||||
friend inline bool operator==(
|
||||
SuggestPostOptions,
|
||||
SuggestPostOptions) = default;
|
||||
};
|
||||
|
||||
struct GlobalMsgId {
|
||||
FullMsgId itemId;
|
||||
uint64 sessionUniqueId = 0;
|
||||
|
|
|
@ -685,6 +685,9 @@ bool PeerData::canCreatePolls() const {
|
|||
}
|
||||
|
||||
bool PeerData::canCreateTodoLists() const {
|
||||
if (isMonoforum()) {
|
||||
return false;
|
||||
}
|
||||
return session().premium()
|
||||
&& (Data::CanSend(this, ChatRestriction::SendPolls) || isUser());
|
||||
}
|
||||
|
|
|
@ -121,6 +121,7 @@ struct EntryState {
|
|||
Section section = Section::History;
|
||||
FilterId filterId = 0;
|
||||
FullReplyTo currentReplyTo;
|
||||
SuggestPostOptions currentSuggest;
|
||||
|
||||
friend inline auto operator<=>(
|
||||
const EntryState&,
|
||||
|
|
|
@ -239,6 +239,9 @@ void History::createLocalDraftFromCloud(
|
|||
|
||||
draft->reply.topicRootId = topicRootId;
|
||||
draft->reply.monoforumPeerId = monoforumPeerId;
|
||||
if (!suggestDraftAllowed()) {
|
||||
draft->suggest = SuggestPostOptions();
|
||||
}
|
||||
auto existing = localDraft(topicRootId, monoforumPeerId);
|
||||
if (Data::DraftIsNull(existing)
|
||||
|| !existing->date
|
||||
|
@ -247,12 +250,14 @@ void History::createLocalDraftFromCloud(
|
|||
setLocalDraft(std::make_unique<Data::Draft>(
|
||||
draft->textWithTags,
|
||||
draft->reply,
|
||||
draft->suggest,
|
||||
draft->cursor,
|
||||
draft->webpage));
|
||||
existing = localDraft(topicRootId, monoforumPeerId);
|
||||
} else if (existing != draft) {
|
||||
existing->textWithTags = draft->textWithTags;
|
||||
existing->reply = draft->reply;
|
||||
existing->suggest = draft->suggest;
|
||||
existing->cursor = draft->cursor;
|
||||
existing->webpage = draft->webpage;
|
||||
}
|
||||
|
@ -325,6 +330,7 @@ Data::Draft *History::createCloudDraft(
|
|||
.topicRootId = topicRootId,
|
||||
.monoforumPeerId = monoforumPeerId,
|
||||
},
|
||||
SuggestPostOptions(),
|
||||
MessageCursor(),
|
||||
Data::WebPageDraft()));
|
||||
cloudDraft(topicRootId, monoforumPeerId)->date = TimeId(0);
|
||||
|
@ -337,18 +343,23 @@ Data::Draft *History::createCloudDraft(
|
|||
setCloudDraft(std::make_unique<Data::Draft>(
|
||||
fromDraft->textWithTags,
|
||||
reply,
|
||||
fromDraft->suggest,
|
||||
fromDraft->cursor,
|
||||
fromDraft->webpage));
|
||||
existing = cloudDraft(topicRootId, monoforumPeerId);
|
||||
} else if (existing != fromDraft) {
|
||||
existing->textWithTags = fromDraft->textWithTags;
|
||||
existing->reply = fromDraft->reply;
|
||||
existing->suggest = fromDraft->suggest;
|
||||
existing->cursor = fromDraft->cursor;
|
||||
existing->webpage = fromDraft->webpage;
|
||||
}
|
||||
existing->date = base::unixtime::now();
|
||||
existing->reply.topicRootId = topicRootId;
|
||||
existing->reply.monoforumPeerId = monoforumPeerId;
|
||||
if (!suggestDraftAllowed()) {
|
||||
existing->suggest = SuggestPostOptions();
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto thread = threadFor(topicRootId, monoforumPeerId)) {
|
||||
|
@ -3382,6 +3393,10 @@ bool History::amMonoforumAdmin() const {
|
|||
return (_flags & Flag::IsMonoforumAdmin);
|
||||
}
|
||||
|
||||
bool History::suggestDraftAllowed() const {
|
||||
return peer->isMonoforum() || !peer->amMonoforumAdmin();
|
||||
}
|
||||
|
||||
not_null<History*> History::migrateToOrMe() const {
|
||||
if (const auto to = peer->migrateTo()) {
|
||||
return owner().history(to);
|
||||
|
|
|
@ -79,6 +79,7 @@ public:
|
|||
|
||||
void monoforumChanged(Data::SavedMessages *old);
|
||||
[[nodiscard]] bool amMonoforumAdmin() const;
|
||||
[[nodiscard]] bool suggestDraftAllowed() const;
|
||||
|
||||
[[nodiscard]] not_null<History*> migrateToOrMe() const;
|
||||
[[nodiscard]] History *migrateFrom() const;
|
||||
|
|
|
@ -190,6 +190,7 @@ struct HistoryItem::CreateConfig {
|
|||
TimeId editDate = 0;
|
||||
HistoryMessageMarkupData markup;
|
||||
HistoryMessageRepliesData replies;
|
||||
HistoryMessageSuggestInfo suggest;
|
||||
bool imported = false;
|
||||
|
||||
// For messages created from existing messages (forwarded).
|
||||
|
@ -3841,6 +3842,9 @@ void HistoryItem::createComponents(CreateConfig &&config) {
|
|||
mask |= HistoryMessageRestrictions::Bit();
|
||||
}
|
||||
}
|
||||
if (config.suggest.exists) {
|
||||
mask |= HistoryMessageSuggestedPost::Bit();
|
||||
}
|
||||
|
||||
UpdateComponents(mask);
|
||||
|
||||
|
@ -3935,6 +3939,13 @@ void HistoryItem::createComponents(CreateConfig &&config) {
|
|||
flagSensitiveContent();
|
||||
}
|
||||
|
||||
if (const auto suggest = Get<HistoryMessageSuggestedPost>()) {
|
||||
suggest->stars = config.suggest.stars;
|
||||
suggest->date = config.suggest.date;
|
||||
suggest->accepted = config.suggest.accepted;
|
||||
suggest->rejected = config.suggest.rejected;
|
||||
}
|
||||
|
||||
if (out() && isSending()) {
|
||||
if (const auto channel = _history->peer->asMegagroup()) {
|
||||
_boostsApplied = channel->mgInfo->boostsApplied;
|
||||
|
@ -4137,6 +4148,9 @@ void HistoryItem::createComponentsHelper(HistoryItemCommonFields &&fields) {
|
|||
if (fields.flags & MessageFlag::HasViews) {
|
||||
config.viewsCount = 1;
|
||||
}
|
||||
if (fields.suggest.exists) {
|
||||
config.suggest = fields.suggest;
|
||||
}
|
||||
|
||||
createComponents(std::move(config));
|
||||
}
|
||||
|
@ -4261,6 +4275,7 @@ void HistoryItem::createComponents(const MTPDmessage &data) {
|
|||
config.postAuthor = qs(data.vpost_author().value_or_empty());
|
||||
config.restrictions = Data::UnavailableReason::Extract(
|
||||
data.vrestriction_reason());
|
||||
config.suggest = HistoryMessageSuggestInfo(data.vsuggested_post());
|
||||
createComponents(std::move(config));
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ struct HistoryItemCommonFields {
|
|||
uint64 groupedId = 0;
|
||||
EffectId effectId = 0;
|
||||
HistoryMessageMarkupData markup;
|
||||
HistoryMessageSuggestInfo suggest;
|
||||
bool ignoreForwardFrom = false;
|
||||
bool ignoreForwardCaptions = false;
|
||||
};
|
||||
|
|
|
@ -614,6 +614,14 @@ struct HistoryMessageFactcheck
|
|||
bool requested = false;
|
||||
};
|
||||
|
||||
struct HistoryMessageSuggestedPost
|
||||
: RuntimeComponent<HistoryMessageSuggestedPost, HistoryItem> {
|
||||
int stars = 0;
|
||||
TimeId date = 0;
|
||||
bool accepted = false;
|
||||
bool rejected = false;
|
||||
};
|
||||
|
||||
struct HistoryMessageRestrictions
|
||||
: RuntimeComponent<HistoryMessageRestrictions, HistoryItem> {
|
||||
std::vector<Data::UnavailableReason> reasons;
|
||||
|
|
|
@ -312,7 +312,7 @@ HistoryMessageRepliesData::HistoryMessageRepliesData(
|
|||
if (!data) {
|
||||
return;
|
||||
}
|
||||
const auto &fields = data->c_messageReplies();
|
||||
const auto &fields = data->data();
|
||||
if (const auto list = fields.vrecent_repliers()) {
|
||||
recentRepliers.reserve(list->v.size());
|
||||
for (const auto &id : list->v) {
|
||||
|
@ -326,3 +326,31 @@ HistoryMessageRepliesData::HistoryMessageRepliesData(
|
|||
isNull = false;
|
||||
pts = fields.vreplies_pts().v;
|
||||
}
|
||||
|
||||
HistoryMessageSuggestInfo::HistoryMessageSuggestInfo(
|
||||
const MTPSuggestedPost *data) {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
const auto &fields = data->data();
|
||||
stars = fields.vstars_amount().v;
|
||||
date = fields.vschedule_date().value_or_empty();
|
||||
accepted = fields.is_accepted();
|
||||
rejected = fields.is_rejected();
|
||||
exists = true;
|
||||
}
|
||||
|
||||
HistoryMessageSuggestInfo::HistoryMessageSuggestInfo(
|
||||
const Api::SendOptions &options)
|
||||
: HistoryMessageSuggestInfo(options.suggest) {
|
||||
}
|
||||
|
||||
HistoryMessageSuggestInfo::HistoryMessageSuggestInfo(
|
||||
SuggestPostOptions options) {
|
||||
if (!options.exists) {
|
||||
return;
|
||||
}
|
||||
stars = options.stars;
|
||||
date = options.date;
|
||||
exists = true;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/flags.h"
|
||||
#include "data/data_chat_participant_status.h"
|
||||
|
||||
namespace Api {
|
||||
struct SendOptions;
|
||||
} // namespace Api
|
||||
|
||||
namespace Data {
|
||||
class Session;
|
||||
} // namespace Data
|
||||
|
@ -136,3 +140,16 @@ struct HistoryMessageRepliesData {
|
|||
bool isNull = true;
|
||||
int pts = 0;
|
||||
};
|
||||
|
||||
struct HistoryMessageSuggestInfo {
|
||||
HistoryMessageSuggestInfo() = default;
|
||||
explicit HistoryMessageSuggestInfo(const MTPSuggestedPost *data);
|
||||
explicit HistoryMessageSuggestInfo(const Api::SendOptions &options);
|
||||
explicit HistoryMessageSuggestInfo(SuggestPostOptions options);
|
||||
|
||||
int stars = 0;
|
||||
TimeId date = 0;
|
||||
bool accepted = false;
|
||||
bool rejected = false;
|
||||
bool exists = false;
|
||||
};
|
||||
|
|
|
@ -118,6 +118,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/history_view_requests_bar.h"
|
||||
#include "history/view/history_view_sticker_toast.h"
|
||||
#include "history/view/history_view_subsection_tabs.h"
|
||||
#include "history/view/history_view_suggest_options.h"
|
||||
#include "history/view/history_view_translate_bar.h"
|
||||
#include "history/view/media/history_view_media.h"
|
||||
#include "profile/profile_block_group_members.h"
|
||||
|
@ -1039,6 +1040,7 @@ Dialogs::EntryState HistoryWidget::computeDialogsEntryState() const {
|
|||
.key = _history,
|
||||
.section = Dialogs::EntryState::Section::History,
|
||||
.currentReplyTo = replyTo(),
|
||||
.currentSuggest = suggestOptions(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1900,13 +1902,16 @@ void HistoryWidget::saveFieldToHistoryLocalDraft() {
|
|||
.topicRootId = topicRootId,
|
||||
.monoforumPeerId = monoforumPeerId,
|
||||
},
|
||||
SuggestPostOptions(),
|
||||
_preview->draft(),
|
||||
_saveEditMsgRequestId));
|
||||
} else {
|
||||
if (_replyTo || !_field->empty()) {
|
||||
const auto suggest = suggestOptions();
|
||||
if (_replyTo || suggest.exists || !_field->empty()) {
|
||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||
_field,
|
||||
_replyTo,
|
||||
suggest,
|
||||
_preview->draft()));
|
||||
} else {
|
||||
_history->clearLocalDraft(topicRootId, monoforumPeerId);
|
||||
|
@ -2270,6 +2275,8 @@ bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
|||
if (_processingReplyTo) {
|
||||
_processingReplyItem = session().data().message(
|
||||
_processingReplyTo.messageId);
|
||||
} else if (draft && draft->suggest) {
|
||||
applySuggestOptions(draft->suggest);
|
||||
}
|
||||
processReply();
|
||||
}
|
||||
|
@ -2480,6 +2487,7 @@ void HistoryWidget::showHistory(
|
|||
setHistory(nullptr);
|
||||
_list = nullptr;
|
||||
_peer = nullptr;
|
||||
_suggestOptions = nullptr;
|
||||
_sendPayment.clear();
|
||||
_topicsRequested.clear();
|
||||
_canSendMessages = false;
|
||||
|
@ -2606,6 +2614,7 @@ void HistoryWidget::showHistory(
|
|||
} else if (_peer->isRepliesChat() || _peer->isVerifyCodes()) {
|
||||
updateNotifyControls();
|
||||
}
|
||||
refreshSuggestPostToggle();
|
||||
refreshScheduledToggle();
|
||||
refreshSendGiftToggle();
|
||||
refreshSendAsToggle();
|
||||
|
@ -2917,6 +2926,7 @@ void HistoryWidget::registerDraftSource() {
|
|||
(editMsgId
|
||||
? FullReplyTo{ FullMsgId(peerId, editMsgId) }
|
||||
: _replyTo),
|
||||
(editMsgId ? SuggestPostOptions() : suggestOptions()),
|
||||
_field->getTextWithTags(),
|
||||
_preview->draft(),
|
||||
};
|
||||
|
@ -3154,6 +3164,41 @@ void HistoryWidget::refreshSendGiftToggle() {
|
|||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::applySuggestOptions(SuggestPostOptions suggest) {
|
||||
Expects(suggest.exists);
|
||||
|
||||
using namespace HistoryView;
|
||||
_suggestOptions = std::make_unique<SuggestOptions>(
|
||||
controller(),
|
||||
_peer,
|
||||
suggest);
|
||||
_suggestOptions->repaints() | rpl::start_with_next([=] {
|
||||
updateField();
|
||||
}, _suggestOptions->lifetime());
|
||||
}
|
||||
|
||||
void HistoryWidget::refreshSuggestPostToggle() {
|
||||
const auto has = _peer
|
||||
&& _peer->isMonoforum()
|
||||
&& !_peer->amMonoforumAdmin();
|
||||
if (!_toggleSuggestPost && has) {
|
||||
_toggleSuggestPost.create(this, st::historySuggestPostToggle);
|
||||
_toggleSuggestPost->setVisible(!_suggestOptions);
|
||||
_toggleSuggestPost->addClickHandler([=] {
|
||||
applySuggestOptions({ .exists = 1 });
|
||||
cancelReply();
|
||||
_processingReplyTo = FullReplyTo();
|
||||
_processingReplyItem = nullptr;
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
});
|
||||
orderWidgets();
|
||||
} else if (_toggleSuggestPost && !has) {
|
||||
_toggleSuggestPost.destroy();
|
||||
cancelSuggestPost();
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::setupSendAsToggle() {
|
||||
session().sendAsPeers().updated(
|
||||
) | rpl::filter([=](not_null<PeerData*> peer) {
|
||||
|
@ -3294,6 +3339,9 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
if (_scheduled) {
|
||||
_scheduled->hide();
|
||||
}
|
||||
if (_toggleSuggestPost) {
|
||||
_toggleSuggestPost->hide();
|
||||
}
|
||||
if (_giftToUser) {
|
||||
_giftToUser->hide();
|
||||
}
|
||||
|
@ -3408,6 +3456,14 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
rightButtonsChanged = true;
|
||||
}
|
||||
}
|
||||
if (_toggleSuggestPost) {
|
||||
const auto was = _toggleSuggestPost->isVisible();
|
||||
const auto now = !_suggestOptions;
|
||||
if (was != now) {
|
||||
_toggleSuggestPost->setVisible(now);
|
||||
rightButtonsChanged = true;
|
||||
}
|
||||
}
|
||||
if (_giftToUser) {
|
||||
const auto was = _giftToUser->isVisible();
|
||||
const auto now = (!_editMsgId) && (!hideExtraButtons);
|
||||
|
@ -3437,7 +3493,8 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
|| _replyTo
|
||||
|| readyToForward()
|
||||
|| _previewDrawPreview
|
||||
|| _kbReplyTo) {
|
||||
|| _kbReplyTo
|
||||
|| _suggestOptions) {
|
||||
if (_fieldBarCancel->isHidden()) {
|
||||
_fieldBarCancel->show();
|
||||
updateControlsGeometry();
|
||||
|
@ -3466,6 +3523,9 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
if (_scheduled) {
|
||||
_scheduled->hide();
|
||||
}
|
||||
if (_toggleSuggestPost) {
|
||||
_toggleSuggestPost->hide();
|
||||
}
|
||||
if (_giftToUser) {
|
||||
_giftToUser->hide();
|
||||
}
|
||||
|
@ -4503,6 +4563,7 @@ Api::SendAction HistoryWidget::prepareSendAction(
|
|||
Api::SendOptions options) const {
|
||||
auto result = Api::SendAction(_history, options);
|
||||
result.replyTo = replyTo();
|
||||
result.options.suggest = suggestOptions();
|
||||
result.options.sendAs = _sendAs
|
||||
? _history->session().sendAsPeers().resolveChosen(
|
||||
_history->peer).get()
|
||||
|
@ -5040,7 +5101,11 @@ void HistoryWidget::updateOverStates(QPoint pos) {
|
|||
st::historyReplyHeight);
|
||||
const auto hasWebPage = !!_previewDrawPreview;
|
||||
const auto inDetails = detailsRect.contains(pos)
|
||||
&& (_editMsgId || replyTo() || isReadyToForward || hasWebPage);
|
||||
&& (_editMsgId
|
||||
|| replyTo()
|
||||
|| isReadyToForward
|
||||
|| hasWebPage
|
||||
|| _suggestOptions);
|
||||
const auto inPhotoEdit = inDetails
|
||||
&& _photoEditMedia
|
||||
&& QRect(
|
||||
|
@ -5585,7 +5650,8 @@ void HistoryWidget::toggleKeyboard(bool manual) {
|
|||
if (!readyToForward()
|
||||
&& !_previewDrawPreview
|
||||
&& !_editMsgId
|
||||
&& !_replyTo) {
|
||||
&& !_replyTo
|
||||
&& !_suggestOptions) {
|
||||
_fieldBarCancel->hide();
|
||||
updateMouseTracking();
|
||||
}
|
||||
|
@ -5806,7 +5872,7 @@ void HistoryWidget::moveFieldControls() {
|
|||
}
|
||||
|
||||
// (_botMenu.button) (_attachToggle|_replaceMedia) (_sendAs) ---- _inlineResults ------------------------------ _tabbedPanel ------ _fieldBarCancel
|
||||
// (_attachDocument|_attachPhoto) _field (_ttlInfo) (_scheduled) (_giftToUser) (_silent|_cmdStart|_kbShow) (_kbHide|_tabbedSelectorToggle) _send
|
||||
// (_attachDocument|_attachPhoto) _field (_ttlInfo) (_scheduled) (_giftToUser) (_silent|_cmdStart|_kbShow) (_toggleSuggestPost) (_kbHide|_tabbedSelectorToggle) _send
|
||||
// (_botStart|_unblock|_joinChannel|_muteUnmute|_reportMessages)
|
||||
|
||||
auto buttonsBottom = bottom - _attachToggle->height();
|
||||
|
@ -5848,6 +5914,10 @@ void HistoryWidget::moveFieldControls() {
|
|||
if (kbShowShown || _cmdStartShown || _silent) {
|
||||
right += _botCommandStart->width();
|
||||
}
|
||||
if (_toggleSuggestPost) {
|
||||
_toggleSuggestPost->moveToRight(right, buttonsBottom);
|
||||
right += _toggleSuggestPost->width();
|
||||
}
|
||||
if (_giftToUser) {
|
||||
_giftToUser->moveToRight(right, buttonsBottom);
|
||||
right += _giftToUser->width();
|
||||
|
@ -5912,6 +5982,9 @@ void HistoryWidget::updateFieldSize() {
|
|||
if (_silent && !_silent->isHidden()) {
|
||||
fieldWidth -= _silent->width();
|
||||
}
|
||||
if (_toggleSuggestPost && !_toggleSuggestPost->isHidden()) {
|
||||
fieldWidth -= _toggleSuggestPost->width();
|
||||
}
|
||||
if (_giftToUser && !_giftToUser->isHidden()) {
|
||||
fieldWidth -= _giftToUser->width();
|
||||
}
|
||||
|
@ -6590,6 +6663,12 @@ FullReplyTo HistoryWidget::replyTo() const {
|
|||
: FullReplyTo();
|
||||
}
|
||||
|
||||
SuggestPostOptions HistoryWidget::suggestOptions() const {
|
||||
return (_history && _history->suggestDraftAllowed() && _suggestOptions)
|
||||
? _suggestOptions->values()
|
||||
: SuggestPostOptions();
|
||||
}
|
||||
|
||||
bool HistoryWidget::hasSavedScroll() const {
|
||||
Expects(_history != nullptr);
|
||||
|
||||
|
@ -6797,7 +6876,8 @@ void HistoryWidget::updateHistoryGeometry(
|
|||
if (_editMsgId
|
||||
|| replyTo()
|
||||
|| readyToForward()
|
||||
|| _previewDrawPreview) {
|
||||
|| _previewDrawPreview
|
||||
|| _suggestOptions) {
|
||||
newScrollHeight -= st::historyReplyHeight;
|
||||
}
|
||||
if (_kbShown) {
|
||||
|
@ -7143,7 +7223,8 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
_kbReplyTo = nullptr;
|
||||
if (!readyToForward()
|
||||
&& !_previewDrawPreview
|
||||
&& !_replyTo) {
|
||||
&& !_replyTo
|
||||
&& !_suggestOptions) {
|
||||
_fieldBarCancel->hide();
|
||||
updateMouseTracking();
|
||||
}
|
||||
|
@ -7162,7 +7243,8 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
if (!readyToForward()
|
||||
&& !_previewDrawPreview
|
||||
&& !_replyTo
|
||||
&& !_editMsgId) {
|
||||
&& !_editMsgId
|
||||
&& !_suggestOptions) {
|
||||
_fieldBarCancel->hide();
|
||||
updateMouseTracking();
|
||||
}
|
||||
|
@ -7316,6 +7398,8 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
|||
_kbReplyTo->history()->peer->id,
|
||||
Window::SectionShow::Way::Forward,
|
||||
_kbReplyTo->id);
|
||||
} else if (_suggestOptions) {
|
||||
_suggestOptions->edit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7324,6 +7408,7 @@ void HistoryWidget::editDraftOptions() {
|
|||
|
||||
const auto history = _history;
|
||||
const auto reply = _replyTo;
|
||||
const auto suggest = suggestOptions();
|
||||
const auto webpage = _preview->draft();
|
||||
const auto forward = _forwardPanel->draft();
|
||||
|
||||
|
@ -7348,7 +7433,7 @@ void HistoryWidget::editDraftOptions() {
|
|||
EditDraftOptions({
|
||||
.show = controller()->uiShow(),
|
||||
.history = history,
|
||||
.draft = Data::Draft(_field, reply, _preview->draft()),
|
||||
.draft = Data::Draft(_field, reply, suggest, _preview->draft()),
|
||||
.usedLink = _preview->link(),
|
||||
.forward = _forwardPanel->draft(),
|
||||
.links = _preview->links(),
|
||||
|
@ -8465,7 +8550,9 @@ void HistoryWidget::processReply() {
|
|||
|
||||
if (!_peer || !_processingReplyTo) {
|
||||
return processCancel();
|
||||
} else if (!_processingReplyItem) {
|
||||
}
|
||||
cancelSuggestPost();
|
||||
if (!_processingReplyItem) {
|
||||
session().api().requestMessageData(
|
||||
session().data().peer(_processingReplyTo.messageId.peer),
|
||||
_processingReplyTo.messageId.msg,
|
||||
|
@ -8524,16 +8611,19 @@ void HistoryWidget::setReplyFieldsFromProcessing() {
|
|||
if (_editMsgId) {
|
||||
if (const auto localDraft = _history->localDraft({}, {})) {
|
||||
localDraft->reply = id;
|
||||
localDraft->suggest = SuggestPostOptions();
|
||||
} else {
|
||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||
TextWithTags(),
|
||||
id,
|
||||
SuggestPostOptions(),
|
||||
MessageCursor(),
|
||||
Data::WebPageDraft()));
|
||||
}
|
||||
} else {
|
||||
_replyEditMsg = item;
|
||||
_replyTo = id;
|
||||
cancelSuggestPost();
|
||||
updateReplyEditText(_replyEditMsg);
|
||||
updateCanSendMessage();
|
||||
updateBotKeyboard();
|
||||
|
@ -8573,10 +8663,12 @@ void HistoryWidget::editMessage(
|
|||
_send->clearState();
|
||||
}
|
||||
if (!_editMsgId) {
|
||||
if (_replyTo || !_field->empty()) {
|
||||
const auto suggest = suggestOptions();
|
||||
if (_replyTo || suggest.exists || !_field->empty()) {
|
||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||
_field,
|
||||
_replyTo,
|
||||
suggest,
|
||||
_preview->draft()));
|
||||
} else {
|
||||
_history->clearLocalDraft(MsgId(), PeerId());
|
||||
|
@ -8593,6 +8685,7 @@ void HistoryWidget::editMessage(
|
|||
_history->setLocalEditDraft(std::make_unique<Data::Draft>(
|
||||
editData,
|
||||
FullReplyTo{ item->fullId() },
|
||||
SuggestPostOptions(),
|
||||
cursor,
|
||||
previewDraft));
|
||||
applyDraft();
|
||||
|
@ -8679,7 +8772,8 @@ bool HistoryWidget::cancelReply(bool lastKeyboardUsed) {
|
|||
mouseMoveEvent(0);
|
||||
if (!readyToForward()
|
||||
&& !_previewDrawPreview
|
||||
&& !_kbReplyTo) {
|
||||
&& !_kbReplyTo
|
||||
&& !_suggestOptions) {
|
||||
_fieldBarCancel->hide();
|
||||
updateMouseTracking();
|
||||
}
|
||||
|
@ -8754,7 +8848,8 @@ void HistoryWidget::cancelEdit() {
|
|||
mouseMoveEvent(nullptr);
|
||||
if (!readyToForward()
|
||||
&& !_previewDrawPreview
|
||||
&& !replyTo()) {
|
||||
&& !replyTo()
|
||||
&& !_suggestOptions) {
|
||||
_fieldBarCancel->hide();
|
||||
updateMouseTracking();
|
||||
}
|
||||
|
@ -8784,9 +8879,21 @@ void HistoryWidget::cancelFieldAreaState() {
|
|||
_history->setForwardDraft(MsgId(), PeerId(), {});
|
||||
} else if (_kbReplyTo) {
|
||||
toggleKeyboard();
|
||||
} else if (_suggestOptions) {
|
||||
cancelSuggestPost();
|
||||
}
|
||||
}
|
||||
|
||||
bool HistoryWidget::cancelSuggestPost() {
|
||||
if (!_suggestOptions) {
|
||||
return false;
|
||||
}
|
||||
_suggestOptions = nullptr;
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
return true;
|
||||
}
|
||||
|
||||
void HistoryWidget::fullInfoUpdated() {
|
||||
auto refresh = false;
|
||||
if (_list) {
|
||||
|
@ -8891,6 +8998,7 @@ bool HistoryWidget::updateCanSendMessage() {
|
|||
if (!_canSendMessages) {
|
||||
cancelReply();
|
||||
}
|
||||
refreshSuggestPostToggle();
|
||||
refreshScheduledToggle();
|
||||
refreshSendGiftToggle();
|
||||
refreshSilentToggle();
|
||||
|
@ -9190,13 +9298,12 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
|||
auto backh = fieldHeight() + 2 * st::historySendPadding;
|
||||
auto hasForward = readyToForward();
|
||||
auto drawMsgText = (_editMsgId || _replyTo) ? _replyEditMsg : _kbReplyTo;
|
||||
if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
||||
backy -= st::historyReplyHeight;
|
||||
backh += st::historyReplyHeight;
|
||||
} else if (hasForward) {
|
||||
backy -= st::historyReplyHeight;
|
||||
backh += st::historyReplyHeight;
|
||||
} else if (_previewDrawPreview) {
|
||||
if (_editMsgId
|
||||
|| _replyTo
|
||||
|| hasForward
|
||||
|| _kbReplyTo
|
||||
|| _previewDrawPreview
|
||||
|| _suggestOptions) {
|
||||
backy -= st::historyReplyHeight;
|
||||
backh += st::historyReplyHeight;
|
||||
}
|
||||
|
@ -9361,6 +9468,8 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
|||
- _fieldBarCancel->width()
|
||||
- st::msgReplyPadding.right();
|
||||
_forwardPanel->paint(p, x, backy, available, width());
|
||||
} else if (_suggestOptions) {
|
||||
_suggestOptions->paintBar(p, 0, backy, width());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9462,7 +9571,8 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
|
|||
if (restrictionHidden
|
||||
|| replyTo()
|
||||
|| readyToForward()
|
||||
|| _kbShown) {
|
||||
|| _kbShown
|
||||
|| _suggestOptions) {
|
||||
if (!isSearching()) {
|
||||
drawField(p, clip);
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ class TranslateBar;
|
|||
class ComposeSearch;
|
||||
class SubsectionTabs;
|
||||
struct SelectedQuote;
|
||||
class SuggestOptions;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace HistoryView::Controls {
|
||||
|
@ -214,9 +215,11 @@ public:
|
|||
not_null<PeerData*> peer);
|
||||
|
||||
[[nodiscard]] FullReplyTo replyTo() const;
|
||||
[[nodiscard]] SuggestPostOptions suggestOptions() const;
|
||||
bool lastForceReplyReplied(const FullMsgId &replyTo) const;
|
||||
bool lastForceReplyReplied() const;
|
||||
bool cancelReply(bool lastKeyboardUsed = false);
|
||||
bool cancelSuggestPost();
|
||||
void cancelEdit();
|
||||
void updateForwarding();
|
||||
|
||||
|
@ -676,6 +679,8 @@ private:
|
|||
void setupScheduledToggle();
|
||||
void refreshScheduledToggle();
|
||||
void refreshSendGiftToggle();
|
||||
void refreshSuggestPostToggle();
|
||||
void applySuggestOptions(SuggestPostOptions suggest);
|
||||
void setupSendAsToggle();
|
||||
void refreshSendAsToggle();
|
||||
void refreshAttachBotsMenu();
|
||||
|
@ -709,6 +714,8 @@ private:
|
|||
std::unique_ptr<Ui::SpoilerAnimation> _replySpoiler;
|
||||
mutable base::Timer _updateEditTimeLeftDisplay;
|
||||
|
||||
std::unique_ptr<HistoryView::SuggestOptions> _suggestOptions;
|
||||
|
||||
object_ptr<Ui::IconButton> _fieldBarCancel;
|
||||
|
||||
std::unique_ptr<Ui::RpWidget> _topBars;
|
||||
|
@ -821,6 +828,7 @@ private:
|
|||
object_ptr<Ui::IconButton> _botKeyboardShow;
|
||||
object_ptr<Ui::IconButton> _botKeyboardHide;
|
||||
object_ptr<Ui::IconButton> _botCommandStart;
|
||||
object_ptr<Ui::IconButton> _toggleSuggestPost = { nullptr };
|
||||
object_ptr<Ui::IconButton> _giftToUser = { nullptr };
|
||||
object_ptr<Ui::SilentToggle> _silent = { nullptr };
|
||||
object_ptr<Ui::IconButton> _scheduled = { nullptr };
|
||||
|
|
|
@ -1006,6 +1006,7 @@ void ComposeControls::setCurrentDialogsEntryState(
|
|||
unregisterDraftSources();
|
||||
state.currentReplyTo.topicRootId = _topicRootId;
|
||||
state.currentReplyTo.monoforumPeerId = _monoforumPeerId;
|
||||
state.currentSuggest = SuggestPostOptions();
|
||||
_currentDialogsEntryState = state;
|
||||
updateForwarding();
|
||||
registerDraftSource();
|
||||
|
@ -1299,7 +1300,11 @@ void ComposeControls::saveFieldToHistoryLocalDraft() {
|
|||
const auto key = draftKeyCurrent();
|
||||
_history->setDraft(
|
||||
key,
|
||||
std::make_unique<Data::Draft>(_field, id, _preview->draft()));
|
||||
std::make_unique<Data::Draft>(
|
||||
_field,
|
||||
id,
|
||||
SuggestPostOptions(),
|
||||
_preview->draft()));
|
||||
} else {
|
||||
_history->clearDraft(draftKeyCurrent());
|
||||
}
|
||||
|
@ -1414,6 +1419,7 @@ void ComposeControls::init() {
|
|||
const auto topicRootId = _topicRootId;
|
||||
const auto monoforumPeerId = _monoforumPeerId;
|
||||
const auto reply = _header->replyingToMessage();
|
||||
const auto suggest = SuggestPostOptions();
|
||||
const auto webpage = _preview->draft();
|
||||
|
||||
const auto done = [=](
|
||||
|
@ -1441,7 +1447,7 @@ void ComposeControls::init() {
|
|||
EditDraftOptions({
|
||||
.show = _show,
|
||||
.history = history,
|
||||
.draft = Data::Draft(_field, reply, _preview->draft()),
|
||||
.draft = Data::Draft(_field, reply, suggest, _preview->draft()),
|
||||
.usedLink = _preview->link(),
|
||||
.forward = _header->forwardDraft(),
|
||||
.links = _preview->links(),
|
||||
|
@ -1891,6 +1897,7 @@ void ComposeControls::registerDraftSource() {
|
|||
const auto draft = [=] {
|
||||
return Storage::MessageDraft{
|
||||
_header->getDraftReply(),
|
||||
SuggestPostOptions(),
|
||||
_field->getTextWithTags(),
|
||||
_preview->draft(),
|
||||
};
|
||||
|
@ -2980,6 +2987,7 @@ void ComposeControls::editMessage(not_null<HistoryItem*> item) {
|
|||
.topicRootId = key.topicRootId(),
|
||||
.monoforumPeerId = key.monoforumPeerId(),
|
||||
},
|
||||
SuggestPostOptions(),
|
||||
cursor,
|
||||
Data::WebPageDraft::FromItem(item)));
|
||||
applyDraft();
|
||||
|
@ -3076,6 +3084,7 @@ void ComposeControls::replyToMessage(FullReplyTo id) {
|
|||
std::make_unique<Data::Draft>(
|
||||
TextWithTags(),
|
||||
id,
|
||||
SuggestPostOptions(),
|
||||
MessageCursor(),
|
||||
Data::WebPageDraft()));
|
||||
}
|
||||
|
|
|
@ -1386,6 +1386,7 @@ void ShowReplyToChatBox(
|
|||
history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||
textWithTags,
|
||||
reply,
|
||||
SuggestPostOptions(),
|
||||
cursor,
|
||||
Data::WebPageDraft()));
|
||||
history->clearLocalEditDraft(topicRootId, monoforumPeerId);
|
||||
|
|
|
@ -353,6 +353,7 @@ void ClearDraftReplyTo(
|
|||
.topicRootId = topicRootId,
|
||||
.monoforumPeerId = monoforumPeerId,
|
||||
};
|
||||
draft.suggest = SuggestPostOptions();
|
||||
if (Data::DraftIsNull(&draft)) {
|
||||
history->clearLocalDraft(topicRootId, monoforumPeerId);
|
||||
} else {
|
||||
|
|
|
@ -1830,6 +1830,7 @@ void ChatWidget::refreshTopBarActiveChat() {
|
|||
? EntryState::Section::SavedSublist
|
||||
: EntryState::Section::Replies,
|
||||
.currentReplyTo = replyTo(),
|
||||
.currentSuggest = SuggestPostOptions(),
|
||||
};
|
||||
_topBar->setActiveChat(state, _sendAction.get());
|
||||
_composeControls->setCurrentDialogsEntryState(state);
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "history/view/history_view_message.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "core/click_handler_types.h" // ClickHandlerContext
|
||||
#include "core/ui_integration.h"
|
||||
#include "history/view/history_view_cursor_state.h"
|
||||
|
@ -454,6 +455,20 @@ Message::~Message() {
|
|||
void Message::initPaidInformation() {
|
||||
const auto item = data();
|
||||
if (!item->history()->peer->isUser()) {
|
||||
|
||||
|
||||
if (const auto suggest = item->Get<HistoryMessageSuggestedPost>()) {
|
||||
if (!suggest->stars && !suggest->date) {
|
||||
setServicePreMessage({ { u"suggestion to publish for free anytime"_q } });
|
||||
} else if (!suggest->date) {
|
||||
setServicePreMessage({ { u"suggestion to publish for %1 stars anytime"_q.arg(suggest->stars) }});
|
||||
} else if (!suggest->stars) {
|
||||
setServicePreMessage({ { u"suggestion to publish for free %1"_q.arg(langDateTime(base::unixtime::parse(suggest->date))) }});
|
||||
} else {
|
||||
setServicePreMessage({ { u"suggestion to publish for %1 stars %2"_q.arg(suggest->stars).arg(langDateTime(base::unixtime::parse(suggest->date))) } });
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
const auto media = this->media();
|
||||
|
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "history/view/history_view_suggest_options.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/boxes/choose_date_time.h"
|
||||
#include "ui/widgets/fields/number_input.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace HistoryView {
|
||||
namespace {
|
||||
|
||||
struct EditOptionsArgs {
|
||||
int starsLimit = 0;
|
||||
QString channelName;
|
||||
SuggestPostOptions values;
|
||||
Fn<void(SuggestPostOptions)> save;
|
||||
};
|
||||
|
||||
void EditOptionsBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
EditOptionsArgs &&args) {
|
||||
struct State {
|
||||
rpl::variable<TimeId> date;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
state->date = args.values.date;
|
||||
|
||||
box->setTitle(tr::lng_suggest_options_title());
|
||||
|
||||
const auto container = box->verticalLayout();
|
||||
|
||||
Ui::AddSkip(container);
|
||||
Ui::AddSubsectionTitle(container, tr::lng_suggest_options_price());
|
||||
|
||||
const auto wrap = box->addRow(object_ptr<Ui::FixedHeightWidget>(
|
||||
box,
|
||||
st::editTagField.heightMin));
|
||||
auto owned = object_ptr<Ui::NumberInput>(
|
||||
wrap,
|
||||
st::editTagField,
|
||||
tr::lng_paid_cost_placeholder(),
|
||||
args.values.stars ? QString::number(args.values.stars) : QString(),
|
||||
args.starsLimit);
|
||||
const auto field = owned.data();
|
||||
wrap->widthValue() | rpl::start_with_next([=](int width) {
|
||||
field->move(0, 0);
|
||||
field->resize(width, field->height());
|
||||
wrap->resize(width, field->height());
|
||||
}, wrap->lifetime());
|
||||
field->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
auto p = QPainter(field);
|
||||
st::paidStarIcon.paint(p, 0, st::paidStarIconTop, field->width());
|
||||
}, field->lifetime());
|
||||
field->selectAll();
|
||||
box->setFocusCallback([=] {
|
||||
field->setFocusFast();
|
||||
});
|
||||
|
||||
Ui::AddSkip(container);
|
||||
Ui::AddSkip(container);
|
||||
Ui::AddDividerText(
|
||||
container,
|
||||
tr::lng_suggest_options_price_about(
|
||||
lt_channel,
|
||||
rpl::single(args.channelName)));
|
||||
Ui::AddSkip(container);
|
||||
|
||||
const auto time = Settings::AddButtonWithLabel(
|
||||
container,
|
||||
tr::lng_suggest_options_date(),
|
||||
state->date.value() | rpl::map([](TimeId date) {
|
||||
return date
|
||||
? langDateTime(base::unixtime::parse(date))
|
||||
: tr::lng_suggest_options_date_any(tr::now);
|
||||
}),
|
||||
st::settingsButtonNoIcon);
|
||||
|
||||
time->setClickedCallback([=] {
|
||||
box->uiShow()->show(Box(Ui::ChooseDateTimeBox, Ui::ChooseDateTimeBoxArgs{
|
||||
.title = tr::lng_suggest_options_date(),
|
||||
.submit = tr::lng_settings_save(),
|
||||
.done = [=](TimeId result) { state->date = result; },
|
||||
.min = [] { return base::unixtime::now() + 1; },
|
||||
.time = (state->date.current()
|
||||
? state->date.current()
|
||||
: (base::unixtime::now() + 86400)),
|
||||
}));
|
||||
});
|
||||
|
||||
Ui::AddSkip(container);
|
||||
Ui::AddDividerText(container, tr::lng_suggest_options_date_about());
|
||||
AssertIsDebug()//tr::lng_suggest_options_offer
|
||||
const auto save = [=] {
|
||||
const auto now = uint32(field->getLastText().toULongLong());
|
||||
if (now > args.starsLimit) {
|
||||
field->showError();
|
||||
return;
|
||||
}
|
||||
const auto weak = Ui::MakeWeak(box);
|
||||
args.save({ .stars = now, .date = state->date.current()});
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
|
||||
QObject::connect(field, &Ui::NumberInput::submitted, box, save);
|
||||
|
||||
box->addButton(tr::lng_settings_save(), save);
|
||||
box->addButton(tr::lng_cancel(), [=] {
|
||||
box->closeBox();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SuggestOptions::SuggestOptions(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
SuggestPostOptions values)
|
||||
: _controller(controller)
|
||||
, _peer(peer)
|
||||
, _values(values) {
|
||||
updateTexts();
|
||||
}
|
||||
|
||||
SuggestOptions::~SuggestOptions() = default;
|
||||
|
||||
void SuggestOptions::paintBar(QPainter &p, int x, int y, int outerWidth) {
|
||||
st::historyDirectMessage.icon.paint(
|
||||
p,
|
||||
QPoint(x, y) + st::historySuggestIconPosition,
|
||||
outerWidth);
|
||||
|
||||
x += st::historyReplySkip;
|
||||
auto available = outerWidth
|
||||
- x
|
||||
- st::historyReplyCancel.width
|
||||
- st::msgReplyPadding.right();
|
||||
p.setPen(st::windowActiveTextFg);
|
||||
_title.draw(p, {
|
||||
.position = QPoint(x, y + st::msgReplyPadding.top()),
|
||||
.availableWidth = available,
|
||||
});
|
||||
p.setPen(st::windowSubTextFg);
|
||||
_text.draw(p, {
|
||||
.position = QPoint(
|
||||
x,
|
||||
y + st::msgReplyPadding.top() + st::msgServiceNameFont->height),
|
||||
.availableWidth = available,
|
||||
});
|
||||
}
|
||||
|
||||
void SuggestOptions::edit() {
|
||||
const auto apply = [=](SuggestPostOptions values) {
|
||||
_values = values;
|
||||
updateTexts();
|
||||
_repaints.fire({});
|
||||
};
|
||||
const auto broadcast = _peer->monoforumBroadcast();
|
||||
const auto &appConfig = _peer->session().appConfig();
|
||||
_controller->show(Box(EditOptionsBox, EditOptionsArgs{
|
||||
.starsLimit = appConfig.suggestedPostStarsMax(),
|
||||
.channelName = (broadcast ? broadcast : _peer.get())->shortName(),
|
||||
.values = _values,
|
||||
.save = apply,
|
||||
}));
|
||||
}
|
||||
|
||||
void SuggestOptions::updateTexts() {
|
||||
_title.setText(
|
||||
st::semiboldTextStyle,
|
||||
tr::lng_suggest_bar_title(tr::now));
|
||||
_text.setMarkedText(st::defaultTextStyle, composeText());
|
||||
}
|
||||
|
||||
TextWithEntities SuggestOptions::composeText() const {
|
||||
if (!_values.stars && !_values.date) {
|
||||
return tr::lng_suggest_bar_text(tr::now, Ui::Text::WithEntities);
|
||||
} else if (!_values.date) {
|
||||
return tr::lng_suggest_bar_priced(
|
||||
tr::now,
|
||||
lt_amount,
|
||||
TextWithEntities{ QString::number(_values.stars) + " stars" },
|
||||
Ui::Text::WithEntities);
|
||||
} else if (!_values.stars) {
|
||||
return tr::lng_suggest_bar_dated(
|
||||
tr::now,
|
||||
lt_date,
|
||||
TextWithEntities{
|
||||
langDateTime(base::unixtime::parse(_values.date)),
|
||||
},
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
return tr::lng_suggest_bar_priced_dated(
|
||||
tr::now,
|
||||
lt_amount,
|
||||
TextWithEntities{ QString::number(_values.stars) + " stars," },
|
||||
lt_date,
|
||||
TextWithEntities{
|
||||
langDateTime(base::unixtime::parse(_values.date)),
|
||||
},
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
|
||||
SuggestPostOptions SuggestOptions::values() const {
|
||||
auto result = _values;
|
||||
result.exists = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
rpl::producer<> SuggestOptions::repaints() const {
|
||||
return _repaints.events();
|
||||
}
|
||||
|
||||
rpl::lifetime &SuggestOptions::lifetime() {
|
||||
return _lifetime;
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "api/api_common.h"
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
class SuggestOptions final {
|
||||
public:
|
||||
SuggestOptions(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
SuggestPostOptions values);
|
||||
~SuggestOptions();
|
||||
|
||||
void paintBar(QPainter &p, int x, int y, int outerWidth);
|
||||
void edit();
|
||||
|
||||
[[nodiscard]] SuggestPostOptions values() const;
|
||||
|
||||
[[nodiscard]] rpl::producer<> repaints() const;
|
||||
|
||||
[[nodiscard]] rpl::lifetime &lifetime();
|
||||
|
||||
private:
|
||||
void updateTexts();
|
||||
|
||||
[[nodiscard]] TextWithEntities composeText() const;
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<PeerData*> _peer;
|
||||
|
||||
Ui::Text::String _title;
|
||||
Ui::Text::String _text;
|
||||
|
||||
SuggestPostOptions _values;
|
||||
rpl::event_stream<> _repaints;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
} // namespace HistoryView
|
|
@ -359,6 +359,7 @@ WebViewContext ResolveContext(
|
|||
if (const auto thread = state.key.thread()) {
|
||||
context.action = Api::SendAction(thread);
|
||||
context.action->replyTo = state.currentReplyTo;
|
||||
context.action->options.suggest = state.currentSuggest;
|
||||
} else {
|
||||
context.action = Api::SendAction(bot->owner().history(bot));
|
||||
}
|
||||
|
@ -373,6 +374,7 @@ WebViewContext ResolveContext(
|
|||
.key = (topic ? Key{ topic } : Key{ history }),
|
||||
.section = (topic ? Section::Replies : Section::History),
|
||||
.currentReplyTo = context.action->replyTo,
|
||||
.currentSuggest = context.action->options.suggest,
|
||||
};
|
||||
}
|
||||
return context;
|
||||
|
@ -2615,11 +2617,11 @@ std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu(
|
|||
? SendMenu::Type::SilentOnly
|
||||
: SendMenu::Type::Scheduled;
|
||||
const auto flag = PollData::Flags();
|
||||
const auto replyTo = action.replyTo;
|
||||
Window::PeerMenuCreatePoll(
|
||||
controller,
|
||||
peer,
|
||||
replyTo,
|
||||
action.replyTo,
|
||||
action.options.suggest,
|
||||
flag,
|
||||
flag,
|
||||
source,
|
||||
|
@ -2637,11 +2639,11 @@ std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu(
|
|||
|| action.history->peer->starsPerMessageChecked())
|
||||
? SendMenu::Type::SilentOnly
|
||||
: SendMenu::Type::Scheduled;
|
||||
const auto replyTo = action.replyTo;
|
||||
Window::PeerMenuCreateTodoList(
|
||||
controller,
|
||||
peer,
|
||||
replyTo,
|
||||
action.replyTo,
|
||||
action.options.suggest,
|
||||
source,
|
||||
{ sendMenuType });
|
||||
}, &st::menuIconCreateTodoList);
|
||||
|
|
|
@ -162,6 +162,10 @@ int AppConfig::todoListItemTextLimit() const {
|
|||
return get<int>(u"todo_item_length_max"_q, 64);
|
||||
}
|
||||
|
||||
int AppConfig::suggestedPostStarsMax() const {
|
||||
return get<int>(u"stars_suggested_post_amount_max"_q, 100'000);
|
||||
}
|
||||
|
||||
void AppConfig::refresh(bool force) {
|
||||
if (_requestId || !_api) {
|
||||
if (force) {
|
||||
|
|
|
@ -88,6 +88,8 @@ public:
|
|||
[[nodiscard]] int todoListTitleLimit() const;
|
||||
[[nodiscard]] int todoListItemTextLimit() const;
|
||||
|
||||
[[nodiscard]] int suggestedPostStarsMax() const;
|
||||
|
||||
void refresh(bool force = false);
|
||||
|
||||
private:
|
||||
|
|
|
@ -606,6 +606,7 @@ bool MainWidget::shareUrl(
|
|||
.topicRootId = topicRootId,
|
||||
.monoforumPeerId = monoforumPeerId,
|
||||
},
|
||||
SuggestPostOptions(),
|
||||
cursor,
|
||||
Data::WebPageDraft()));
|
||||
history->clearLocalEditDraft(topicRootId, monoforumPeerId);
|
||||
|
|
|
@ -174,7 +174,7 @@ namespace Media::Stories {
|
|||
Data::ShortcutIdToMTP(session, options.shortcutId),
|
||||
MTP_long(options.effectId),
|
||||
MTP_long(starsPaid),
|
||||
SuggestToMTP(options.suggest)
|
||||
Api::SuggestToMTP(options.suggest)
|
||||
), [=](
|
||||
const MTPUpdates &result,
|
||||
const MTP::Response &response) {
|
||||
|
|
|
@ -632,6 +632,7 @@ void ShortcutMessages::setupComposeControls() {
|
|||
.key = Dialogs::Key{ _history },
|
||||
.section = Dialogs::EntryState::Section::ShortcutMessages,
|
||||
.currentReplyTo = replyTo(),
|
||||
.currentSuggest = SuggestPostOptions(),
|
||||
};
|
||||
_composeControls->setCurrentDialogsEntryState(state);
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ constexpr auto kMultiDraftCursorsTagOld = quint64(0xFFFF'FFFF'FFFF'FF02ULL);
|
|||
constexpr auto kMultiDraftTag = quint64(0xFFFF'FFFF'FFFF'FF03ULL);
|
||||
constexpr auto kMultiDraftCursorsTag = quint64(0xFFFF'FFFF'FFFF'FF04ULL);
|
||||
constexpr auto kRichDraftsTag = quint64(0xFFFF'FFFF'FFFF'FF05ULL);
|
||||
constexpr auto kDraftsTag2 = quint64(0xFFFF'FFFF'FFFF'FF06ULL);
|
||||
|
||||
enum { // Local Storage Keys
|
||||
lskUserMap = 0x00,
|
||||
|
@ -1187,6 +1188,7 @@ void EnumerateDrafts(
|
|||
callback(
|
||||
key,
|
||||
draft->reply,
|
||||
draft->suggest,
|
||||
draft->textWithTags,
|
||||
draft->webpage,
|
||||
draft->cursor);
|
||||
|
@ -1200,6 +1202,7 @@ void EnumerateDrafts(
|
|||
callback(
|
||||
key,
|
||||
draft.reply,
|
||||
draft.suggest,
|
||||
draft.textWithTags,
|
||||
draft.webpage,
|
||||
cursor);
|
||||
|
@ -1265,6 +1268,7 @@ void Account::writeDrafts(not_null<History*> history) {
|
|||
const auto sizeCallback = [&](
|
||||
auto&&, // key
|
||||
const FullReplyTo &reply,
|
||||
SuggestPostOptions suggest,
|
||||
const TextWithTags &text,
|
||||
const Data::WebPageDraft &webpage,
|
||||
auto&&) { // cursor
|
||||
|
@ -1272,6 +1276,7 @@ void Account::writeDrafts(not_null<History*> history) {
|
|||
+ Serialize::stringSize(text.text)
|
||||
+ TextUtilities::SerializeTagsSize(text.tags)
|
||||
+ sizeof(qint64) + sizeof(qint64) // messageId
|
||||
+ sizeof(quint64) // suggest
|
||||
+ Serialize::stringSize(webpage.url)
|
||||
+ sizeof(qint32) // webpage.forceLargeMedia
|
||||
+ sizeof(qint32) // webpage.forceSmallMedia
|
||||
|
@ -1287,13 +1292,14 @@ void Account::writeDrafts(not_null<History*> history) {
|
|||
|
||||
EncryptedDescriptor data(size);
|
||||
data.stream
|
||||
<< quint64(kRichDraftsTag)
|
||||
<< quint64(kDraftsTag2)
|
||||
<< SerializePeerId(peerId)
|
||||
<< quint32(count);
|
||||
|
||||
const auto writeCallback = [&](
|
||||
const Data::DraftKey &key,
|
||||
const FullReplyTo &reply,
|
||||
SuggestPostOptions suggest,
|
||||
const TextWithTags &text,
|
||||
const Data::WebPageDraft &webpage,
|
||||
auto&&) { // cursor
|
||||
|
@ -1303,6 +1309,9 @@ void Account::writeDrafts(not_null<History*> history) {
|
|||
<< TextUtilities::SerializeTags(text.tags)
|
||||
<< qint64(reply.messageId.peer.value)
|
||||
<< qint64(reply.messageId.msg.bare)
|
||||
<< quint64(quint64(quint32(suggest.date))
|
||||
| (quint64(suggest.stars) << 32)
|
||||
| (quint64(suggest.exists) << 63))
|
||||
<< webpage.url
|
||||
<< qint32(webpage.forceLargeMedia ? 1 : 0)
|
||||
<< qint32(webpage.forceSmallMedia ? 1 : 0)
|
||||
|
@ -1359,6 +1368,7 @@ void Account::writeDraftCursors(not_null<History*> history) {
|
|||
const auto writeCallback = [&](
|
||||
const Data::DraftKey &key,
|
||||
auto&&, // reply
|
||||
auto&&, // suggest
|
||||
auto&&, // text
|
||||
auto&&, // webpage
|
||||
const MessageCursor &cursor) { // cursor
|
||||
|
@ -1519,12 +1529,14 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
|
|||
}
|
||||
auto map = Data::HistoryDrafts();
|
||||
const auto keysOld = (tag == kMultiDraftTagOld);
|
||||
const auto rich = (tag == kRichDraftsTag);
|
||||
const auto withSuggest = (tag == kDraftsTag2);
|
||||
const auto rich = (tag == kRichDraftsTag) || withSuggest;
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
TextWithTags text;
|
||||
QByteArray textTagsSerialized;
|
||||
qint64 keyValue = 0;
|
||||
qint64 messageIdPeer = 0, messageIdMsg = 0;
|
||||
quint64 suggestSerialized = 0;
|
||||
qint32 keyValueOld = 0;
|
||||
QString webpageUrl;
|
||||
qint32 webpageForceLargeMedia = 0;
|
||||
|
@ -1558,7 +1570,11 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
|
|||
>> text.text
|
||||
>> textTagsSerialized
|
||||
>> messageIdPeer
|
||||
>> messageIdMsg
|
||||
>> messageIdMsg;
|
||||
if (withSuggest) {
|
||||
draft.stream >> suggestSerialized;
|
||||
}
|
||||
draft.stream
|
||||
>> webpageUrl
|
||||
>> webpageForceLargeMedia
|
||||
>> webpageForceSmallMedia
|
||||
|
@ -1581,6 +1597,13 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
|
|||
MsgId(messageIdMsg)),
|
||||
.topicRootId = key.topicRootId(),
|
||||
},
|
||||
SuggestPostOptions{
|
||||
.exists = uint32(suggestSerialized >> 63),
|
||||
.stars = uint32(
|
||||
(suggestSerialized & ~(1ULL << 63)) >> 32),
|
||||
.date = TimeId(
|
||||
uint32(suggestSerialized & 0xFFFF'FFFFULL)),
|
||||
},
|
||||
MessageCursor(),
|
||||
Data::WebPageDraft{
|
||||
.url = webpageUrl,
|
||||
|
@ -1654,6 +1677,7 @@ void Account::readDraftsWithCursorsLegacy(
|
|||
std::make_unique<Data::Draft>(
|
||||
msgData,
|
||||
FullReplyTo{ FullMsgId(peerId, MsgId(msgReplyTo)) },
|
||||
SuggestPostOptions(),
|
||||
MessageCursor(),
|
||||
Data::WebPageDraft{
|
||||
.removed = (msgPreviewCancelled == 1),
|
||||
|
@ -1665,6 +1689,7 @@ void Account::readDraftsWithCursorsLegacy(
|
|||
std::make_unique<Data::Draft>(
|
||||
editData,
|
||||
FullReplyTo{ FullMsgId(peerId, editMsgId) },
|
||||
SuggestPostOptions(),
|
||||
MessageCursor(),
|
||||
Data::WebPageDraft{
|
||||
.removed = (editPreviewCancelled == 1),
|
||||
|
|
|
@ -53,6 +53,7 @@ enum class StartResult : uchar;
|
|||
|
||||
struct MessageDraft {
|
||||
FullReplyTo reply;
|
||||
SuggestPostOptions suggest;
|
||||
TextWithTags textWithTags;
|
||||
Data::WebPageDraft webpage;
|
||||
};
|
||||
|
|
|
@ -166,6 +166,7 @@ Data::Draft OccupiedDraft(const QString &normalizedName) {
|
|||
+ ";n:"
|
||||
+ normalizedName },
|
||||
FullReplyTo(),
|
||||
SuggestPostOptions(),
|
||||
MessageCursor(),
|
||||
Data::WebPageDraft()
|
||||
};
|
||||
|
|
|
@ -1177,6 +1177,7 @@ void Manager::notificationActivated(
|
|||
.topicRootId = topicRootId,
|
||||
.monoforumPeerId = monoforumPeerId,
|
||||
},
|
||||
SuggestPostOptions(),
|
||||
MessageCursor{
|
||||
length,
|
||||
length,
|
||||
|
|
|
@ -1224,11 +1224,13 @@ void Filler::addCreatePoll() {
|
|||
: SendMenu::Type::Scheduled;
|
||||
const auto flag = PollData::Flags();
|
||||
const auto replyTo = _request.currentReplyTo;
|
||||
const auto suggest = _request.currentSuggest;
|
||||
auto callback = [=] {
|
||||
PeerMenuCreatePoll(
|
||||
controller,
|
||||
peer,
|
||||
replyTo,
|
||||
suggest,
|
||||
flag,
|
||||
flag,
|
||||
source,
|
||||
|
@ -1263,11 +1265,13 @@ void Filler::addCreateTodoList() {
|
|||
? SendMenu::Type::SilentOnly
|
||||
: SendMenu::Type::Scheduled;
|
||||
const auto replyTo = _request.currentReplyTo;
|
||||
const auto suggest = _request.currentSuggest;
|
||||
auto callback = [=] {
|
||||
PeerMenuCreateTodoList(
|
||||
controller,
|
||||
peer,
|
||||
replyTo,
|
||||
suggest,
|
||||
source,
|
||||
{ sendMenuType });
|
||||
};
|
||||
|
@ -1852,6 +1856,7 @@ void PeerMenuCreatePoll(
|
|||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
FullReplyTo replyTo,
|
||||
SuggestPostOptions suggest,
|
||||
PollData::Flags chosen,
|
||||
PollData::Flags disabled,
|
||||
Api::SendType sendType,
|
||||
|
@ -1902,6 +1907,7 @@ void PeerMenuCreatePoll(
|
|||
peer->owner().history(peer),
|
||||
result.options);
|
||||
action.replyTo = replyTo;
|
||||
action.options.suggest = suggest;
|
||||
const auto local = action.history->localDraft(
|
||||
replyTo.topicRootId,
|
||||
replyTo.monoforumPeerId);
|
||||
|
@ -1962,6 +1968,7 @@ void PeerMenuCreateTodoList(
|
|||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
FullReplyTo replyTo,
|
||||
SuggestPostOptions suggest,
|
||||
Api::SendType sendType,
|
||||
SendMenu::Details sendMenuDetails) {
|
||||
if (!peer->session().premium()) {
|
||||
|
@ -2008,6 +2015,7 @@ void PeerMenuCreateTodoList(
|
|||
peer->owner().history(peer),
|
||||
result.options);
|
||||
action.replyTo = replyTo;
|
||||
action.options.suggest = suggest;
|
||||
const auto local = action.history->localDraft(
|
||||
replyTo.topicRootId,
|
||||
replyTo.monoforumPeerId);
|
||||
|
|
|
@ -107,6 +107,7 @@ void PeerMenuCreatePoll(
|
|||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
FullReplyTo replyTo = FullReplyTo(),
|
||||
SuggestPostOptions suggest = SuggestPostOptions(),
|
||||
PollData::Flags chosen = PollData::Flags(),
|
||||
PollData::Flags disabled = PollData::Flags(),
|
||||
Api::SendType sendType = Api::SendType::Normal,
|
||||
|
@ -121,6 +122,7 @@ void PeerMenuCreateTodoList(
|
|||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
FullReplyTo replyTo = FullReplyTo(),
|
||||
SuggestPostOptions suggest = SuggestPostOptions(),
|
||||
Api::SendType sendType = Api::SendType::Normal,
|
||||
SendMenu::Details sendMenuDetails = SendMenu::Details());
|
||||
void PeerMenuEditTodoList(
|
||||
|
|
|
@ -2114,9 +2114,13 @@ bool SessionController::switchInlineQuery(
|
|||
&& to.currentReplyTo.quote.empty()) {
|
||||
to.currentReplyTo.messageId.msg = MsgId();
|
||||
}
|
||||
if (!history->suggestDraftAllowed()) {
|
||||
to.currentSuggest = SuggestPostOptions();
|
||||
}
|
||||
auto draft = std::make_unique<Data::Draft>(
|
||||
textWithTags,
|
||||
to.currentReplyTo,
|
||||
to.currentSuggest,
|
||||
cursor,
|
||||
Data::WebPageDraft());
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue