Improve reply options edit design.
BIN
Telegram/Resources/icons/menu/link_above.png
Normal file
After Width: | Height: | Size: 450 B |
BIN
Telegram/Resources/icons/menu/link_above@2x.png
Normal file
After Width: | Height: | Size: 725 B |
BIN
Telegram/Resources/icons/menu/link_above@3x.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
Telegram/Resources/icons/menu/link_below.png
Normal file
After Width: | Height: | Size: 454 B |
BIN
Telegram/Resources/icons/menu/link_below@2x.png
Normal file
After Width: | Height: | Size: 761 B |
BIN
Telegram/Resources/icons/menu/link_below@3x.png
Normal file
After Width: | Height: | Size: 1,017 B |
BIN
Telegram/Resources/icons/menu/link_enlarge.png
Normal file
After Width: | Height: | Size: 582 B |
BIN
Telegram/Resources/icons/menu/link_enlarge@2x.png
Normal file
After Width: | Height: | Size: 965 B |
BIN
Telegram/Resources/icons/menu/link_enlarge@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/menu/link_shrink.png
Normal file
After Width: | Height: | Size: 542 B |
BIN
Telegram/Resources/icons/menu/link_shrink@2x.png
Normal file
After Width: | Height: | Size: 991 B |
BIN
Telegram/Resources/icons/menu/link_shrink@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
|
@ -2530,6 +2530,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_context_attached_stickers" = "Attached Stickers";
|
||||
"lng_context_to_msg" = "Go To Message";
|
||||
"lng_context_reply_msg" = "Reply";
|
||||
"lng_context_quote_and_reply" = "Quote & Reply";
|
||||
"lng_context_edit_msg" = "Edit";
|
||||
"lng_context_forward_msg" = "Forward Message";
|
||||
"lng_context_send_now_msg" = "Send now";
|
||||
|
@ -2634,6 +2635,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_inline_switch_choose" = "Choose conversation...";
|
||||
"lng_inline_switch_cant" = "Sorry, no way to write here :(";
|
||||
|
||||
"lng_reply_in_another_title" = "Reply in...";
|
||||
"lng_reply_in_another_chat" = "Reply in Another Chat";
|
||||
"lng_reply_show_in_chat" = "Show in Chat";
|
||||
"lng_reply_remove" = "Do Not Reply";
|
||||
"lng_reply_about_quote" = "You can select specific part to quote.";
|
||||
"lng_reply_options_header" = "Reply to Message";
|
||||
"lng_reply_options_quote" = "Update Quote";
|
||||
"lng_reply_header_short" = "Reply";
|
||||
"lng_reply_quote_selected" = "Quote Selected";
|
||||
"lng_link_options_header" = "Link Preview Settings";
|
||||
"lng_link_header_short" = "Link";
|
||||
"lng_link_move_up" = "Move Up";
|
||||
"lng_link_move_down" = "Move Down";
|
||||
"lng_link_shrink_photo" = "Shrink Photo";
|
||||
"lng_link_enlarge_photo" = "Enlarge Photo";
|
||||
"lng_link_remove" = "Do Not Preview";
|
||||
"lng_link_about_choose" = "Click on a link to generate its preview.";
|
||||
|
||||
"lng_share_cant" = "Sorry, no way to share here :(";
|
||||
"lng_reply_cant" = "Sorry, no way to reply to an old message in supergroup :(";
|
||||
"lng_reply_cant_forward" = "Sorry, you can't reply to a message that was sent before the group was upgraded to a supergroup. Do you wish to forward it and add your comment?";
|
||||
|
|
|
@ -70,22 +70,8 @@ ChatFilter ChatFilter::FromTL(
|
|||
| (data.is_exclude_read() ? Flag::NoRead : Flag(0))
|
||||
| (data.is_exclude_archived() ? Flag::NoArchived : Flag(0));
|
||||
auto &&to_histories = ranges::views::transform([&](
|
||||
const MTPInputPeer &data) {
|
||||
const auto peer = data.match([&](const MTPDinputPeerUser &data) {
|
||||
const auto user = owner->user(data.vuser_id().v);
|
||||
user->setAccessHash(data.vaccess_hash().v);
|
||||
return (PeerData*)user;
|
||||
}, [&](const MTPDinputPeerChat &data) {
|
||||
return (PeerData*)owner->chat(data.vchat_id().v);
|
||||
}, [&](const MTPDinputPeerChannel &data) {
|
||||
const auto channel = owner->channel(data.vchannel_id().v);
|
||||
channel->setAccessHash(data.vaccess_hash().v);
|
||||
return (PeerData*)channel;
|
||||
}, [&](const MTPDinputPeerSelf &data) {
|
||||
return (PeerData*)owner->session().user();
|
||||
}, [&](const auto &data) {
|
||||
return (PeerData*)nullptr;
|
||||
});
|
||||
const MTPInputPeer &input) {
|
||||
const auto peer = Data::PeerFromInputMTP(owner, input);
|
||||
return peer ? owner->history(peer).get() : nullptr;
|
||||
}) | ranges::views::filter([](History *history) {
|
||||
return history != nullptr;
|
||||
|
|
|
@ -81,12 +81,10 @@ void ApplyPeerCloudDraft(
|
|||
session,
|
||||
draft.ventities().value_or_empty()))
|
||||
};
|
||||
const auto reply = draft.vreply_to()
|
||||
? ReplyFieldsFromMTP(history, *draft.vreply_to())
|
||||
: ReplyFields();
|
||||
const auto replyPeerId = reply.externalPeerId
|
||||
? reply.externalPeerId
|
||||
: peerId;
|
||||
auto replyTo = draft.vreply_to()
|
||||
? ReplyToFromMTP(history, *draft.vreply_to())
|
||||
: FullReplyTo();
|
||||
replyTo.topicRootId = topicRootId;
|
||||
auto webpage = WebPageDraft{
|
||||
.invert = draft.is_invert_media(),
|
||||
.removed = draft.is_no_webpage(),
|
||||
|
@ -106,14 +104,7 @@ void ApplyPeerCloudDraft(
|
|||
}
|
||||
auto cloudDraft = std::make_unique<Draft>(
|
||||
textWithTags,
|
||||
FullReplyTo{
|
||||
.messageId = FullMsgId(replyPeerId, reply.messageId),
|
||||
.quote = reply.quote,
|
||||
.storyId = (reply.storyId
|
||||
? FullStoryId{ replyPeerId, reply.storyId }
|
||||
: FullStoryId()),
|
||||
.topicRootId = topicRootId,
|
||||
},
|
||||
replyTo,
|
||||
MessageCursor(Ui::kQFixedMax, Ui::kQFixedMax, Ui::kQFixedMax),
|
||||
std::move(webpage));
|
||||
cloudDraft->date = date;
|
||||
|
|
|
@ -126,6 +126,40 @@ AllowedReactions Parse(const MTPChatReactions &value) {
|
|||
});
|
||||
}
|
||||
|
||||
PeerData *PeerFromInputMTP(
|
||||
not_null<Session*> owner,
|
||||
const MTPInputPeer &input) {
|
||||
return input.match([&](const MTPDinputPeerUser &data) {
|
||||
const auto user = owner->user(data.vuser_id().v);
|
||||
user->setAccessHash(data.vaccess_hash().v);
|
||||
return (PeerData*)user;
|
||||
}, [&](const MTPDinputPeerChat &data) {
|
||||
return (PeerData*)owner->chat(data.vchat_id().v);
|
||||
}, [&](const MTPDinputPeerChannel &data) {
|
||||
const auto channel = owner->channel(data.vchannel_id().v);
|
||||
channel->setAccessHash(data.vaccess_hash().v);
|
||||
return (PeerData*)channel;
|
||||
}, [&](const MTPDinputPeerSelf &data) {
|
||||
return (PeerData*)owner->session().user();
|
||||
}, [&](const auto &data) {
|
||||
return (PeerData*)nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
UserData *UserFromInputMTP(
|
||||
not_null<Session*> owner,
|
||||
const MTPInputUser &input) {
|
||||
return input.match([&](const MTPDinputUser &data) {
|
||||
const auto user = owner->user(data.vuser_id().v);
|
||||
user->setAccessHash(data.vaccess_hash().v);
|
||||
return user.get();
|
||||
}, [&](const MTPDinputUserSelf &data) {
|
||||
return owner->session().user().get();
|
||||
}, [](const auto &data) {
|
||||
return (UserData*)nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
||||
PeerClickHandler::PeerClickHandler(not_null<PeerData*> peer)
|
||||
|
|
|
@ -116,6 +116,12 @@ bool operator<(const AllowedReactions &a, const AllowedReactions &b);
|
|||
bool operator==(const AllowedReactions &a, const AllowedReactions &b);
|
||||
|
||||
[[nodiscard]] AllowedReactions Parse(const MTPChatReactions &value);
|
||||
[[nodiscard]] PeerData *PeerFromInputMTP(
|
||||
not_null<Session*> owner,
|
||||
const MTPInputPeer &input);
|
||||
[[nodiscard]] UserData *UserFromInputMTP(
|
||||
not_null<Session*> owner,
|
||||
const MTPInputUser &input);
|
||||
|
||||
} // namespace Data
|
||||
|
||||
|
|
|
@ -2216,35 +2216,6 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
return;
|
||||
}
|
||||
const auto itemId = item->fullId();
|
||||
const auto canSendReply = [&] {
|
||||
const auto peer = item->history()->peer;
|
||||
const auto topic = item->topic();
|
||||
return topic
|
||||
? Data::CanSendAnything(topic)
|
||||
: (Data::CanSendAnything(peer)
|
||||
&& (!peer->isChannel() || peer->asChannel()->amIn()));
|
||||
}();
|
||||
const auto canReply = canSendReply || [&] {
|
||||
const auto peer = item->history()->peer;
|
||||
if (const auto chat = peer->asChat()) {
|
||||
return !chat->isForbidden();
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
return !channel->isForbidden();
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
if (canReply) {
|
||||
const auto quote = selectedQuote(item);
|
||||
_menu->addAction(tr::lng_context_reply_msg(tr::now), [=] {
|
||||
if (canSendReply) {
|
||||
_widget->replyToMessage({ itemId, quote });
|
||||
} else {
|
||||
HistoryView::Controls::ShowReplyToChatBox(
|
||||
controller->uiShow(),
|
||||
{ itemId, quote });
|
||||
}
|
||||
}, &st::menuIconReply);
|
||||
}
|
||||
const auto repliesCount = item->repliesCount();
|
||||
const auto withReplies = (repliesCount > 0);
|
||||
const auto topicRootId = item->history()->isForum()
|
||||
|
@ -2408,6 +2379,45 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
}
|
||||
};
|
||||
|
||||
const auto addReplyAction = [&](HistoryItem *item) {
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const auto canSendReply = [&] {
|
||||
const auto peer = item->history()->peer;
|
||||
const auto topic = item->topic();
|
||||
return topic
|
||||
? Data::CanSendAnything(topic)
|
||||
: (Data::CanSendAnything(peer)
|
||||
&& (!peer->isChannel() || peer->asChannel()->amIn()));
|
||||
}();
|
||||
const auto canReply = canSendReply || [&] {
|
||||
const auto peer = item->history()->peer;
|
||||
if (const auto chat = peer->asChat()) {
|
||||
return !chat->isForbidden();
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
return !channel->isForbidden();
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
if (canReply) {
|
||||
const auto itemId = item->fullId();
|
||||
const auto quote = selectedQuote(item);
|
||||
const auto text = quote.empty()
|
||||
? tr::lng_context_reply_msg(tr::now)
|
||||
: tr::lng_context_quote_and_reply(tr::now);
|
||||
_menu->addAction(text, [=] {
|
||||
if (canSendReply) {
|
||||
_widget->replyToMessage({ itemId, quote });
|
||||
} else {
|
||||
HistoryView::Controls::ShowReplyToChatBox(
|
||||
controller->uiShow(),
|
||||
{ itemId, quote });
|
||||
}
|
||||
}, &st::menuIconReply);
|
||||
}
|
||||
};
|
||||
|
||||
const auto lnkPhoto = link
|
||||
? reinterpret_cast<PhotoData*>(
|
||||
link->property(kPhotoLinkMediaProperty).toULongLong())
|
||||
|
@ -2419,6 +2429,8 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
if (lnkPhoto || lnkDocument) {
|
||||
const auto item = _dragStateItem;
|
||||
const auto itemId = item ? item->fullId() : FullMsgId();
|
||||
addReplyAction(item);
|
||||
|
||||
if (isUponSelected > 0) {
|
||||
const auto selectedText = getSelectedText();
|
||||
if (!hasCopyRestrictionForSelected()
|
||||
|
@ -2529,6 +2541,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
: QString();
|
||||
|
||||
if (isUponSelected > 0) {
|
||||
addReplyAction(item);
|
||||
const auto selectedText = getSelectedText();
|
||||
if (!hasCopyRestrictionForSelected() && !selectedText.empty()) {
|
||||
_menu->addAction(
|
||||
|
@ -2551,6 +2564,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
}
|
||||
addItemActions(item, item);
|
||||
} else {
|
||||
addReplyAction(item);
|
||||
addItemActions(item, albumPartItem);
|
||||
if (item && !isUponSelected) {
|
||||
const auto media = (view ? view->media() : nullptr);
|
||||
|
|
|
@ -435,6 +435,42 @@ ReplyFields ReplyFieldsFromMTP(
|
|||
});
|
||||
}
|
||||
|
||||
FullReplyTo ReplyToFromMTP(
|
||||
not_null<History*> history,
|
||||
const MTPInputReplyTo &reply) {
|
||||
return reply.match([&](const MTPDinputReplyToMessage &data) {
|
||||
auto result = FullReplyTo{
|
||||
.messageId = { history->peer->id, data.vreply_to_msg_id().v },
|
||||
};
|
||||
if (const auto peer = data.vreply_to_peer_id()) {
|
||||
const auto parsed = Data::PeerFromInputMTP(
|
||||
&history->owner(),
|
||||
*peer);
|
||||
if (!parsed) {
|
||||
return FullReplyTo();
|
||||
}
|
||||
result.messageId.peer = parsed->id;
|
||||
}
|
||||
result.topicRootId = data.vtop_msg_id().value_or_empty();
|
||||
result.quote = TextWithEntities{
|
||||
qs(data.vquote_text().value_or_empty()),
|
||||
Api::EntitiesFromMTP(
|
||||
&history->session(),
|
||||
data.vquote_entities().value_or_empty()),
|
||||
};
|
||||
return result;
|
||||
}, [&](const MTPDinputReplyToStory &data) {
|
||||
if (const auto parsed = Data::UserFromInputMTP(
|
||||
&history->owner(),
|
||||
data.vuser_id())) {
|
||||
return FullReplyTo{
|
||||
.storyId = { parsed->id, data.vstory_id().v },
|
||||
};
|
||||
}
|
||||
return FullReplyTo();
|
||||
});
|
||||
}
|
||||
|
||||
HistoryMessageReply::HistoryMessageReply() = default;
|
||||
|
||||
HistoryMessageReply &HistoryMessageReply::operator=(
|
||||
|
|
|
@ -245,6 +245,10 @@ struct ReplyFields {
|
|||
not_null<History*> history,
|
||||
const MTPMessageReplyHeader &reply);
|
||||
|
||||
[[nodiscard]] FullReplyTo ReplyToFromMTP(
|
||||
not_null<History*> history,
|
||||
const MTPInputReplyTo &reply);
|
||||
|
||||
struct HistoryMessageReply
|
||||
: public RuntimeComponent<HistoryMessageReply, HistoryItem> {
|
||||
HistoryMessageReply();
|
||||
|
|
|
@ -6237,7 +6237,11 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
|||
}
|
||||
} else if (const auto reply = replyTo()) {
|
||||
const auto done = [=](FullReplyTo replyTo) {
|
||||
replyToMessage(replyTo);
|
||||
if (replyTo) {
|
||||
replyToMessage(replyTo);
|
||||
} else {
|
||||
cancelReply();
|
||||
}
|
||||
};
|
||||
const auto highlight = [=] {
|
||||
controller()->showPeerHistory(
|
||||
|
|
|
@ -626,7 +626,11 @@ void FieldHeader::init() {
|
|||
const auto history = _history;
|
||||
const auto topicRootId = _topicRootId;
|
||||
const auto done = [=](FullReplyTo replyTo) {
|
||||
replyToMessage(replyTo);
|
||||
if (replyTo) {
|
||||
replyToMessage(replyTo);
|
||||
} else {
|
||||
_replyCancelled.fire({});
|
||||
}
|
||||
};
|
||||
const auto clearOldReplyTo = [=, id = reply.messageId] {
|
||||
ClearDraftReplyTo(history, topicRootId, id);
|
||||
|
|
|
@ -118,9 +118,7 @@ private:
|
|||
bool selectionStartAfterSymbol = false;
|
||||
};
|
||||
|
||||
const auto preview = box->addRow(
|
||||
object_ptr<Ui::RpWidget>(box),
|
||||
QMargins(0, 0, 0, st::settingsThemesTopSkip));
|
||||
const auto preview = box->addRow(object_ptr<Ui::RpWidget>(box), {});
|
||||
const auto state = preview->lifetime().make_state<State>();
|
||||
state->theme = DefaultThemeOn(preview->lifetime());
|
||||
|
||||
|
@ -246,14 +244,17 @@ private:
|
|||
preview->resize(width, height);
|
||||
}, preview->lifetime());
|
||||
|
||||
preview->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
box->setAttribute(Qt::WA_OpaquePaintEvent, false);
|
||||
box->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
Window::SectionWidget::PaintBackground(
|
||||
state->theme.get(),
|
||||
preview,
|
||||
preview->window()->height(),
|
||||
box,
|
||||
box->window()->height(),
|
||||
0,
|
||||
clip);
|
||||
}, box->lifetime());
|
||||
|
||||
preview->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
auto p = Painter(preview);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.translate(state->position);
|
||||
|
@ -366,7 +367,7 @@ void ShowReplyToChatBox(
|
|||
|
||||
private:
|
||||
void prepareViewHook() override {
|
||||
delegate()->peerListSetTitle(rpl::single(u"Reply in..."_q));
|
||||
delegate()->peerListSetTitle(tr::lng_reply_in_another_title());
|
||||
}
|
||||
|
||||
rpl::event_stream<Chosen> _singleChosen;
|
||||
|
@ -382,7 +383,10 @@ void ShowReplyToChatBox(
|
|||
const auto state = [&] {
|
||||
auto controller = std::make_unique<Controller>(session);
|
||||
const auto controllerRaw = controller.get();
|
||||
auto box = Box<PeerListBox>(std::move(controller), nullptr);
|
||||
auto box = Box<PeerListBox>(std::move(controller), [=](
|
||||
not_null<PeerListBox*> box) {
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
});
|
||||
const auto boxRaw = box.data();
|
||||
show->show(std::move(box));
|
||||
auto state = State{ boxRaw, controllerRaw };
|
||||
|
@ -440,28 +444,31 @@ void EditReplyOptions(
|
|||
show->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
box->setWidth(st::boxWideWidth);
|
||||
|
||||
struct State {
|
||||
rpl::variable<TextWithEntities> quote;
|
||||
const auto bottom = box->setPinnedToBottomContent(
|
||||
object_ptr<Ui::VerticalLayout>(box));
|
||||
const auto addSkip = [&] {
|
||||
const auto skip = bottom->add(object_ptr<Ui::FixedHeightWidget>(
|
||||
bottom,
|
||||
st::settingsPrivacySkipTop));
|
||||
skip->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
QPainter(skip).fillRect(clip, st::boxBg);
|
||||
}, skip->lifetime());
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
state->quote = AddQuoteTracker(box, show, item, reply.quote);
|
||||
|
||||
box->setTitle(reply.quote.empty()
|
||||
? rpl::single(u"Reply to Message"_q)
|
||||
: rpl::single(u"Update Quote"_q));
|
||||
addSkip();
|
||||
|
||||
Settings::AddButton(
|
||||
box->verticalLayout(),
|
||||
rpl::single(u"Reply in another chat"_q),
|
||||
bottom,
|
||||
tr::lng_reply_in_another_chat(),
|
||||
st::settingsButton,
|
||||
{ &st::menuIconReply }
|
||||
{ &st::menuIconReplace }
|
||||
)->setClickedCallback([=] {
|
||||
ShowReplyToChatBox(show, reply, clearOldDraft);
|
||||
});
|
||||
|
||||
Settings::AddButton(
|
||||
box->verticalLayout(),
|
||||
rpl::single(u"Show message"_q),
|
||||
bottom,
|
||||
tr::lng_reply_show_in_chat(),
|
||||
st::settingsButton,
|
||||
{ &st::menuIconShowInChat }
|
||||
)->setClickedCallback(highlight);
|
||||
|
@ -475,15 +482,38 @@ void EditReplyOptions(
|
|||
};
|
||||
|
||||
Settings::AddButton(
|
||||
box->verticalLayout(),
|
||||
rpl::single(u"Remove reply"_q),
|
||||
bottom,
|
||||
tr::lng_reply_remove(),
|
||||
st::settingsAttentionButtonWithIcon,
|
||||
{ &st::menuIconDeleteAttention }
|
||||
)->setClickedCallback([=] {
|
||||
finish({});
|
||||
});
|
||||
|
||||
box->addButton(rpl::single(u"Apply"_q), [=] {
|
||||
if (!item->originalText().empty()) {
|
||||
addSkip();
|
||||
Settings::AddDividerText(
|
||||
bottom,
|
||||
tr::lng_reply_about_quote());
|
||||
}
|
||||
|
||||
struct State {
|
||||
rpl::variable<TextWithEntities> quote;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
state->quote = AddQuoteTracker(box, show, item, reply.quote);
|
||||
|
||||
box->setTitle(reply.quote.empty()
|
||||
? tr::lng_reply_options_header()
|
||||
: tr::lng_reply_options_quote());
|
||||
|
||||
auto save = state->quote.value(
|
||||
) | rpl::map([=](const TextWithEntities "e) {
|
||||
return quote.empty()
|
||||
? tr::lng_settings_save()
|
||||
: tr::lng_reply_quote_selected();
|
||||
}) | rpl::flatten_latest();
|
||||
box->addButton(std::move(save), [=] {
|
||||
auto result = reply;
|
||||
result.quote = state->quote.current();
|
||||
finish(result);
|
||||
|
|
|
@ -761,7 +761,7 @@ contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<
|
|||
contacts.topPeersDisabled#b52c939d = contacts.TopPeers;
|
||||
|
||||
draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage;
|
||||
draftMessage#db074fa8 flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?MessageReplyHeader message:string entities:flags.3?Vector<MessageEntity> media:flags.5?MessageMedia date:int = DraftMessage;
|
||||
draftMessage#3fccf7ef flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector<MessageEntity> media:flags.5?InputMedia date:int = DraftMessage;
|
||||
|
||||
messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers;
|
||||
messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
|
||||
|
|
|
@ -140,6 +140,11 @@ menuIconPremium: icon {{ "menu/premium", menuIconColor }};
|
|||
menuIconIpAddress: icon {{ "menu/ip_address", menuIconColor }};
|
||||
menuIconAddress: icon {{ "menu/payment_address", menuIconColor }};
|
||||
menuIconShowAll: icon {{ "menu/all_media", menuIconColor }};
|
||||
menuIconReplace: icon {{ "chat/input_replace", menuIconColor }};
|
||||
menuIconAbove: icon {{ "menu/link_above", menuIconColor }};
|
||||
menuIconBelow: icon {{ "menu/link_below", menuIconColor }};
|
||||
menuIconEnlarge: icon {{ "menu/link_enlarge", menuIconColor }};
|
||||
menuIconShrink: icon {{ "menu/link_shrink", menuIconColor }};
|
||||
|
||||
menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }};
|
||||
menuIconTTLAnyTextPosition: point(11px, 22px);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 71d24af3a840d15a6cc0a3a8a1e9cbe77a604739
|
||||
Subproject commit c36559a6797f02d8a56a414ac91f9c6fd08b5270
|