mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-26 19:14:02 +02:00
Merge branch 'games' into player
This commit is contained in:
commit
37b5329af3
53 changed files with 12563 additions and 9238 deletions
Binary file not shown.
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 177 KiB |
Binary file not shown.
Before Width: | Height: | Size: 238 KiB After Width: | Height: | Size: 241 KiB |
|
@ -1866,6 +1866,8 @@ emojiSymbolsActive: sprite(287px, 286px, 21px, 22px);
|
|||
stickersSettings: sprite(140px, 124px, 21px, 22px);
|
||||
savedGifsOver: sprite(329px, 286px, 21px, 22px);
|
||||
savedGifsActive: sprite(350px, 286px, 21px, 22px);
|
||||
featuredStickersOver: sprite(329px, 264px, 21px, 22px);
|
||||
featuredStickersActive: sprite(350px, 264px, 21px, 22px);
|
||||
|
||||
stickersSettingsUnreadSize: 17px;
|
||||
stickersSettingsUnreadPosition: point(4px, 5px);
|
||||
|
|
|
@ -580,6 +580,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
"lng_action_pinned_media_contact" = "a contact information";
|
||||
"lng_action_pinned_media_location" = "a location mark";
|
||||
"lng_action_pinned_media_sticker" = "a sticker";
|
||||
"lng_action_game_score" = "{from} scored {score} in {game}";
|
||||
|
||||
"lng_profile_migrate_reached" = "{count:_not_used_|# member|# members} limit reached";
|
||||
"lng_profile_migrate_body" = "To get over this limit, you can upgrade your group to a supergroup.";
|
||||
|
@ -683,6 +684,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
"lng_switch_stickers" = "Stickers";
|
||||
"lng_switch_stickers_gifs" = "GIFs & Stickers";
|
||||
"lng_switch_emoji" = "Emoji";
|
||||
"lng_stickers_featured_add" = "Add";
|
||||
|
||||
"lng_saved_gifs" = "Saved GIFs";
|
||||
"lng_inline_bot_results" = "Results from {inline_bot}";
|
||||
|
@ -762,6 +764,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_open_this_link" = "Open this link?";
|
||||
"lng_open_link" = "Open";
|
||||
"lng_allow_bot_pass" = "Do you allow {bot_name} to pass your Telegram name and id to the web pages you open via this bot?";
|
||||
"lng_allow_bot" = "Allow";
|
||||
|
||||
"lng_bot_start" = "Start";
|
||||
"lng_bot_choose_group" = "Choose Group";
|
||||
|
@ -870,6 +874,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
"lng_reply_cant" = "Sorry, no way to reply to an old message in supergroup :(";
|
||||
"lng_reply_cant_forward" = "Sorry, no way to reply to an old message in supergroup :( Do you wish to forward it and add your comment?";
|
||||
|
||||
"lng_share_title" = "Share to";
|
||||
"lng_share_confirm" = "Share";
|
||||
"lng_share_wrong_user" = "This game was opened from a different user.";
|
||||
|
||||
"lng_contact_phone" = "Phone number";
|
||||
"lng_enter_contact_data" = "New Contact";
|
||||
"lng_edit_group_title" = "Edit group name";
|
||||
|
|
|
@ -1857,7 +1857,8 @@ namespace {
|
|||
photoSizes.push_back(MTP_photoSize(MTP_string("a"), uphoto.vphoto_small, MTP_int(160), MTP_int(160), MTP_int(0)));
|
||||
photoSizes.push_back(MTP_photoSize(MTP_string("c"), uphoto.vphoto_big, MTP_int(640), MTP_int(640), MTP_int(0)));
|
||||
|
||||
return MTP_photo(uphoto.vphoto_id, MTP_long(0), date, MTP_vector<MTPPhotoSize>(photoSizes));
|
||||
MTPDphoto::Flags photoFlags = 0;
|
||||
return MTP_photo(MTP_flags(photoFlags), uphoto.vphoto_id, MTP_long(0), date, MTP_vector<MTPPhotoSize>(photoSizes));
|
||||
}
|
||||
return MTP_photoEmpty(MTP_long(0));
|
||||
}
|
||||
|
|
|
@ -877,7 +877,7 @@ bool AppClass::peerPhotoFail(PeerId peer, const RPCError &error) {
|
|||
|
||||
void AppClass::peerClearPhoto(PeerId id) {
|
||||
if (MTP::authedId() && peerToUser(id) == MTP::authedId()) {
|
||||
MTP::send(MTPphotos_UpdateProfilePhoto(MTP_inputPhotoEmpty(), MTP_inputPhotoCropAuto()), rpcDone(&AppClass::selfPhotoCleared), rpcFail(&AppClass::peerPhotoFail, id));
|
||||
MTP::send(MTPphotos_UpdateProfilePhoto(MTP_inputPhotoEmpty()), rpcDone(&AppClass::selfPhotoCleared), rpcFail(&AppClass::peerPhotoFail, id));
|
||||
} else if (peerIsChat(id)) {
|
||||
MTP::send(MTPmessages_EditChatPhoto(peerToBareMTPInt(id), MTP_inputChatPhotoEmpty()), rpcDone(&AppClass::chatPhotoCleared, id), rpcFail(&AppClass::peerPhotoFail, id));
|
||||
} else if (peerIsChannel(id)) {
|
||||
|
@ -966,17 +966,17 @@ void AppClass::killDownloadSessions() {
|
|||
void AppClass::photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file) {
|
||||
if (!App::self()) return;
|
||||
|
||||
QMap<FullMsgId, PeerId>::iterator i = photoUpdates.find(msgId);
|
||||
auto i = photoUpdates.find(msgId);
|
||||
if (i != photoUpdates.end()) {
|
||||
PeerId id = i.value();
|
||||
auto id = i.value();
|
||||
if (MTP::authedId() && peerToUser(id) == MTP::authedId()) {
|
||||
MTP::send(MTPphotos_UploadProfilePhoto(file, MTP_string(""), MTP_inputGeoPointEmpty(), MTP_inputPhotoCrop(MTP_double(0), MTP_double(0), MTP_double(100))), rpcDone(&AppClass::selfPhotoDone), rpcFail(&AppClass::peerPhotoFail, id));
|
||||
MTP::send(MTPphotos_UploadProfilePhoto(file), rpcDone(&AppClass::selfPhotoDone), rpcFail(&AppClass::peerPhotoFail, id));
|
||||
} else if (peerIsChat(id)) {
|
||||
History *hist = App::history(id);
|
||||
hist->sendRequestId = MTP::send(MTPmessages_EditChatPhoto(hist->peer->asChat()->inputChat, MTP_inputChatUploadedPhoto(file, MTP_inputPhotoCrop(MTP_double(0), MTP_double(0), MTP_double(100)))), rpcDone(&AppClass::chatPhotoDone, id), rpcFail(&AppClass::peerPhotoFail, id), 0, 0, hist->sendRequestId);
|
||||
auto history = App::history(id);
|
||||
history->sendRequestId = MTP::send(MTPmessages_EditChatPhoto(history->peer->asChat()->inputChat, MTP_inputChatUploadedPhoto(file)), rpcDone(&AppClass::chatPhotoDone, id), rpcFail(&AppClass::peerPhotoFail, id), 0, 0, history->sendRequestId);
|
||||
} else if (peerIsChannel(id)) {
|
||||
History *hist = App::history(id);
|
||||
hist->sendRequestId = MTP::send(MTPchannels_EditPhoto(hist->peer->asChannel()->inputChannel, MTP_inputChatUploadedPhoto(file, MTP_inputPhotoCrop(MTP_double(0), MTP_double(0), MTP_double(100)))), rpcDone(&AppClass::chatPhotoDone, id), rpcFail(&AppClass::peerPhotoFail, id), 0, 0, hist->sendRequestId);
|
||||
auto history = App::history(id);
|
||||
history->sendRequestId = MTP::send(MTPchannels_EditPhoto(history->peer->asChannel()->inputChannel, MTP_inputChatUploadedPhoto(file)), rpcDone(&AppClass::chatPhotoDone, id), rpcFail(&AppClass::peerPhotoFail, id), 0, 0, history->sendRequestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1053,7 +1053,8 @@ void AppClass::uploadProfilePhoto(const QImage &tosend, const PeerId &peerId) {
|
|||
|
||||
PhotoId id = rand_value<PhotoId>();
|
||||
|
||||
MTPPhoto photo(MTP_photo(MTP_long(id), MTP_long(0), MTP_int(unixtime()), MTP_vector<MTPPhotoSize>(photoSizes)));
|
||||
MTPDphoto::Flags photoFlags = 0;
|
||||
auto photo = MTP_photo(MTP_flags(photoFlags), MTP_long(id), MTP_long(0), MTP_int(unixtime()), MTP_vector<MTPPhotoSize>(photoSizes));
|
||||
|
||||
QString file, filename;
|
||||
int32 filesize = 0;
|
||||
|
@ -1090,10 +1091,9 @@ void AppClass::checkMapVersion() {
|
|||
AppClass::~AppClass() {
|
||||
Shortcuts::finish();
|
||||
|
||||
if (auto w = _window) {
|
||||
_window = 0;
|
||||
delete w;
|
||||
}
|
||||
auto window = createAndSwap(_window);
|
||||
delete window;
|
||||
|
||||
anim::stopManager();
|
||||
|
||||
stopWebLoadManager();
|
||||
|
@ -1102,7 +1102,7 @@ AppClass::~AppClass() {
|
|||
|
||||
MTP::finish();
|
||||
|
||||
AppObject = 0;
|
||||
AppObject = nullptr;
|
||||
deleteAndMark(_uploader);
|
||||
deleteAndMark(_translator);
|
||||
|
||||
|
|
|
@ -193,28 +193,32 @@ void AbstractBox::raiseShadow() {
|
|||
}
|
||||
}
|
||||
|
||||
ScrollableBox::ScrollableBox(const style::flatScroll &scroll, int32 w) : AbstractBox(w),
|
||||
_scroll(this, scroll), _innerPtr(0), _topSkip(st::boxTitleHeight), _bottomSkip(st::boxScrollSkip) {
|
||||
ScrollableBox::ScrollableBox(const style::flatScroll &scroll, int32 w) : AbstractBox(w)
|
||||
, _scroll(this, scroll)
|
||||
, _topSkip(st::boxTitleHeight)
|
||||
, _bottomSkip(st::boxScrollSkip) {
|
||||
setBlueTitle(true);
|
||||
}
|
||||
|
||||
void ScrollableBox::resizeEvent(QResizeEvent *e) {
|
||||
_scroll.setGeometry(0, _topSkip, width(), height() - _topSkip - _bottomSkip);
|
||||
_scroll->setGeometry(0, _topSkip, width(), height() - _topSkip - _bottomSkip);
|
||||
AbstractBox::resizeEvent(e);
|
||||
}
|
||||
|
||||
void ScrollableBox::init(QWidget *inner, int32 bottomSkip, int32 topSkip) {
|
||||
void ScrollableBox::init(QWidget *inner, int bottomSkip, int topSkip) {
|
||||
_bottomSkip = bottomSkip;
|
||||
_topSkip = topSkip;
|
||||
_innerPtr = inner;
|
||||
_scroll.setWidget(_innerPtr);
|
||||
_scroll.setFocusPolicy(Qt::NoFocus);
|
||||
ScrollableBox::resizeEvent(0);
|
||||
_scroll->setWidget(inner);
|
||||
_scroll->setFocusPolicy(Qt::NoFocus);
|
||||
ScrollableBox::resizeEvent(nullptr);
|
||||
}
|
||||
|
||||
void ScrollableBox::showAll() {
|
||||
_scroll.show();
|
||||
AbstractBox::showAll();
|
||||
void ScrollableBox::initOwned(QWidget *inner, int bottomSkip, int topSkip) {
|
||||
_bottomSkip = bottomSkip;
|
||||
_topSkip = topSkip;
|
||||
_scroll->setOwnedWidget(inner);
|
||||
_scroll->setFocusPolicy(Qt::NoFocus);
|
||||
ScrollableBox::resizeEvent(nullptr);
|
||||
}
|
||||
|
||||
ItemListBox::ItemListBox(const style::flatScroll &scroll, int32 w) : ScrollableBox(scroll, w) {
|
||||
|
|
|
@ -101,18 +101,20 @@ public:
|
|||
|
||||
class ScrollableBox : public AbstractBox {
|
||||
public:
|
||||
ScrollableBox(const style::flatScroll &scroll, int32 w = st::boxWideWidth);
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
ScrollableBox(const style::flatScroll &scroll, int w = st::boxWideWidth);
|
||||
|
||||
protected:
|
||||
void init(QWidget *inner, int32 bottomSkip = st::boxScrollSkip, int32 topSkip = st::boxTitleHeight);
|
||||
void init(QWidget *inner, int bottomSkip = st::boxScrollSkip, int topSkip = st::boxTitleHeight);
|
||||
void initOwned(QWidget *inner, int bottomSkip = st::boxScrollSkip, int topSkip = st::boxTitleHeight);
|
||||
|
||||
void showAll() override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
ScrollArea _scroll;
|
||||
ScrollArea *scrollArea() {
|
||||
return _scroll;
|
||||
}
|
||||
|
||||
private:
|
||||
QWidget *_innerPtr;
|
||||
ChildWidget<ScrollArea> _scroll;
|
||||
int32 _topSkip, _bottomSkip;
|
||||
|
||||
};
|
||||
|
|
|
@ -49,25 +49,6 @@ confirmInviteUserName: flatLabel(labelDefFlat) {
|
|||
}
|
||||
confirmInviteUserNameTop: 227px;
|
||||
|
||||
stickersAddIcon: icon {
|
||||
{ "stickers_add", #ffffff },
|
||||
};
|
||||
stickersAddSize: size(30px, 24px);
|
||||
|
||||
stickersFeaturedHeight: 32px;
|
||||
stickersFeaturedFont: contactsNameFont;
|
||||
stickersFeaturedPosition: point(16px, 6px);
|
||||
stickersFeaturedBadgeFont: semiboldFont;
|
||||
stickersFeaturedBadgeSize: 21px;
|
||||
stickersFeaturedPen: contactsNewItemFg;
|
||||
stickersFeaturedUnreadBg: msgFileInBg;
|
||||
stickersFeaturedUnreadSize: 5px;
|
||||
stickersFeaturedUnreadSkip: 5px;
|
||||
stickersFeaturedUnreadTop: 7px;
|
||||
stickersFeaturedInstalled: icon {
|
||||
{ "mediaview_save_check", #40ace3 }
|
||||
};
|
||||
|
||||
confirmPhoneAboutLabel: flatLabel(labelDefFlat) {
|
||||
width: 282px;
|
||||
}
|
||||
|
@ -87,3 +68,26 @@ aboutRevokePublicLabel: flatLabel(labelDefFlat) {
|
|||
}
|
||||
|
||||
localStorageBoxSkip: 10px;
|
||||
|
||||
shareRowsTop: 12px;
|
||||
shareRowHeight: 108px;
|
||||
sharePhotoRadius: 28px;
|
||||
sharePhotoSmallRadius: 24px;
|
||||
sharePhotoTop: 6px;
|
||||
shareSelectWidth: 2px;
|
||||
shareSelectFg: windowActiveBg;
|
||||
shareCheckBorder: windowBg;
|
||||
shareCheckBg: windowActiveBg;
|
||||
shareCheckRadius: 10px;
|
||||
shareCheckSmallRadius: 3px;
|
||||
shareCheckIcon: icon {
|
||||
{ "default_checkbox_check", windowBg, point(3px, 6px) },
|
||||
};
|
||||
shareNameFont: font(11px);
|
||||
shareNameFg: windowTextFg;
|
||||
shareNameActiveFg: btnYesColor;
|
||||
shareNameTop: 6px;
|
||||
shareColumnSkip: 6px;
|
||||
shareSelectDuration: 150;
|
||||
shareActivateDuration: 150;
|
||||
shareScrollDuration: 300;
|
||||
|
|
|
@ -19,15 +19,16 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
|
||||
#include "confirmbox.h"
|
||||
#include "lang.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "application.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "localstorage.h"
|
||||
|
||||
TextParseOptions _confirmBoxTextOptions = {
|
||||
TextParseLinks | TextParseMultiline | TextParseRichText, // flags
|
||||
|
@ -195,6 +196,18 @@ void ConfirmLinkBox::onOpenLink() {
|
|||
UrlClickHandler::doOpen(_url);
|
||||
}
|
||||
|
||||
ConfirmBotGameBox::ConfirmBotGameBox(UserData *bot, const QString &url) : ConfirmBox(lng_allow_bot_pass(lt_bot_name, bot->name), lang(lng_allow_bot))
|
||||
, _bot(bot)
|
||||
, _url(url) {
|
||||
connect(this, SIGNAL(confirmed()), this, SLOT(onOpenLink()));
|
||||
}
|
||||
|
||||
void ConfirmBotGameBox::onOpenLink() {
|
||||
Ui::hideLayer();
|
||||
Local::makeBotTrusted(_bot);
|
||||
UrlClickHandler::doOpen(_url);
|
||||
}
|
||||
|
||||
MaxInviteBox::MaxInviteBox(const QString &link) : AbstractBox(st::boxWidth)
|
||||
, _close(this, lang(lng_box_ok), st::defaultBoxButton)
|
||||
, _text(st::boxTextFont, lng_participant_invite_sorry(lt_count, Global::ChatSizeMax()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right())
|
||||
|
|
|
@ -125,6 +125,21 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class ConfirmBotGameBox : public ConfirmBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConfirmBotGameBox(UserData *bot, const QString &url);
|
||||
|
||||
public slots:
|
||||
void onOpenLink();
|
||||
|
||||
private:
|
||||
UserData *_bot;
|
||||
QString _url;
|
||||
|
||||
};
|
||||
|
||||
class MaxInviteBox : public AbstractBox {
|
||||
Q_OBJECT
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "dialogs/dialogs_indexed_list.h"
|
||||
#include "lang.h"
|
||||
#include "boxes/addcontactbox.h"
|
||||
#include "boxes/contactsbox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "application.h"
|
||||
|
@ -1353,11 +1352,11 @@ void ContactsBox::init() {
|
|||
_cancel.hide();
|
||||
}
|
||||
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(scrollArea(), SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
|
||||
connect(&_filter, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(&_filterCancel, SIGNAL(clicked()), this, SLOT(onFilterCancel()));
|
||||
connect(&_inner, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int)));
|
||||
connect(&_inner, SIGNAL(mustScrollTo(int, int)), scrollArea(), SLOT(scrollToY(int, int)));
|
||||
connect(&_inner, SIGNAL(selectAllQuery()), &_filter, SLOT(selectAll()));
|
||||
connect(&_inner, SIGNAL(searchByUsername()), this, SLOT(onNeedSearchByUsername()));
|
||||
connect(&_inner, SIGNAL(adminAdded()), this, SIGNAL(adminAdded()));
|
||||
|
@ -1478,9 +1477,9 @@ void ContactsBox::keyPressEvent(QKeyEvent *e) {
|
|||
} else if (e->key() == Qt::Key_Up) {
|
||||
_inner.selectSkip(-1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner.selectSkipPage(_scroll.height(), 1);
|
||||
_inner.selectSkipPage(scrollArea()->height(), 1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner.selectSkipPage(_scroll.height(), -1);
|
||||
_inner.selectSkipPage(scrollArea()->height(), -1);
|
||||
} else {
|
||||
ItemListBox::keyPressEvent(e);
|
||||
}
|
||||
|
@ -1530,7 +1529,7 @@ void ContactsBox::onFilterCancel() {
|
|||
}
|
||||
|
||||
void ContactsBox::onFilterUpdate() {
|
||||
_scroll.scrollToY(0);
|
||||
scrollArea()->scrollToY(0);
|
||||
if (_filter.getLastText().isEmpty()) {
|
||||
_filterCancel.hide();
|
||||
} else {
|
||||
|
@ -1681,7 +1680,7 @@ bool ContactsBox::editAdminFail(const RPCError &error) {
|
|||
}
|
||||
|
||||
void ContactsBox::onScroll() {
|
||||
_inner.loadProfilePhotos(_scroll.scrollTop());
|
||||
_inner.loadProfilePhotos(scrollArea()->scrollTop());
|
||||
}
|
||||
|
||||
void ContactsBox::creationDone(const MTPUpdates &updates) {
|
||||
|
@ -2245,8 +2244,8 @@ MembersBox::MembersBox(ChannelData *channel, MembersFilter filter) : ItemListBox
|
|||
|
||||
connect(&_inner, SIGNAL(addRequested()), this, SLOT(onAdd()));
|
||||
|
||||
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(&_inner, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int)));
|
||||
connect(scrollArea(), SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(&_inner, SIGNAL(mustScrollTo(int, int)), scrollArea(), SLOT(scrollToY(int, int)));
|
||||
connect(&_inner, SIGNAL(loaded()), this, SLOT(onLoaded()));
|
||||
|
||||
connect(&_loadTimer, SIGNAL(timeout()), &_inner, SLOT(load()));
|
||||
|
@ -2260,9 +2259,9 @@ void MembersBox::keyPressEvent(QKeyEvent *e) {
|
|||
} else if (e->key() == Qt::Key_Up) {
|
||||
_inner.selectSkip(-1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner.selectSkipPage(_scroll.height(), 1);
|
||||
_inner.selectSkipPage(scrollArea()->height(), 1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner.selectSkipPage(_scroll.height(), -1);
|
||||
_inner.selectSkipPage(scrollArea()->height(), -1);
|
||||
} else {
|
||||
ItemListBox::keyPressEvent(e);
|
||||
}
|
||||
|
@ -2282,7 +2281,7 @@ void MembersBox::resizeEvent(QResizeEvent *e) {
|
|||
}
|
||||
|
||||
void MembersBox::onScroll() {
|
||||
_inner.loadProfilePhotos(_scroll.scrollTop());
|
||||
_inner.loadProfilePhotos(scrollArea()->scrollTop());
|
||||
}
|
||||
|
||||
void MembersBox::onAdd() {
|
||||
|
|
|
@ -252,10 +252,10 @@ void SessionsBox::resizeEvent(QResizeEvent *e) {
|
|||
void SessionsBox::showAll() {
|
||||
_done.show();
|
||||
if (_loading) {
|
||||
_scroll.hide();
|
||||
scrollArea()->hide();
|
||||
_shadow.hide();
|
||||
} else {
|
||||
_scroll.show();
|
||||
scrollArea()->show();
|
||||
_shadow.show();
|
||||
}
|
||||
ScrollableBox::showAll();
|
||||
|
|
995
Telegram/SourceFiles/boxes/sharebox.cpp
Normal file
995
Telegram/SourceFiles/boxes/sharebox.cpp
Normal file
|
@ -0,0 +1,995 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "boxes/sharebox.h"
|
||||
|
||||
#include "dialogs/dialogs_indexed_list.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "observer_peer.h"
|
||||
#include "lang.h"
|
||||
#include "mainwindow.h"
|
||||
#include "mainwidget.h"
|
||||
#include "core/qthelp_url.h"
|
||||
#include "localstorage.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
ShareBox::ShareBox(SubmitCallback &&callback) : ItemListBox(st::boxScroll)
|
||||
, _callback(std_::move(callback))
|
||||
, _inner(this)
|
||||
, _filter(this, st::boxSearchField, lang(lng_participant_filter))
|
||||
, _filterCancel(this, st::boxSearchCancel)
|
||||
, _share(this, lang(lng_share_confirm), st::defaultBoxButton)
|
||||
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
|
||||
, _topShadow(this)
|
||||
, _bottomShadow(this) {
|
||||
int topSkip = st::boxTitleHeight + _filter->height();
|
||||
int bottomSkip = st::boxButtonPadding.top() + _share->height() + st::boxButtonPadding.bottom();
|
||||
init(_inner, bottomSkip, topSkip);
|
||||
|
||||
connect(_inner, SIGNAL(selectedChanged()), this, SLOT(onSelectedChanged()));
|
||||
connect(_inner, SIGNAL(mustScrollTo(int,int)), this, SLOT(onMustScrollTo(int,int)));
|
||||
connect(_share, SIGNAL(clicked()), this, SLOT(onShare()));
|
||||
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
connect(scrollArea(), SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
|
||||
connect(_filter, SIGNAL(submitted(bool)), _inner, SLOT(onSelectActive()));
|
||||
connect(_filterCancel, SIGNAL(clicked()), this, SLOT(onFilterCancel()));
|
||||
connect(_inner, SIGNAL(filterCancel()), this, SLOT(onFilterCancel()));
|
||||
connect(_inner, SIGNAL(searchByUsername()), this, SLOT(onNeedSearchByUsername()));
|
||||
|
||||
_filterCancel->setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
_searchTimer.setSingleShot(true);
|
||||
connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchByUsername()));
|
||||
|
||||
prepare();
|
||||
}
|
||||
|
||||
bool ShareBox::onSearchByUsername(bool searchCache) {
|
||||
auto query = _filter->getLastText().trimmed();
|
||||
if (query.isEmpty()) {
|
||||
if (_peopleRequest) {
|
||||
_peopleRequest = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (query.size() >= MinUsernameLength) {
|
||||
if (searchCache) {
|
||||
auto i = _peopleCache.constFind(query);
|
||||
if (i != _peopleCache.cend()) {
|
||||
_peopleQuery = query;
|
||||
_peopleRequest = 0;
|
||||
peopleReceived(i.value(), 0);
|
||||
return true;
|
||||
}
|
||||
} else if (_peopleQuery != query) {
|
||||
_peopleQuery = query;
|
||||
_peopleFull = false;
|
||||
_peopleRequest = MTP::send(MTPcontacts_Search(MTP_string(_peopleQuery), MTP_int(SearchPeopleLimit)), rpcDone(&ShareBox::peopleReceived), rpcFail(&ShareBox::peopleFailed));
|
||||
_peopleQueries.insert(_peopleRequest, _peopleQuery);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShareBox::onNeedSearchByUsername() {
|
||||
if (!onSearchByUsername(true)) {
|
||||
_searchTimer.start(AutoSearchTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void ShareBox::peopleReceived(const MTPcontacts_Found &result, mtpRequestId requestId) {
|
||||
auto query = _peopleQuery;
|
||||
|
||||
auto i = _peopleQueries.find(requestId);
|
||||
if (i != _peopleQueries.cend()) {
|
||||
query = i.value();
|
||||
_peopleCache[query] = result;
|
||||
_peopleQueries.erase(i);
|
||||
}
|
||||
|
||||
if (_peopleRequest == requestId) {
|
||||
switch (result.type()) {
|
||||
case mtpc_contacts_found: {
|
||||
auto &found = result.c_contacts_found();
|
||||
App::feedUsers(found.vusers);
|
||||
App::feedChats(found.vchats);
|
||||
_inner->peopleReceived(query, found.vresults.c_vector().v);
|
||||
} break;
|
||||
}
|
||||
|
||||
_peopleRequest = 0;
|
||||
onScroll();
|
||||
}
|
||||
}
|
||||
|
||||
bool ShareBox::peopleFailed(const RPCError &error, mtpRequestId requestId) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
|
||||
if (_peopleRequest == requestId) {
|
||||
_peopleRequest = 0;
|
||||
_peopleFull = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShareBox::doSetInnerFocus() {
|
||||
_filter->setFocus();
|
||||
}
|
||||
|
||||
void ShareBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
if (paint(p)) return;
|
||||
|
||||
paintTitle(p, lang(lng_share_title));
|
||||
}
|
||||
|
||||
void ShareBox::resizeEvent(QResizeEvent *e) {
|
||||
ItemListBox::resizeEvent(e);
|
||||
_filter->resize(width(), _filter->height());
|
||||
_filter->moveToLeft(0, st::boxTitleHeight);
|
||||
_filterCancel->moveToRight(0, st::boxTitleHeight);
|
||||
_inner->resizeToWidth(width());
|
||||
moveButtons();
|
||||
_topShadow->setGeometry(0, st::boxTitleHeight + _filter->height(), width(), st::lineWidth);
|
||||
_bottomShadow->setGeometry(0, height() - st::boxButtonPadding.bottom() - _share->height() - st::boxButtonPadding.top() - st::lineWidth, width(), st::lineWidth);
|
||||
}
|
||||
|
||||
void ShareBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (_filter->hasFocus()) {
|
||||
if (e->key() == Qt::Key_Up) {
|
||||
_inner->activateSkipColumn(-1);
|
||||
} else if (e->key() == Qt::Key_Down) {
|
||||
_inner->activateSkipColumn(1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner->activateSkipPage(scrollArea()->height(), -1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner->activateSkipPage(scrollArea()->height(), 1);
|
||||
} else {
|
||||
ItemListBox::keyPressEvent(e);
|
||||
}
|
||||
} else {
|
||||
ItemListBox::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ShareBox::moveButtons() {
|
||||
_share->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _share->height());
|
||||
auto cancelRight = st::boxButtonPadding.right();
|
||||
if (_inner->hasSelected()) {
|
||||
cancelRight += _share->width() + st::boxButtonPadding.left();
|
||||
}
|
||||
_cancel->moveToRight(cancelRight, _share->y());
|
||||
}
|
||||
|
||||
void ShareBox::onFilterCancel() {
|
||||
_filter->setText(QString());
|
||||
}
|
||||
|
||||
void ShareBox::onFilterUpdate() {
|
||||
_filterCancel->setVisible(!_filter->getLastText().isEmpty());
|
||||
_inner->updateFilter(_filter->getLastText());
|
||||
}
|
||||
|
||||
void ShareBox::onShare() {
|
||||
if (_callback) {
|
||||
_callback(_inner->selected());
|
||||
}
|
||||
}
|
||||
|
||||
void ShareBox::onSelectedChanged() {
|
||||
_share->setVisible(_inner->hasSelected());
|
||||
moveButtons();
|
||||
update();
|
||||
}
|
||||
|
||||
void ShareBox::onMustScrollTo(int top, int bottom) {
|
||||
auto scrollTop = scrollArea()->scrollTop(), scrollBottom = scrollTop + scrollArea()->height();
|
||||
auto from = scrollTop, to = scrollTop;
|
||||
if (scrollTop > top) {
|
||||
to = top;
|
||||
} else if (scrollBottom < bottom) {
|
||||
to = bottom - (scrollBottom - scrollTop);
|
||||
}
|
||||
if (from != to) {
|
||||
START_ANIMATION(_scrollAnimation, func([this]() {
|
||||
scrollArea()->scrollToY(_scrollAnimation.current(scrollArea()->scrollTop()));
|
||||
}), from, to, st::shareScrollDuration, anim::sineInOut);
|
||||
}
|
||||
}
|
||||
|
||||
void ShareBox::onScroll() {
|
||||
auto scroll = scrollArea();
|
||||
auto scrollTop = scroll->scrollTop();
|
||||
_inner->setVisibleTopBottom(scrollTop, scrollTop + scroll->height());
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
ShareInner::ShareInner(QWidget *parent) : ScrolledWidget(parent)
|
||||
, _chatsIndexed(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Add)) {
|
||||
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
|
||||
|
||||
_rowsTop = st::shareRowsTop;
|
||||
_rowHeight = st::shareRowHeight;
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
auto dialogs = App::main()->dialogsList();
|
||||
for_const (auto row, dialogs->all()) {
|
||||
auto history = row->history();
|
||||
if (history->peer->canWrite()) {
|
||||
_chatsIndexed->addToEnd(history);
|
||||
}
|
||||
}
|
||||
|
||||
_filter = qsl("a");
|
||||
updateFilter();
|
||||
|
||||
prepareWideCheckIcons();
|
||||
|
||||
using UpdateFlag = Notify::PeerUpdate::Flag;
|
||||
auto observeEvents = UpdateFlag::NameChanged | UpdateFlag::PhotoChanged;
|
||||
Notify::registerPeerObserver(observeEvents, this, &ShareInner::notifyPeerUpdated);
|
||||
}
|
||||
|
||||
void ShareInner::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||
loadProfilePhotos(visibleTop);
|
||||
}
|
||||
|
||||
void ShareInner::activateSkipRow(int direction) {
|
||||
activateSkipColumn(direction * _columnCount);
|
||||
}
|
||||
|
||||
int ShareInner::displayedChatsCount() const {
|
||||
return _filter.isEmpty() ? _chatsIndexed->size() : (_filtered.size() + d_byUsernameFiltered.size());
|
||||
}
|
||||
|
||||
void ShareInner::activateSkipColumn(int direction) {
|
||||
if (_active < 0) {
|
||||
if (direction > 0) {
|
||||
setActive(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto count = displayedChatsCount();
|
||||
auto active = _active + direction;
|
||||
if (active < 0) {
|
||||
active = (_active > 0) ? 0 : -1;
|
||||
}
|
||||
if (active >= count) {
|
||||
active = count - 1;
|
||||
}
|
||||
setActive(active);
|
||||
}
|
||||
|
||||
void ShareInner::activateSkipPage(int pageHeight, int direction) {
|
||||
activateSkipRow(direction * (pageHeight / _rowHeight));
|
||||
}
|
||||
|
||||
void ShareInner::notifyPeerUpdated(const Notify::PeerUpdate &update) {
|
||||
if (update.flags & Notify::PeerUpdate::Flag::NameChanged) {
|
||||
_chatsIndexed->peerNameChanged(update.peer, update.oldNames, update.oldNameFirstChars);
|
||||
}
|
||||
|
||||
updateChat(update.peer);
|
||||
}
|
||||
|
||||
void ShareInner::updateChat(PeerData *peer) {
|
||||
auto i = _dataMap.find(peer);
|
||||
if (i != _dataMap.cend()) {
|
||||
updateChatName(i.value(), peer);
|
||||
repaintChat(peer);
|
||||
}
|
||||
}
|
||||
|
||||
void ShareInner::updateChatName(Chat *chat, PeerData *peer) {
|
||||
chat->name.setText(st::shareNameFont, peer->name, _textNameOptions);
|
||||
}
|
||||
|
||||
void ShareInner::repaintChatAtIndex(int index) {
|
||||
if (index < 0) return;
|
||||
|
||||
auto row = index / _columnCount;
|
||||
auto column = index % _columnCount;
|
||||
update(rtlrect(_rowsLeft + qFloor(column * _rowWidthReal), row * _rowHeight, _rowWidth, _rowHeight, width()));
|
||||
}
|
||||
|
||||
ShareInner::Chat *ShareInner::getChatAtIndex(int index) {
|
||||
if (index < 0) return nullptr;
|
||||
auto row = ([this, index]() -> Dialogs::Row* {
|
||||
if (_filter.isEmpty()) return _chatsIndexed->rowAtY(index, 1);
|
||||
return (index < _filtered.size()) ? _filtered[index] : nullptr;
|
||||
})();
|
||||
if (row) {
|
||||
return static_cast<Chat*>(row->attached);
|
||||
}
|
||||
|
||||
if (!_filter.isEmpty()) {
|
||||
index -= _filtered.size();
|
||||
if (index >= 0 && index < d_byUsernameFiltered.size()) {
|
||||
return d_byUsernameFiltered[index];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ShareInner::repaintChat(PeerData *peer) {
|
||||
repaintChatAtIndex(chatIndex(peer));
|
||||
}
|
||||
|
||||
int ShareInner::chatIndex(PeerData *peer) const {
|
||||
int index = 0;
|
||||
if (_filter.isEmpty()) {
|
||||
for_const (auto row, _chatsIndexed->all()) {
|
||||
if (row->history()->peer == peer) {
|
||||
return index;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
} else {
|
||||
for_const (auto row, _filtered) {
|
||||
if (row->history()->peer == peer) {
|
||||
return index;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
for_const (auto row, d_byUsernameFiltered) {
|
||||
if (row->peer == peer) {
|
||||
return index;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ShareInner::loadProfilePhotos(int yFrom) {
|
||||
if (yFrom < 0) {
|
||||
yFrom = 0;
|
||||
}
|
||||
if (auto part = (yFrom % _rowHeight)) {
|
||||
yFrom -= part;
|
||||
}
|
||||
int yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5 * _columnCount;
|
||||
if (!yTo) {
|
||||
return;
|
||||
}
|
||||
yFrom *= _columnCount;
|
||||
yTo *= _columnCount;
|
||||
|
||||
MTP::clearLoaderPriorities();
|
||||
if (_filter.isEmpty()) {
|
||||
if (!_chatsIndexed->isEmpty()) {
|
||||
auto i = _chatsIndexed->cfind(yFrom, _rowHeight);
|
||||
for (auto end = _chatsIndexed->cend(); i != end; ++i) {
|
||||
if (((*i)->pos() * _rowHeight) >= yTo) {
|
||||
break;
|
||||
}
|
||||
(*i)->history()->peer->loadUserpic();
|
||||
}
|
||||
}
|
||||
} else if (!_filtered.isEmpty()) {
|
||||
int from = yFrom / _rowHeight;
|
||||
if (from < 0) from = 0;
|
||||
if (from < _filtered.size()) {
|
||||
int to = (yTo / _rowHeight) + 1;
|
||||
if (to > _filtered.size()) to = _filtered.size();
|
||||
|
||||
for (; from < to; ++from) {
|
||||
_filtered[from]->history()->peer->loadUserpic();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShareInner::Chat *ShareInner::getChat(Dialogs::Row *row) {
|
||||
auto data = static_cast<Chat*>(row->attached);
|
||||
if (!data) {
|
||||
auto peer = row->history()->peer;
|
||||
auto i = _dataMap.constFind(peer);
|
||||
if (i == _dataMap.cend()) {
|
||||
_dataMap.insert(peer, data = new Chat(peer));
|
||||
updateChatName(data, peer);
|
||||
} else {
|
||||
data = i.value();
|
||||
}
|
||||
row->attached = data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void ShareInner::setActive(int active) {
|
||||
if (active != _active) {
|
||||
auto changeNameFg = [this](int index, style::color from, style::color to) {
|
||||
if (auto chat = getChatAtIndex(index)) {
|
||||
START_ANIMATION(chat->nameFg, func([this, chat] {
|
||||
repaintChat(chat->peer);
|
||||
}), from->c, to->c, st::shareActivateDuration, anim::linear);
|
||||
}
|
||||
};
|
||||
changeNameFg(_active, st::shareNameActiveFg, st::shareNameFg);
|
||||
_active = active;
|
||||
changeNameFg(_active, st::shareNameFg, st::shareNameActiveFg);
|
||||
}
|
||||
auto y = (_active < _columnCount) ? 0 : (_rowsTop + ((_active / _columnCount) * _rowHeight));
|
||||
emit mustScrollTo(y, y + _rowHeight);
|
||||
}
|
||||
|
||||
void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
|
||||
auto x = _rowsLeft + qFloor((index % _columnCount) * _rowWidthReal);
|
||||
auto y = _rowsTop + (index / _columnCount) * _rowHeight;
|
||||
|
||||
auto selectionLevel = chat->selection.current(chat->selected ? 1. : 0.);
|
||||
|
||||
auto w = width();
|
||||
auto photoLeft = (_rowWidth - (st::sharePhotoRadius * 2)) / 2;
|
||||
auto photoTop = st::sharePhotoTop;
|
||||
if (chat->selection.isNull()) {
|
||||
if (!chat->wideUserpicCache.isNull()) {
|
||||
chat->wideUserpicCache = QPixmap();
|
||||
}
|
||||
auto userpicRadius = chat->selected ? st::sharePhotoSmallRadius : st::sharePhotoRadius;
|
||||
auto userpicShift = st::sharePhotoRadius - userpicRadius;
|
||||
auto userpicLeft = x + photoLeft + userpicShift;
|
||||
auto userpicTop = y + photoTop + userpicShift;
|
||||
chat->peer->paintUserpicLeft(p, userpicRadius * 2, userpicLeft, userpicTop, w);
|
||||
} else {
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||
auto userpicRadius = qRound(WideCacheScale * (st::sharePhotoRadius + (st::sharePhotoSmallRadius - st::sharePhotoRadius) * selectionLevel));
|
||||
auto userpicShift = WideCacheScale * st::sharePhotoRadius - userpicRadius;
|
||||
auto userpicLeft = x + photoLeft - (WideCacheScale - 1) * st::sharePhotoRadius + userpicShift;
|
||||
auto userpicTop = y + photoTop - (WideCacheScale - 1) * st::sharePhotoRadius + userpicShift;
|
||||
auto to = QRect(userpicLeft, userpicTop, userpicRadius * 2, userpicRadius * 2);
|
||||
auto from = QRect(QPoint(0, 0), chat->wideUserpicCache.size());
|
||||
p.drawPixmapLeft(to, w, chat->wideUserpicCache, from);
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform, false);
|
||||
}
|
||||
|
||||
if (selectionLevel > 0) {
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing, true);
|
||||
p.setOpacity(snap(selectionLevel, 0., 1.));
|
||||
p.setBrush(Qt::NoBrush);
|
||||
QPen pen = st::shareSelectFg;
|
||||
pen.setWidth(st::shareSelectWidth);
|
||||
p.setPen(pen);
|
||||
p.drawEllipse(myrtlrect(x + photoLeft, y + photoTop, st::sharePhotoRadius * 2, st::sharePhotoRadius * 2));
|
||||
p.setOpacity(1.);
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||
}
|
||||
|
||||
removeFadeOutedIcons(chat);
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||
for (auto &icon : chat->icons) {
|
||||
auto fadeIn = icon.fadeIn.current(1.);
|
||||
auto fadeOut = icon.fadeOut.current(1.);
|
||||
auto iconRadius = qRound(WideCacheScale * (st::shareCheckSmallRadius + fadeOut * (st::shareCheckRadius - st::shareCheckSmallRadius)));
|
||||
auto iconShift = WideCacheScale * st::shareCheckRadius - iconRadius;
|
||||
auto iconLeft = x + photoLeft + 2 * st::sharePhotoRadius + st::shareSelectWidth - 2 * st::shareCheckRadius - (WideCacheScale - 1) * st::shareCheckRadius + iconShift;
|
||||
auto iconTop = y + photoTop + 2 * st::sharePhotoRadius + st::shareSelectWidth - 2 * st::shareCheckRadius - (WideCacheScale - 1) * st::shareCheckRadius + iconShift;
|
||||
auto to = QRect(iconLeft, iconTop, iconRadius * 2, iconRadius * 2);
|
||||
auto from = QRect(QPoint(0, 0), _wideCheckIconCache.size());
|
||||
auto opacity = fadeIn * fadeOut;
|
||||
p.setOpacity(opacity);
|
||||
if (fadeOut < 1.) {
|
||||
p.drawPixmapLeft(to, w, icon.wideCheckCache, from);
|
||||
} else {
|
||||
auto divider = qRound((WideCacheScale - 2) * st::shareCheckRadius + fadeIn * 3 * st::shareCheckRadius);
|
||||
p.drawPixmapLeft(QRect(iconLeft, iconTop, divider, iconRadius * 2), w, _wideCheckIconCache, QRect(0, 0, divider * cIntRetinaFactor(), _wideCheckIconCache.height()));
|
||||
p.drawPixmapLeft(QRect(iconLeft + divider, iconTop, iconRadius * 2 - divider, iconRadius * 2), w, _wideCheckCache, QRect(divider * cIntRetinaFactor(), 0, _wideCheckCache.width() - divider * cIntRetinaFactor(), _wideCheckCache.height()));
|
||||
}
|
||||
}
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform, false);
|
||||
p.setOpacity(1.);
|
||||
|
||||
if (chat->nameFg.isNull()) {
|
||||
p.setPen((index == _active) ? st::shareNameActiveFg : st::shareNameFg);
|
||||
} else {
|
||||
p.setPen(chat->nameFg.current());
|
||||
}
|
||||
auto nameWidth = (_rowWidth - st::shareColumnSkip);
|
||||
auto nameLeft = st::shareColumnSkip / 2;
|
||||
auto nameTop = photoTop + st::sharePhotoRadius * 2 + st::shareNameTop;
|
||||
chat->name.drawLeftElided(p, x + nameLeft, y + nameTop, nameWidth, w, 2, style::al_top, 0, -1, 0, true);
|
||||
}
|
||||
|
||||
ShareInner::Chat::Chat(PeerData *peer) : peer(peer), name(st::sharePhotoRadius * 2) {
|
||||
}
|
||||
|
||||
void ShareInner::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
auto r = e->rect();
|
||||
p.setClipRect(r);
|
||||
p.fillRect(r, st::white);
|
||||
auto yFrom = r.y(), yTo = r.y() + r.height();
|
||||
auto rowFrom = yFrom / _rowHeight;
|
||||
auto rowTo = (yTo + _rowHeight - 1) / _rowHeight;
|
||||
auto indexFrom = rowFrom * _columnCount;
|
||||
auto indexTo = rowTo * _columnCount;
|
||||
if (_filter.isEmpty()) {
|
||||
if (!_chatsIndexed->isEmpty()) {
|
||||
auto i = _chatsIndexed->cfind(indexFrom, 1);
|
||||
for (auto end = _chatsIndexed->cend(); i != end; ++i) {
|
||||
if (indexFrom >= indexTo) {
|
||||
break;
|
||||
}
|
||||
paintChat(p, getChat(*i), indexFrom);
|
||||
++indexFrom;
|
||||
}
|
||||
} else {
|
||||
// empty
|
||||
p.setFont(st::noContactsFont);
|
||||
p.setPen(st::noContactsColor);
|
||||
}
|
||||
} else {
|
||||
if (_filtered.isEmpty() && _byUsernameFiltered.isEmpty()) {
|
||||
// empty
|
||||
p.setFont(st::noContactsFont);
|
||||
p.setPen(st::noContactsColor);
|
||||
} else {
|
||||
auto filteredSize = _filtered.size();
|
||||
if (filteredSize) {
|
||||
if (indexFrom < 0) indexFrom = 0;
|
||||
while (indexFrom < indexTo) {
|
||||
if (indexFrom >= _filtered.size()) {
|
||||
break;
|
||||
}
|
||||
paintChat(p, getChat(_filtered[indexFrom]), indexFrom);
|
||||
++indexFrom;
|
||||
}
|
||||
indexFrom -= filteredSize;
|
||||
indexTo -= filteredSize;
|
||||
}
|
||||
if (!_byUsernameFiltered.isEmpty()) {
|
||||
if (indexFrom < 0) indexFrom = 0;
|
||||
while (indexFrom < indexTo) {
|
||||
if (indexFrom >= d_byUsernameFiltered.size()) {
|
||||
break;
|
||||
}
|
||||
paintChat(p, d_byUsernameFiltered[indexFrom], filteredSize + indexFrom);
|
||||
++indexFrom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShareInner::enterEvent(QEvent *e) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void ShareInner::leaveEvent(QEvent *e) {
|
||||
setMouseTracking(false);
|
||||
}
|
||||
|
||||
void ShareInner::mouseMoveEvent(QMouseEvent *e) {
|
||||
updateUpon(e->pos());
|
||||
setCursor((_upon >= 0) ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
|
||||
void ShareInner::updateUpon(const QPoint &pos) {
|
||||
auto x = pos.x(), y = pos.y();
|
||||
auto row = (y - _rowsTop) / _rowHeight;
|
||||
auto column = qFloor((x - _rowsLeft) / _rowWidthReal);
|
||||
auto left = _rowsLeft + qFloor(column * _rowWidthReal) + st::shareColumnSkip / 2;
|
||||
auto top = _rowsTop + row * _rowHeight + st::sharePhotoTop;
|
||||
auto xupon = (x >= left) && (x < left + (_rowWidth - st::shareColumnSkip));
|
||||
auto yupon = (y >= top) && (y < top + st::sharePhotoRadius * 2 + st::shareNameTop + st::shareNameFont->height * 2);
|
||||
auto upon = (xupon && yupon) ? (row * _columnCount + column) : -1;
|
||||
if (upon >= displayedChatsCount()) {
|
||||
upon = -1;
|
||||
}
|
||||
_upon = upon;
|
||||
}
|
||||
|
||||
void ShareInner::mousePressEvent(QMouseEvent *e) {
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
updateUpon(e->pos());
|
||||
changeCheckState(getChatAtIndex(_upon));
|
||||
}
|
||||
}
|
||||
|
||||
void ShareInner::onSelectActive() {
|
||||
changeCheckState(getChatAtIndex(_active > 0 ? _active : 0));
|
||||
}
|
||||
|
||||
void ShareInner::resizeEvent(QResizeEvent *e) {
|
||||
_columnSkip = (width() - _columnCount * st::sharePhotoRadius * 2) / float64(_columnCount + 1);
|
||||
_rowWidthReal = st::sharePhotoRadius * 2 + _columnSkip;
|
||||
_rowsLeft = qFloor(_columnSkip / 2);
|
||||
_rowWidth = qFloor(_rowWidthReal);
|
||||
update();
|
||||
}
|
||||
|
||||
struct AnimBumpy {
|
||||
AnimBumpy(float64 bump) : bump(bump)
|
||||
, dt0(bump - sqrt(bump * (bump - 1.)))
|
||||
, k(1 / (2 * dt0 - 1)) {
|
||||
}
|
||||
float64 bump;
|
||||
float64 dt0;
|
||||
float64 k;
|
||||
};
|
||||
|
||||
float64 anim_bumpy(const float64 &delta, const float64 &dt) {
|
||||
static AnimBumpy data = { 1.25 };
|
||||
return delta * (data.bump - data.k * (dt - data.dt0) * (dt - data.dt0));
|
||||
}
|
||||
|
||||
void ShareInner::changeCheckState(Chat *chat) {
|
||||
if (!chat) return;
|
||||
|
||||
if (!_filter.isEmpty()) {
|
||||
auto row = _chatsIndexed->getRow(chat->peer->id);
|
||||
if (!row) {
|
||||
row = _chatsIndexed->addToEnd(App::history(chat->peer)).value(0);
|
||||
}
|
||||
chat = getChat(row);
|
||||
if (!chat->selected) {
|
||||
_chatsIndexed->moveToTop(chat->peer);
|
||||
}
|
||||
emit filterCancel();
|
||||
}
|
||||
|
||||
chat->selected = !chat->selected;
|
||||
if (chat->selected) {
|
||||
_selected.insert(chat->peer);
|
||||
chat->icons.push_back(Chat::Icon());
|
||||
START_ANIMATION(chat->icons.back().fadeIn, func([this, chat] {
|
||||
repaintChat(chat->peer);
|
||||
}), 0, 1, st::shareSelectDuration, anim::linear);
|
||||
} else {
|
||||
_selected.remove(chat->peer);
|
||||
prepareWideCheckIconCache(&chat->icons.back());
|
||||
START_ANIMATION(chat->icons.back().fadeOut, func([this, chat] {
|
||||
removeFadeOutedIcons(chat);
|
||||
repaintChat(chat->peer);
|
||||
}), 1, 0, st::shareSelectDuration, anim::linear);
|
||||
}
|
||||
prepareWideUserpicCache(chat);
|
||||
START_ANIMATION(chat->selection, func([this, chat] {
|
||||
repaintChat(chat->peer);
|
||||
}), chat->selected ? 0 : 1, chat->selected ? 1 : 0, st::shareSelectDuration, anim_bumpy);
|
||||
if (chat->selected) {
|
||||
setActive(chatIndex(chat->peer));
|
||||
}
|
||||
emit selectedChanged();
|
||||
}
|
||||
|
||||
void ShareInner::removeFadeOutedIcons(Chat *chat) {
|
||||
while (!chat->icons.empty() && chat->icons.front().fadeIn.isNull() && chat->icons.front().fadeOut.isNull()) {
|
||||
if (chat->icons.size() > 1 || !chat->selected) {
|
||||
chat->icons.pop_front();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShareInner::prepareWideUserpicCache(Chat *chat) {
|
||||
if (chat->wideUserpicCache.isNull()) {
|
||||
auto size = st::sharePhotoRadius * 2;
|
||||
auto wideSize = size * WideCacheScale;
|
||||
QImage cache(wideSize * cIntRetinaFactor(), wideSize * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
cache.setDevicePixelRatio(cRetinaFactor());
|
||||
{
|
||||
Painter p(&cache);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.fillRect(0, 0, wideSize, wideSize, Qt::transparent);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
chat->peer->paintUserpic(p, size, (wideSize - size) / 2, (wideSize - size) / 2);
|
||||
}
|
||||
chat->wideUserpicCache = App::pixmapFromImageInPlace(std_::move(cache));
|
||||
chat->wideUserpicCache.setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
}
|
||||
|
||||
void ShareInner::prepareWideCheckIconCache(Chat::Icon *icon) {
|
||||
QImage wideCache(_wideCheckCache.width(), _wideCheckCache.height(), QImage::Format_ARGB32_Premultiplied);
|
||||
wideCache.setDevicePixelRatio(cRetinaFactor());
|
||||
{
|
||||
Painter p(&wideCache);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
auto iconRadius = WideCacheScale * st::shareCheckRadius;
|
||||
auto divider = qRound((WideCacheScale - 2) * st::shareCheckRadius + icon->fadeIn.current(1.) * 3 * st::shareCheckRadius);
|
||||
p.drawPixmapLeft(QRect(0, 0, divider, iconRadius * 2), width(), _wideCheckIconCache, QRect(0, 0, divider * cIntRetinaFactor(), _wideCheckIconCache.height()));
|
||||
p.drawPixmapLeft(QRect(divider, 0, iconRadius * 2 - divider, iconRadius * 2), width(), _wideCheckCache, QRect(divider * cIntRetinaFactor(), 0, _wideCheckCache.width() - divider * cIntRetinaFactor(), _wideCheckCache.height()));
|
||||
}
|
||||
icon->wideCheckCache = App::pixmapFromImageInPlace(std_::move(wideCache));
|
||||
icon->wideCheckCache.setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
|
||||
void ShareInner::prepareWideCheckIcons() {
|
||||
auto size = st::shareCheckRadius * 2;
|
||||
auto wideSize = size * WideCacheScale;
|
||||
QImage cache(wideSize * cIntRetinaFactor(), wideSize * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
cache.setDevicePixelRatio(cRetinaFactor());
|
||||
{
|
||||
Painter p(&cache);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.fillRect(0, 0, wideSize, wideSize, Qt::transparent);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing, true);
|
||||
auto pen = st::shareCheckBorder->p;
|
||||
pen.setWidth(st::shareSelectWidth);
|
||||
p.setPen(pen);
|
||||
p.setBrush(st::shareCheckBg);
|
||||
auto ellipse = QRect((wideSize - size) / 2, (wideSize - size) / 2, size, size);
|
||||
p.drawEllipse(ellipse);
|
||||
}
|
||||
QImage cacheIcon = cache;
|
||||
{
|
||||
Painter p(&cacheIcon);
|
||||
auto ellipse = QRect((wideSize - size) / 2, (wideSize - size) / 2, size, size);
|
||||
st::shareCheckIcon.paint(p, ellipse.topLeft(), wideSize);
|
||||
}
|
||||
_wideCheckCache = App::pixmapFromImageInPlace(std_::move(cache));
|
||||
_wideCheckCache.setDevicePixelRatio(cRetinaFactor());
|
||||
_wideCheckIconCache = App::pixmapFromImageInPlace(std_::move(cacheIcon));
|
||||
_wideCheckIconCache.setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
|
||||
bool ShareInner::hasSelected() const {
|
||||
return _selected.size();
|
||||
}
|
||||
|
||||
void ShareInner::updateFilter(QString filter) {
|
||||
_lastQuery = filter.toLower().trimmed();
|
||||
filter = textSearchKey(filter);
|
||||
|
||||
QStringList f;
|
||||
if (!filter.isEmpty()) {
|
||||
QStringList filterList = filter.split(cWordSplit(), QString::SkipEmptyParts);
|
||||
int l = filterList.size();
|
||||
|
||||
f.reserve(l);
|
||||
for (int i = 0; i < l; ++i) {
|
||||
QString filterName = filterList[i].trimmed();
|
||||
if (filterName.isEmpty()) continue;
|
||||
f.push_back(filterName);
|
||||
}
|
||||
filter = f.join(' ');
|
||||
}
|
||||
if (_filter != filter) {
|
||||
_filter = filter;
|
||||
|
||||
_byUsernameFiltered.clear();
|
||||
for (int i = 0, l = d_byUsernameFiltered.size(); i < l; ++i) {
|
||||
delete d_byUsernameFiltered[i];
|
||||
}
|
||||
d_byUsernameFiltered.clear();
|
||||
|
||||
if (_filter.isEmpty()) {
|
||||
refresh();
|
||||
} else {
|
||||
QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi;
|
||||
|
||||
_filtered.clear();
|
||||
if (!f.isEmpty()) {
|
||||
const Dialogs::List *toFilter = nullptr;
|
||||
if (!_chatsIndexed->isEmpty()) {
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
auto found = _chatsIndexed->filtered(fi->at(0));
|
||||
if (found->isEmpty()) {
|
||||
toFilter = nullptr;
|
||||
break;
|
||||
}
|
||||
if (!toFilter || toFilter->size() > found->size()) {
|
||||
toFilter = found;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toFilter) {
|
||||
_filtered.reserve(toFilter->size());
|
||||
for_const (auto row, *toFilter) {
|
||||
auto &names = row->history()->peer->names;
|
||||
PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni;
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
auto filterName = *fi;
|
||||
for (ni = nb; ni != ne; ++ni) {
|
||||
if (ni->startsWith(*fi)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ni == ne) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fi == fe) {
|
||||
_filtered.push_back(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
refresh();
|
||||
|
||||
_searching = true;
|
||||
emit searchByUsername();
|
||||
}
|
||||
setActive(-1);
|
||||
update();
|
||||
loadProfilePhotos(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ShareInner::peopleReceived(const QString &query, const QVector<MTPPeer> &people) {
|
||||
_lastQuery = query.toLower().trimmed();
|
||||
if (_lastQuery.at(0) == '@') _lastQuery = _lastQuery.mid(1);
|
||||
int32 already = _byUsernameFiltered.size();
|
||||
_byUsernameFiltered.reserve(already + people.size());
|
||||
d_byUsernameFiltered.reserve(already + people.size());
|
||||
for_const (auto &mtpPeer, people) {
|
||||
auto peerId = peerFromMTP(mtpPeer);
|
||||
int j = 0;
|
||||
for (; j < already; ++j) {
|
||||
if (_byUsernameFiltered[j]->id == peerId) break;
|
||||
}
|
||||
if (j == already) {
|
||||
auto *peer = App::peer(peerId);
|
||||
if (!peer || !peer->canWrite()) continue;
|
||||
|
||||
auto chat = new Chat(peer);
|
||||
updateChatName(chat, peer);
|
||||
if (auto row = _chatsIndexed->getRow(peer->id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_byUsernameFiltered.push_back(peer);
|
||||
d_byUsernameFiltered.push_back(chat);
|
||||
}
|
||||
}
|
||||
_searching = false;
|
||||
refresh();
|
||||
}
|
||||
|
||||
void ShareInner::refresh() {
|
||||
auto count = displayedChatsCount();
|
||||
if (count) {
|
||||
auto rows = (count / _columnCount) + (count % _columnCount ? 1 : 0);
|
||||
resize(width(), _rowsTop + rows * _rowHeight);
|
||||
} else {
|
||||
resize(width(), st::noContactsHeight);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
ShareInner::~ShareInner() {
|
||||
for_const (auto chat, _dataMap) {
|
||||
delete chat;
|
||||
}
|
||||
}
|
||||
|
||||
QVector<PeerData*> ShareInner::selected() const {
|
||||
QVector<PeerData*> result;
|
||||
result.reserve(_dataMap.size());
|
||||
for_const (auto chat, _dataMap) {
|
||||
if (chat->selected) {
|
||||
result.push_back(chat->peer);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
QString appendShareGameScoreUrl(const QString &url, const FullMsgId &fullId) {
|
||||
auto shareHashData = QByteArray(0x10, Qt::Uninitialized);
|
||||
auto ints = reinterpret_cast<int32*>(shareHashData.data());
|
||||
ints[0] = MTP::authedId();
|
||||
ints[1] = fullId.channel;
|
||||
ints[2] = fullId.msg;
|
||||
ints[3] = 0;
|
||||
|
||||
auto key128Size = 0x10;
|
||||
auto shareHashEncrypted = QByteArray(key128Size + shareHashData.size(), Qt::Uninitialized);
|
||||
hashSha1(shareHashData.constData(), shareHashData.size(), shareHashEncrypted.data());
|
||||
if (!Local::encrypt(shareHashData.constData(), shareHashEncrypted.data() + key128Size, shareHashData.size(), shareHashEncrypted.constData())) {
|
||||
return url;
|
||||
}
|
||||
|
||||
auto shareHash = shareHashEncrypted.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
auto shareUrl = qsl("tg://share_game_score?hash=") + QString::fromLatin1(shareHash);
|
||||
|
||||
auto shareComponent = qsl("tgShareScoreUrl=") + qthelp::url_encode(shareUrl);
|
||||
|
||||
auto hashPosition = url.indexOf('#');
|
||||
if (hashPosition < 0) {
|
||||
return url + '#' + shareComponent;
|
||||
}
|
||||
auto hash = url.mid(hashPosition + 1);
|
||||
if (hash.indexOf('=') >= 0 || hash.indexOf('?') >= 0) {
|
||||
return url + '&' + shareComponent;
|
||||
}
|
||||
if (!hash.isEmpty()) {
|
||||
return url + '?' + shareComponent;
|
||||
}
|
||||
return url + shareComponent;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void shareGameScoreFromItem(HistoryItem *item) {
|
||||
Ui::showLayer(new ShareBox([msgId = item->fullId()](const QVector<PeerData*> &result) {
|
||||
MTPmessages_ForwardMessages::Flags sendFlags = MTPmessages_ForwardMessages::Flag::f_with_my_score;
|
||||
MTPVector<MTPint> msgIds = MTP_vector<MTPint>(1, MTP_int(msgId.msg));
|
||||
if (auto main = App::main()) {
|
||||
if (auto item = App::histItemById(msgId)) {
|
||||
for_const (auto peer, result) {
|
||||
MTPVector<MTPlong> random = MTP_vector<MTPlong>(1, rand_value<MTPlong>());
|
||||
MTP::send(MTPmessages_ForwardMessages(MTP_flags(sendFlags), item->history()->peer->input, msgIds, random, peer->input), main->rpcDone(&MainWidget::sentUpdatesReceived));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ui::hideLayer();
|
||||
}));
|
||||
}
|
||||
|
||||
class GameMessageResolvedCallback : public SharedCallback<void, ChannelData*, MsgId> {
|
||||
public:
|
||||
void call(ChannelData *channel, MsgId msgId) const override {
|
||||
if (auto item = App::histItemById(channel, msgId)) {
|
||||
shareGameScoreFromItem(item);
|
||||
} else {
|
||||
Ui::showLayer(new InformBox(lang(lng_edit_deleted)));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void shareGameScoreByHash(const QString &hash) {
|
||||
auto key128Size = 0x10;
|
||||
|
||||
auto hashEncrypted = QByteArray::fromBase64(hash.toLatin1(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
if (hashEncrypted.size() <= key128Size || (hashEncrypted.size() % 0x10) != 0) {
|
||||
Ui::showLayer(new InformBox(lang(lng_confirm_phone_link_invalid)));
|
||||
return;
|
||||
}
|
||||
|
||||
auto hashData = QByteArray(hashEncrypted.size() - key128Size, Qt::Uninitialized);
|
||||
if (!Local::decrypt(hashEncrypted.constData() + key128Size, hashData.data(), hashEncrypted.size() - key128Size, hashEncrypted.constData())) {
|
||||
return;
|
||||
}
|
||||
|
||||
char checkSha1[20] = { 0 };
|
||||
if (memcmp(hashSha1(hashData.constData(), hashData.size(), checkSha1), hashEncrypted.constData(), key128Size) != 0) {
|
||||
Ui::showLayer(new InformBox(lang(lng_share_wrong_user)));
|
||||
return;
|
||||
}
|
||||
auto ints = reinterpret_cast<int32*>(hashData.data());
|
||||
if (ints[0] != MTP::authedId()) {
|
||||
Ui::showLayer(new InformBox(lang(lng_share_wrong_user)));
|
||||
return;
|
||||
}
|
||||
|
||||
auto channelId = ints[1];
|
||||
auto msgId = ints[2];
|
||||
if (auto item = App::histItemById(channelId, msgId)) {
|
||||
shareGameScoreFromItem(item);
|
||||
} else if (App::api()) {
|
||||
auto channel = channelId ? App::channelLoaded(channelId) : nullptr;
|
||||
if (channel || !channelId) {
|
||||
App::api()->requestMessageData(channel, msgId, std_::make_unique<GameMessageResolvedCallback>());
|
||||
}
|
||||
}
|
||||
}
|
217
Telegram/SourceFiles/boxes/sharebox.h
Normal file
217
Telegram/SourceFiles/boxes/sharebox.h
Normal file
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "core/lambda_wrap.h"
|
||||
#include "core/observer.h"
|
||||
|
||||
namespace Dialogs {
|
||||
class Row;
|
||||
class IndexedList;
|
||||
} // namespace Dialogs
|
||||
|
||||
namespace internal {
|
||||
class ShareInner;
|
||||
} // namespace internal
|
||||
|
||||
namespace Notify {
|
||||
struct PeerUpdate;
|
||||
} // namespace Notify
|
||||
|
||||
QString appendShareGameScoreUrl(const QString &url, const FullMsgId &fullId);
|
||||
void shareGameScoreByHash(const QString &hash);
|
||||
|
||||
class ShareBox : public ItemListBox, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using SubmitCallback = base::lambda_unique<void(const QVector<PeerData*> &)>;
|
||||
ShareBox(SubmitCallback &&callback);
|
||||
|
||||
private slots:
|
||||
void onFilterUpdate();
|
||||
void onFilterCancel();
|
||||
void onScroll();
|
||||
|
||||
bool onSearchByUsername(bool searchCache = false);
|
||||
void onNeedSearchByUsername();
|
||||
|
||||
void onShare();
|
||||
void onSelectedChanged();
|
||||
|
||||
void onMustScrollTo(int top, int bottom);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
void doSetInnerFocus() override;
|
||||
|
||||
private:
|
||||
void moveButtons();
|
||||
|
||||
void peopleReceived(const MTPcontacts_Found &result, mtpRequestId requestId);
|
||||
bool peopleFailed(const RPCError &error, mtpRequestId requestId);
|
||||
|
||||
SubmitCallback _callback;
|
||||
|
||||
ChildWidget<internal::ShareInner> _inner;
|
||||
ChildWidget<InputField> _filter;
|
||||
ChildWidget<IconedButton> _filterCancel;
|
||||
|
||||
ChildWidget<BoxButton> _share;
|
||||
ChildWidget<BoxButton> _cancel;
|
||||
|
||||
ChildWidget<ScrollableBoxShadow> _topShadow;
|
||||
ChildWidget<ScrollableBoxShadow> _bottomShadow;
|
||||
|
||||
QTimer _searchTimer;
|
||||
QString _peopleQuery;
|
||||
bool _peopleFull = false;
|
||||
mtpRequestId _peopleRequest = 0;
|
||||
|
||||
using PeopleCache = QMap<QString, MTPcontacts_Found>;
|
||||
PeopleCache _peopleCache;
|
||||
|
||||
using PeopleQueries = QMap<mtpRequestId, QString>;
|
||||
PeopleQueries _peopleQueries;
|
||||
|
||||
IntAnimation _scrollAnimation;
|
||||
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
class ShareInner : public ScrolledWidget, public RPCSender, public Notify::Observer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ShareInner(QWidget *parent);
|
||||
|
||||
QVector<PeerData*> selected() const;
|
||||
bool hasSelected() const;
|
||||
|
||||
void peopleReceived(const QString &query, const QVector<MTPPeer> &people);
|
||||
|
||||
void activateSkipRow(int direction);
|
||||
void activateSkipColumn(int direction);
|
||||
void activateSkipPage(int pageHeight, int direction);
|
||||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
void updateFilter(QString filter = QString());
|
||||
|
||||
~ShareInner();
|
||||
|
||||
public slots:
|
||||
void onSelectActive();
|
||||
|
||||
signals:
|
||||
void mustScrollTo(int ymin, int ymax);
|
||||
void filterCancel();
|
||||
void searchByUsername();
|
||||
void selectedChanged();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void enterEvent(QEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
// Observed notifications.
|
||||
void notifyPeerUpdated(const Notify::PeerUpdate &update);
|
||||
|
||||
int displayedChatsCount() const;
|
||||
|
||||
static constexpr int WideCacheScale = 4;
|
||||
struct Chat {
|
||||
Chat(PeerData *peer);
|
||||
PeerData *peer;
|
||||
Text name;
|
||||
bool selected = false;
|
||||
QPixmap wideUserpicCache;
|
||||
ColorAnimation nameFg;
|
||||
FloatAnimation selection;
|
||||
struct Icon {
|
||||
FloatAnimation fadeIn;
|
||||
FloatAnimation fadeOut;
|
||||
QPixmap wideCheckCache;
|
||||
};
|
||||
QList<Icon> icons;
|
||||
};
|
||||
void paintChat(Painter &p, Chat *chat, int index);
|
||||
void updateChat(PeerData *peer);
|
||||
void updateChatName(Chat *chat, PeerData *peer);
|
||||
void repaintChat(PeerData *peer);
|
||||
void removeFadeOutedIcons(Chat *chat);
|
||||
void prepareWideUserpicCache(Chat *chat);
|
||||
void prepareWideCheckIconCache(Chat::Icon *icon);
|
||||
void prepareWideCheckIcons();
|
||||
int chatIndex(PeerData *peer) const;
|
||||
void repaintChatAtIndex(int index);
|
||||
Chat *getChatAtIndex(int index);
|
||||
|
||||
void loadProfilePhotos(int yFrom);
|
||||
void changeCheckState(Chat *chat);
|
||||
|
||||
Chat *getChat(Dialogs::Row *row);
|
||||
void setActive(int active);
|
||||
void updateUpon(const QPoint &pos);
|
||||
|
||||
void refresh();
|
||||
|
||||
float64 _columnSkip = 0.;
|
||||
float64 _rowWidthReal = 0.;
|
||||
int _rowsLeft = 0;
|
||||
int _rowsTop = 0;
|
||||
int _rowWidth = 0;
|
||||
int _rowHeight = 0;
|
||||
int _columnCount = 4;
|
||||
int _active = -1;
|
||||
int _upon = -1;
|
||||
|
||||
std_::unique_ptr<Dialogs::IndexedList> _chatsIndexed;
|
||||
QString _filter;
|
||||
using FilteredDialogs = QVector<Dialogs::Row*>;
|
||||
FilteredDialogs _filtered;
|
||||
|
||||
QPixmap _wideCheckCache, _wideCheckIconCache;
|
||||
|
||||
using DataMap = QMap<PeerData*, Chat*>;
|
||||
DataMap _dataMap;
|
||||
using SelectedChats = OrderedSet<PeerData*>;
|
||||
SelectedChats _selected;
|
||||
|
||||
ChatData *data(Dialogs::Row *row);
|
||||
|
||||
bool _searching = false;
|
||||
QString _lastQuery;
|
||||
using ByUsernameRows = QVector<PeerData*>;
|
||||
using ByUsernameDatas = QVector<Chat*>;
|
||||
ByUsernameRows _byUsernameFiltered;
|
||||
ByUsernameDatas d_byUsernameFiltered;
|
||||
|
||||
};
|
||||
|
||||
} // namespace internal
|
|
@ -24,11 +24,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "stickersetbox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "stickers/stickers.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "apiwrap.h"
|
||||
#include "localstorage.h"
|
||||
#include "dialogs/dialogs_layout.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_stickers.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -37,40 +39,7 @@ constexpr int kArchivedLimitPerPage = 30;
|
|||
|
||||
} // namespace
|
||||
|
||||
namespace Stickers {
|
||||
|
||||
void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
|
||||
auto &v = d.vsets.c_vector().v;
|
||||
auto &order = Global::RefStickerSetsOrder();
|
||||
Stickers::Order archived;
|
||||
archived.reserve(v.size());
|
||||
QMap<uint64, uint64> setsToRequest;
|
||||
for_const (auto &stickerSet, v) {
|
||||
if (stickerSet.type() == mtpc_stickerSetCovered && stickerSet.c_stickerSetCovered().vset.type() == mtpc_stickerSet) {
|
||||
auto set = Stickers::feedSet(stickerSet.c_stickerSetCovered().vset.c_stickerSet());
|
||||
if (set->stickers.isEmpty()) {
|
||||
setsToRequest.insert(set->id, set->access);
|
||||
}
|
||||
auto index = order.indexOf(set->id);
|
||||
if (index >= 0) {
|
||||
order.removeAt(index);
|
||||
}
|
||||
archived.push_back(set->id);
|
||||
}
|
||||
}
|
||||
if (!setsToRequest.isEmpty()) {
|
||||
for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) {
|
||||
App::api()->scheduleStickerSetRequest(i.key(), i.value());
|
||||
}
|
||||
App::api()->requestStickerSets();
|
||||
}
|
||||
Local::writeArchivedStickers();
|
||||
Ui::showLayer(new StickersBox(archived), KeepOtherLayers);
|
||||
}
|
||||
|
||||
} // namespace Stickers
|
||||
|
||||
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget()
|
||||
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : ScrolledWidget()
|
||||
, _input(set) {
|
||||
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
|
||||
switch (set.type()) {
|
||||
|
@ -80,6 +49,8 @@ StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget()
|
|||
MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&StickerSetInner::gotSet), rpcFail(&StickerSetInner::failedSet));
|
||||
App::main()->updateStickers();
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
_previewTimer.setSingleShot(true);
|
||||
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
|
||||
}
|
||||
|
@ -87,15 +58,20 @@ StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget()
|
|||
void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
|
||||
_pack.clear();
|
||||
_emoji.clear();
|
||||
_packOvers.clear();
|
||||
_selected = -1;
|
||||
setCursor(style::cur_default);
|
||||
if (set.type() == mtpc_messages_stickerSet) {
|
||||
auto &d(set.c_messages_stickerSet());
|
||||
auto &v(d.vdocuments.c_vector().v);
|
||||
_pack.reserve(v.size());
|
||||
_packOvers.reserve(v.size());
|
||||
for (int i = 0, l = v.size(); i < l; ++i) {
|
||||
auto doc = App::feedDocument(v.at(i));
|
||||
if (!doc || !doc->sticker()) continue;
|
||||
|
||||
_pack.push_back(doc);
|
||||
_packOvers.push_back(FloatAnimation());
|
||||
}
|
||||
auto &packs(d.vpacks.c_vector().v);
|
||||
for (int i = 0, l = packs.size(); i < l; ++i) {
|
||||
|
@ -144,6 +120,8 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
|
|||
}
|
||||
_loaded = true;
|
||||
|
||||
updateSelected();
|
||||
|
||||
emit updateButtons();
|
||||
}
|
||||
|
||||
|
@ -200,12 +178,13 @@ void StickerSetInner::installDone(const MTPmessages_StickerSetInstallResult &res
|
|||
|
||||
if (result.type() == mtpc_messages_stickerSetInstallResultArchive) {
|
||||
Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive());
|
||||
} else if (wasArchived) {
|
||||
Local::writeArchivedStickers();
|
||||
} else {
|
||||
if (wasArchived) {
|
||||
Local::writeArchivedStickers();
|
||||
}
|
||||
Local::writeInstalledStickers();
|
||||
emit App::main()->stickersUpdated();
|
||||
}
|
||||
|
||||
Local::writeInstalledStickers();
|
||||
emit App::main()->stickersUpdated();
|
||||
emit installed(_setId);
|
||||
}
|
||||
|
||||
|
@ -218,15 +197,16 @@ bool StickerSetInner::installFail(const RPCError &error) {
|
|||
}
|
||||
|
||||
void StickerSetInner::mousePressEvent(QMouseEvent *e) {
|
||||
int32 index = stickerFromGlobalPos(e->globalPos());
|
||||
int index = stickerFromGlobalPos(e->globalPos());
|
||||
if (index >= 0 && index < _pack.size()) {
|
||||
_previewTimer.start(QApplication::startDragTime());
|
||||
}
|
||||
}
|
||||
|
||||
void StickerSetInner::mouseMoveEvent(QMouseEvent *e) {
|
||||
updateSelected();
|
||||
if (_previewShown >= 0) {
|
||||
int32 index = stickerFromGlobalPos(e->globalPos());
|
||||
int index = stickerFromGlobalPos(e->globalPos());
|
||||
if (index >= 0 && index < _pack.size() && index != _previewShown) {
|
||||
_previewShown = index;
|
||||
Ui::showMediaPreview(_pack.at(_previewShown));
|
||||
|
@ -235,11 +215,47 @@ void StickerSetInner::mouseMoveEvent(QMouseEvent *e) {
|
|||
}
|
||||
|
||||
void StickerSetInner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_previewTimer.stop();
|
||||
if (_previewShown >= 0) {
|
||||
_previewShown = -1;
|
||||
return;
|
||||
}
|
||||
if (_previewTimer.isActive()) {
|
||||
_previewTimer.stop();
|
||||
int index = stickerFromGlobalPos(e->globalPos());
|
||||
if (index >= 0 && index < _pack.size()) {
|
||||
if (auto main = App::main()) {
|
||||
if (main->onSendSticker(_pack.at(index))) {
|
||||
Ui::hideSettingsAndLayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StickerSetInner::updateSelected() {
|
||||
auto index = stickerFromGlobalPos(QCursor::pos());
|
||||
if (index != _selected) {
|
||||
startOverAnimation(_selected, 1., 0.);
|
||||
_selected = index;
|
||||
startOverAnimation(_selected, 0., 1.);
|
||||
setCursor(_selected >= 0 ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
}
|
||||
|
||||
void StickerSetInner::startOverAnimation(int index, float64 from, float64 to) {
|
||||
if (index >= 0 && index < _packOvers.size()) {
|
||||
START_ANIMATION(_packOvers[index], func([this, index]() {
|
||||
int row = index / StickerPanPerRow;
|
||||
int column = index % StickerPanPerRow;
|
||||
int left = st::stickersPadding.left() + column * st::stickersSize.width();
|
||||
int top = st::stickersPadding.top() + row * st::stickersSize.height();
|
||||
rtlupdate(left, top, st::stickersSize.width(), st::stickersSize.height());
|
||||
}), from, to, st::emojiPanDuration, anim::linear);
|
||||
}
|
||||
}
|
||||
|
||||
void StickerSetInner::onPreview() {
|
||||
int32 index = stickerFromGlobalPos(QCursor::pos());
|
||||
int index = stickerFromGlobalPos(QCursor::pos());
|
||||
if (index >= 0 && index < _pack.size()) {
|
||||
_previewShown = index;
|
||||
Ui::showMediaPreview(_pack.at(_previewShown));
|
||||
|
@ -271,10 +287,19 @@ void StickerSetInner::paintEvent(QPaintEvent *e) {
|
|||
for (int32 j = 0; j < StickerPanPerRow; ++j) {
|
||||
int32 index = i * StickerPanPerRow + j;
|
||||
if (index >= _pack.size()) break;
|
||||
t_assert(index < _packOvers.size());
|
||||
|
||||
DocumentData *doc = _pack.at(index);
|
||||
QPoint pos(st::stickersPadding.left() + j * st::stickersSize.width(), st::stickersPadding.top() + i * st::stickersSize.height());
|
||||
|
||||
if (auto over = _packOvers[index].current((index == _selected) ? 1. : 0.)) {
|
||||
p.setOpacity(over);
|
||||
QPoint tl(pos);
|
||||
if (rtl()) tl.setX(width() - tl.x() - st::stickersSize.width());
|
||||
App::roundRect(p, QRect(tl, st::stickersSize), st::emojiPanHover, StickerHoverCorners);
|
||||
p.setOpacity(1);
|
||||
|
||||
}
|
||||
bool goodThumb = !doc->thumb->isNull() && ((doc->thumb->width() >= 128) || (doc->thumb->height() >= 128));
|
||||
if (goodThumb) {
|
||||
doc->thumb->load();
|
||||
|
@ -302,10 +327,9 @@ void StickerSetInner::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void StickerSetInner::setScrollBottom(int32 bottom) {
|
||||
if (bottom == _bottom) return;
|
||||
|
||||
_bottom = bottom;
|
||||
void StickerSetInner::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||
_visibleTop = visibleTop;
|
||||
_visibleBottom = visibleBottom;
|
||||
}
|
||||
|
||||
bool StickerSetInner::loaded() const {
|
||||
|
@ -357,7 +381,7 @@ StickerSetBox::StickerSetBox(const MTPInputStickerSet &set) : ScrollableBox(st::
|
|||
connect(&_done, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
|
||||
connect(&_inner, SIGNAL(updateButtons()), this, SLOT(onUpdateButtons()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(scrollArea(), SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
|
||||
connect(&_inner, SIGNAL(installed(uint64)), this, SLOT(onInstalled(uint64)));
|
||||
|
||||
|
@ -394,7 +418,9 @@ void StickerSetBox::onUpdateButtons() {
|
|||
}
|
||||
|
||||
void StickerSetBox::onScroll() {
|
||||
_inner.setScrollBottom(_scroll.scrollTop() + _scroll.height());
|
||||
auto scroll = scrollArea();
|
||||
auto scrollTop = scroll->scrollTop();
|
||||
_inner.setVisibleTopBottom(scrollTop, scrollTop + scroll->height());
|
||||
}
|
||||
|
||||
void StickerSetBox::showAll() {
|
||||
|
@ -454,7 +480,7 @@ void StickerSetBox::resizeEvent(QResizeEvent *e) {
|
|||
|
||||
namespace internal {
|
||||
|
||||
StickersInner::StickersInner(StickersBox::Section section) : TWidget()
|
||||
StickersInner::StickersInner(StickersBox::Section section) : ScrolledWidget()
|
||||
, _section(section)
|
||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||
, _a_shifting(animation(this, &StickersInner::step_shifting))
|
||||
|
@ -467,7 +493,7 @@ StickersInner::StickersInner(StickersBox::Section section) : TWidget()
|
|||
setup();
|
||||
}
|
||||
|
||||
StickersInner::StickersInner(const Stickers::Order &archivedIds) : TWidget()
|
||||
StickersInner::StickersInner(const Stickers::Order &archivedIds) : ScrolledWidget()
|
||||
, _section(StickersBox::Section::ArchivedPart)
|
||||
, _archivedIds(archivedIds)
|
||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||
|
@ -482,10 +508,15 @@ StickersInner::StickersInner(const Stickers::Order &archivedIds) : TWidget()
|
|||
}
|
||||
|
||||
void StickersInner::setup() {
|
||||
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
|
||||
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(onImageLoaded()));
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void StickersInner::onImageLoaded() {
|
||||
update();
|
||||
readVisibleSets();
|
||||
}
|
||||
|
||||
void StickersInner::paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const {
|
||||
if (selected) {
|
||||
p.fillRect(0, y, width(), _buttonHeight, st::contactsBgOver);
|
||||
|
@ -618,18 +649,18 @@ void StickersInner::paintRow(Painter &p, int32 index) {
|
|||
int statusx = namex;
|
||||
int statusy = st::contactsPadding.top() + st::contactsStatusTop;
|
||||
|
||||
p.setFont(st::contactsNameFont);
|
||||
p.setPen(st::black);
|
||||
p.drawTextLeft(namex, namey, width(), s->title, s->titleWidth);
|
||||
|
||||
if (s->unread) {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::stickersFeaturedUnreadBg);
|
||||
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing, true);
|
||||
p.drawEllipse(rtlrect(namex, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width()));
|
||||
p.drawEllipse(rtlrect(namex + s->titleWidth + st::stickersFeaturedUnreadSkip, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width()));
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||
namex += st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip;
|
||||
}
|
||||
p.setFont(st::contactsNameFont);
|
||||
p.setPen(st::black);
|
||||
p.drawTextLeft(namex, namey, width(), s->title);
|
||||
|
||||
p.setFont(st::contactsStatusFont);
|
||||
p.setPen(st::contactsStatusFg);
|
||||
|
@ -760,7 +791,8 @@ void StickersInner::onClearRecent() {
|
|||
emit App::main()->updateStickers();
|
||||
rebuild();
|
||||
|
||||
MTP::send(MTPmessages_ClearRecentStickers());
|
||||
MTPmessages_ClearRecentStickers::Flags flags = 0;
|
||||
MTP::send(MTPmessages_ClearRecentStickers(MTP_flags(flags)));
|
||||
}
|
||||
|
||||
void StickersInner::onClearBoxDestroyed(QObject *box) {
|
||||
|
@ -849,59 +881,13 @@ void StickersInner::installSet(uint64 setId) {
|
|||
|
||||
MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()), rpcDone(&StickersInner::installDone), rpcFail(&StickersInner::installFail, setId));
|
||||
|
||||
auto flags = it->flags;
|
||||
it->flags &= ~(MTPDstickerSet::Flag::f_archived | MTPDstickerSet_ClientFlag::f_unread);
|
||||
it->flags |= MTPDstickerSet::Flag::f_installed;
|
||||
auto changedFlags = flags ^ it->flags;
|
||||
|
||||
auto &order = Global::RefStickerSetsOrder();
|
||||
int insertAtIndex = 0, currentIndex = order.indexOf(setId);
|
||||
if (currentIndex != insertAtIndex) {
|
||||
if (currentIndex > 0) {
|
||||
order.removeAt(currentIndex);
|
||||
}
|
||||
order.insert(insertAtIndex, setId);
|
||||
}
|
||||
|
||||
auto custom = sets.find(Stickers::CustomSetId);
|
||||
if (custom != sets.cend()) {
|
||||
for_const (auto sticker, it->stickers) {
|
||||
int removeIndex = custom->stickers.indexOf(sticker);
|
||||
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
|
||||
}
|
||||
if (custom->stickers.isEmpty()) {
|
||||
sets.erase(custom);
|
||||
}
|
||||
}
|
||||
Local::writeInstalledStickers();
|
||||
if (changedFlags & MTPDstickerSet_ClientFlag::f_unread) Local::writeFeaturedStickers();
|
||||
if (changedFlags & MTPDstickerSet::Flag::f_archived) {
|
||||
auto index = Global::RefArchivedStickerSetsOrder().indexOf(setId);
|
||||
if (index >= 0) {
|
||||
Global::RefArchivedStickerSetsOrder().removeAt(index);
|
||||
Local::writeArchivedStickers();
|
||||
}
|
||||
}
|
||||
emit App::main()->stickersUpdated();
|
||||
Stickers::installLocally(setId);
|
||||
}
|
||||
|
||||
void StickersInner::installDone(const MTPmessages_StickerSetInstallResult &result) {
|
||||
if (result.type() == mtpc_messages_stickerSetInstallResultArchive) {
|
||||
Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive());
|
||||
Local::writeInstalledStickers();
|
||||
Local::writeArchivedStickers();
|
||||
emit App::main()->stickersUpdated();
|
||||
}
|
||||
|
||||
// TEST DATA ONLY
|
||||
//MTPVector<MTPStickerSet> v = MTP_vector<MTPStickerSet>(0);
|
||||
//for (auto &set : Global::RefStickerSets()) {
|
||||
// if (rand() < RAND_MAX / 2) {
|
||||
// set.flags |= MTPDstickerSet::Flag::f_archived;
|
||||
// v._vector().v.push_back(MTP_stickerSet(MTP_flags(set.flags), MTP_long(set.id), MTP_long(set.access), MTP_string(set.title), MTP_string(set.shortName), MTP_int(set.count), MTP_int(set.hash)));
|
||||
// }
|
||||
//}
|
||||
//Stickers::applyArchivedResult(MTP_messages_stickerSetInstallResultArchive(v).c_messages_stickerSetInstallResultArchive());
|
||||
}
|
||||
|
||||
bool StickersInner::installFail(uint64 setId, const RPCError &error) {
|
||||
|
@ -914,19 +900,7 @@ bool StickersInner::installFail(uint64 setId, const RPCError &error) {
|
|||
return true;
|
||||
}
|
||||
|
||||
it->flags &= ~MTPDstickerSet::Flag::f_installed;
|
||||
|
||||
auto &order = Global::RefStickerSetsOrder();
|
||||
int currentIndex = order.indexOf(setId);
|
||||
if (currentIndex >= 0) {
|
||||
order.removeAt(currentIndex);
|
||||
}
|
||||
|
||||
Local::writeInstalledStickers();
|
||||
emit App::main()->stickersUpdated();
|
||||
|
||||
Ui::showLayer(new InformBox(lang(lng_stickers_not_found)), KeepOtherLayers);
|
||||
|
||||
Stickers::undoInstallLocally(setId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1056,14 +1030,6 @@ void StickersInner::rebuild() {
|
|||
}
|
||||
App::api()->requestStickerSets();
|
||||
updateSize();
|
||||
|
||||
if (_section == Section::Featured && Global::FeaturedStickerSetsUnreadCount()) {
|
||||
Global::SetFeaturedStickerSetsUnreadCount(0);
|
||||
for (auto &set : Global::RefStickerSets()) {
|
||||
set.flags &= ~MTPDstickerSet_ClientFlag::f_unread;
|
||||
}
|
||||
MTP::send(MTPmessages_ReadFeaturedStickers(), rpcDone(&StickersInner::readFeaturedDone), rpcFail(&StickersInner::readFeaturedFail));
|
||||
}
|
||||
}
|
||||
|
||||
void StickersInner::updateSize() {
|
||||
|
@ -1091,7 +1057,7 @@ void StickersInner::updateRows() {
|
|||
if (_section == Section::Installed) {
|
||||
row->disabled = false;
|
||||
}
|
||||
row->title = fillSetTitle(set, maxNameWidth);
|
||||
row->title = fillSetTitle(set, maxNameWidth, &row->titleWidth);
|
||||
row->count = fillSetCount(set);
|
||||
}
|
||||
}
|
||||
|
@ -1115,6 +1081,7 @@ int StickersInner::countMaxNameWidth() const {
|
|||
namew -= qMax(qMax(qMax(_returnWidth, _removeWidth), _restoreWidth), _clearWidth);
|
||||
} else {
|
||||
namew -= st::stickersAddIcon.width() - st::defaultActiveButton.width;
|
||||
namew -= st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip;
|
||||
}
|
||||
return namew;
|
||||
}
|
||||
|
@ -1130,10 +1097,11 @@ void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth)
|
|||
int pixw = 0, pixh = 0;
|
||||
fillSetCover(set, &sticker, &pixw, &pixh);
|
||||
|
||||
QString title = fillSetTitle(set, maxNameWidth);
|
||||
int titleWidth = 0;
|
||||
QString title = fillSetTitle(set, maxNameWidth, &titleWidth);
|
||||
int count = fillSetCount(set);
|
||||
|
||||
_rows.push_back(new StickerSetRow(set.id, sticker, count, title, installed, official, unread, disabled, recent, pixw, pixh));
|
||||
_rows.push_back(new StickerSetRow(set.id, sticker, count, title, titleWidth, installed, official, unread, disabled, recent, pixw, pixh));
|
||||
_animStartTimes.push_back(0);
|
||||
}
|
||||
|
||||
|
@ -1181,11 +1149,15 @@ int StickersInner::fillSetCount(const Stickers::Set &set) const {
|
|||
return result + added;
|
||||
}
|
||||
|
||||
QString StickersInner::fillSetTitle(const Stickers::Set &set, int maxNameWidth) const {
|
||||
QString StickersInner::fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const {
|
||||
auto result = set.title;
|
||||
int32 titleWidth = st::contactsNameFont->width(result);
|
||||
int titleWidth = st::contactsNameFont->width(result);
|
||||
if (titleWidth > maxNameWidth) {
|
||||
result = st::contactsNameFont->elided(result, maxNameWidth);
|
||||
titleWidth = st::contactsNameFont->width(result);
|
||||
}
|
||||
if (outTitleWidth) {
|
||||
*outTitleWidth = titleWidth;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1201,35 +1173,11 @@ void StickersInner::fillSetFlags(const Stickers::Set &set, bool *outRecent, bool
|
|||
*outOfficial = (set.flags & MTPDstickerSet::Flag::f_official);
|
||||
*outDisabled = (set.flags & MTPDstickerSet::Flag::f_archived);
|
||||
if (_section == Section::Featured) {
|
||||
*outUnread = _unreadSets.contains(set.id);
|
||||
if (!*outUnread && (set.flags & MTPDstickerSet_ClientFlag::f_unread)) {
|
||||
*outUnread = true;
|
||||
_unreadSets.insert(set.id);
|
||||
}
|
||||
*outUnread = (set.flags & MTPDstickerSet_ClientFlag::f_unread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StickersInner::readFeaturedDone(const MTPBool &result) {
|
||||
Local::writeFeaturedStickers();
|
||||
emit App::main()->stickersUpdated();
|
||||
}
|
||||
|
||||
bool StickersInner::readFeaturedFail(const RPCError &error) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
|
||||
int unreadCount = 0;
|
||||
for_const (auto &set, Global::StickerSets()) {
|
||||
if (!(set.flags & MTPDstickerSet::Flag::f_installed)) {
|
||||
if (set.flags & MTPDstickerSet_ClientFlag::f_unread) {
|
||||
++unreadCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
Stickers::Order StickersInner::getOrder() const {
|
||||
Stickers::Order result;
|
||||
result.reserve(_rows.size());
|
||||
|
@ -1253,6 +1201,32 @@ Stickers::Order StickersInner::getDisabledSets() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void StickersInner::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||
if (_section == Section::Featured) {
|
||||
_visibleTop = visibleTop;
|
||||
_visibleBottom = visibleBottom;
|
||||
readVisibleSets();
|
||||
}
|
||||
}
|
||||
|
||||
void StickersInner::readVisibleSets() {
|
||||
auto itemsVisibleTop = _visibleTop - _itemsTop;
|
||||
auto itemsVisibleBottom = _visibleBottom - _itemsTop;
|
||||
int rowFrom = floorclamp(itemsVisibleTop, _rowHeight, 0, _rows.size());
|
||||
int rowTo = ceilclamp(itemsVisibleBottom, _rowHeight, 0, _rows.size());
|
||||
for (int i = rowFrom; i < rowTo; ++i) {
|
||||
if (!_rows[i]->unread) {
|
||||
continue;
|
||||
}
|
||||
if (i * _rowHeight < itemsVisibleTop || (i + 1) * _rowHeight > itemsVisibleBottom) {
|
||||
continue;
|
||||
}
|
||||
if (!_rows[i]->sticker || _rows[i]->sticker->thumb->loaded() || _rows[i]->sticker->loaded()) {
|
||||
Stickers::markFeaturedAsRead(_rows[i]->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StickersInner::setVisibleScrollbar(int32 width) {
|
||||
_scrollbar = width;
|
||||
}
|
||||
|
@ -1299,9 +1273,24 @@ void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedSti
|
|||
bool addedSet = false;
|
||||
auto &v = stickers.vsets.c_vector().v;
|
||||
for_const (auto &stickerSet, v) {
|
||||
if (stickerSet.type() != mtpc_stickerSetCovered || stickerSet.c_stickerSetCovered().vset.type() != mtpc_stickerSet) continue;
|
||||
const MTPDstickerSet *setData = nullptr;
|
||||
switch (stickerSet.type()) {
|
||||
case mtpc_stickerSetCovered: {
|
||||
auto &d = stickerSet.c_stickerSetCovered();
|
||||
if (d.vset.type() == mtpc_stickerSet) {
|
||||
setData = &d.vset.c_stickerSet();
|
||||
}
|
||||
} break;
|
||||
case mtpc_stickerSetMultiCovered: {
|
||||
auto &d = stickerSet.c_stickerSetMultiCovered();
|
||||
if (d.vset.type() == mtpc_stickerSet) {
|
||||
setData = &d.vset.c_stickerSet();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
if (!setData) continue;
|
||||
|
||||
if (auto set = Stickers::feedSet(stickerSet.c_stickerSetCovered().vset.c_stickerSet())) {
|
||||
if (auto set = Stickers::feedSet(*setData)) {
|
||||
auto index = archived.indexOf(set->id);
|
||||
if (archived.isEmpty() || index != archived.size() - 1) {
|
||||
if (index < archived.size() - 1) {
|
||||
|
@ -1326,7 +1315,7 @@ void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedSti
|
|||
if (addedSet) {
|
||||
_inner->updateSize();
|
||||
setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight)));
|
||||
_inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0);
|
||||
_inner->setVisibleScrollbar((scrollArea()->scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0);
|
||||
App::api()->requestStickerSets();
|
||||
} else {
|
||||
_allArchivedLoaded = v.isEmpty() || (offsetId != 0);
|
||||
|
@ -1389,7 +1378,7 @@ void StickersBox::setup() {
|
|||
connect(_inner, SIGNAL(checkDraggingScroll(int)), this, SLOT(onCheckDraggingScroll(int)));
|
||||
connect(_inner, SIGNAL(noDraggingScroll()), this, SLOT(onNoDraggingScroll()));
|
||||
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(scrollArea(), SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
_scrollTimer.setSingleShot(false);
|
||||
|
||||
rebuildList();
|
||||
|
@ -1398,14 +1387,21 @@ void StickersBox::setup() {
|
|||
}
|
||||
|
||||
void StickersBox::onScroll() {
|
||||
updateVisibleTopBottom();
|
||||
checkLoadMoreArchived();
|
||||
}
|
||||
|
||||
void StickersBox::updateVisibleTopBottom() {
|
||||
auto visibleTop = scrollArea()->scrollTop();
|
||||
auto visibleBottom = visibleTop + scrollArea()->height();
|
||||
_inner->setVisibleTopBottom(visibleTop, visibleBottom);
|
||||
}
|
||||
|
||||
void StickersBox::checkLoadMoreArchived() {
|
||||
if (_section != Section::Archived) return;
|
||||
|
||||
int scrollTop = _scroll.scrollTop(), scrollTopMax = _scroll.scrollTopMax();
|
||||
if (scrollTop + PreloadHeightsCount * _scroll.height() >= scrollTopMax) {
|
||||
int scrollTop = scrollArea()->scrollTop(), scrollTopMax = scrollArea()->scrollTopMax();
|
||||
if (scrollTop + PreloadHeightsCount * scrollArea()->height() >= scrollTopMax) {
|
||||
if (!_archivedRequestId && !_allArchivedLoaded) {
|
||||
uint64 lastId = 0;
|
||||
for (auto setId = Global::ArchivedStickerSetsOrder().cend(), e = Global::ArchivedStickerSetsOrder().cbegin(); setId != e;) {
|
||||
|
@ -1452,10 +1448,12 @@ void StickersBox::saveOrder() {
|
|||
if (order.size() > 1) {
|
||||
QVector<MTPlong> mtpOrder;
|
||||
mtpOrder.reserve(order.size());
|
||||
for (int32 i = 0, l = order.size(); i < l; ++i) {
|
||||
for (int i = 0, l = order.size(); i < l; ++i) {
|
||||
mtpOrder.push_back(MTP_long(order.at(i)));
|
||||
}
|
||||
_reorderRequest = MTP::send(MTPmessages_ReorderStickerSets(MTP_vector<MTPlong>(mtpOrder)), rpcDone(&StickersBox::reorderDone), rpcFail(&StickersBox::reorderFail));
|
||||
|
||||
MTPmessages_ReorderStickerSets::Flags flags = 0;
|
||||
_reorderRequest = MTP::send(MTPmessages_ReorderStickerSets(MTP_flags(flags), MTP_vector<MTPlong>(mtpOrder)), rpcDone(&StickersBox::reorderDone), rpcFail(&StickersBox::reorderFail));
|
||||
} else {
|
||||
reorderDone(MTP_boolTrue());
|
||||
}
|
||||
|
@ -1522,7 +1520,8 @@ StickersBox::~StickersBox() {
|
|||
void StickersBox::resizeEvent(QResizeEvent *e) {
|
||||
ItemListBox::resizeEvent(e);
|
||||
_inner->resize(width(), _inner->height());
|
||||
_inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0);
|
||||
_inner->setVisibleScrollbar((scrollArea()->scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0);
|
||||
updateVisibleTopBottom();
|
||||
if (_topShadow) {
|
||||
_topShadow->setGeometry(0, st::boxTitleHeight + _aboutHeight, width(), st::lineWidth);
|
||||
}
|
||||
|
@ -1546,14 +1545,14 @@ void StickersBox::onStickersUpdated() {
|
|||
void StickersBox::rebuildList() {
|
||||
_inner->rebuild();
|
||||
setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight)));
|
||||
_inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0);
|
||||
_inner->setVisibleScrollbar((scrollArea()->scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0);
|
||||
}
|
||||
|
||||
void StickersBox::onCheckDraggingScroll(int localY) {
|
||||
if (localY < _scroll.scrollTop()) {
|
||||
_scrollDelta = localY - _scroll.scrollTop();
|
||||
} else if (localY >= _scroll.scrollTop() + _scroll.height()) {
|
||||
_scrollDelta = localY - _scroll.scrollTop() - _scroll.height() + 1;
|
||||
if (localY < scrollArea()->scrollTop()) {
|
||||
_scrollDelta = localY - scrollArea()->scrollTop();
|
||||
} else if (localY >= scrollArea()->scrollTop() + scrollArea()->height()) {
|
||||
_scrollDelta = localY - scrollArea()->scrollTop() - scrollArea()->height() + 1;
|
||||
} else {
|
||||
_scrollDelta = 0;
|
||||
}
|
||||
|
@ -1570,7 +1569,7 @@ void StickersBox::onNoDraggingScroll() {
|
|||
|
||||
void StickersBox::onScrollTimer() {
|
||||
int32 d = (_scrollDelta > 0) ? qMin(_scrollDelta * 3 / 20 + 1, int32(MaxScrollSpeed)) : qMax(_scrollDelta * 3 / 20 - 1, -int32(MaxScrollSpeed));
|
||||
_scroll.scrollToY(_scroll.scrollTop() + d);
|
||||
scrollArea()->scrollToY(scrollArea()->scrollTop() + d);
|
||||
}
|
||||
|
||||
void StickersBox::onSave() {
|
||||
|
|
|
@ -24,42 +24,40 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
class ConfirmBox;
|
||||
|
||||
class StickerSetInner : public TWidget, public RPCSender {
|
||||
class StickerSetInner : public ScrolledWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
StickerSetInner(const MTPInputStickerSet &set);
|
||||
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
bool loaded() const;
|
||||
int32 notInstalled() const;
|
||||
bool official() const;
|
||||
QString title() const;
|
||||
QString shortName() const;
|
||||
|
||||
void setScrollBottom(int32 bottom);
|
||||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
void install();
|
||||
|
||||
~StickerSetInner();
|
||||
|
||||
public slots:
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private slots:
|
||||
void onPreview();
|
||||
|
||||
signals:
|
||||
|
||||
void updateButtons();
|
||||
void installed(uint64 id);
|
||||
|
||||
private:
|
||||
|
||||
int32 stickerFromGlobalPos(const QPoint &p) const;
|
||||
void updateSelected();
|
||||
void startOverAnimation(int index, float64 from, float64 to);
|
||||
int stickerFromGlobalPos(const QPoint &p) const;
|
||||
|
||||
void gotSet(const MTPmessages_StickerSet &set);
|
||||
bool failedSet(const RPCError &error);
|
||||
|
@ -67,6 +65,7 @@ private:
|
|||
void installDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
bool installFail(const RPCError &error);
|
||||
|
||||
QVector<FloatAnimation> _packOvers;
|
||||
StickerPack _pack;
|
||||
StickersByEmojiMap _emoji;
|
||||
bool _loaded = false;
|
||||
|
@ -77,13 +76,17 @@ private:
|
|||
int32 _setHash = 0;
|
||||
MTPDstickerSet::Flags _setFlags = 0;
|
||||
|
||||
int32 _bottom = 0;
|
||||
int _visibleTop = 0;
|
||||
int _visibleBottom = 0;
|
||||
MTPInputStickerSet _input;
|
||||
|
||||
mtpRequestId _installRequest = 0;
|
||||
|
||||
int _selected = -1;
|
||||
|
||||
QTimer _previewTimer;
|
||||
int32 _previewShown = -1;
|
||||
int _previewShown = -1;
|
||||
|
||||
};
|
||||
|
||||
class StickerSetBox : public ScrollableBox, public RPCSender {
|
||||
|
@ -169,6 +172,7 @@ private:
|
|||
bool reorderFail(const RPCError &result);
|
||||
void saveOrder();
|
||||
|
||||
void updateVisibleTopBottom();
|
||||
void checkLoadMoreArchived();
|
||||
void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result);
|
||||
|
||||
|
@ -198,7 +202,7 @@ int32 stickerPacksCount(bool includeDisabledOfficial = false);
|
|||
|
||||
namespace internal {
|
||||
|
||||
class StickersInner : public TWidget, public RPCSender {
|
||||
class StickersInner : public ScrolledWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -220,6 +224,7 @@ public:
|
|||
Stickers::Order getDisabledSets() const;
|
||||
|
||||
void setVisibleScrollbar(int32 width);
|
||||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
|
||||
~StickersInner();
|
||||
|
||||
|
@ -239,6 +244,9 @@ public slots:
|
|||
void onClearRecent();
|
||||
void onClearBoxDestroyed(QObject *box);
|
||||
|
||||
private slots:
|
||||
void onImageLoaded();
|
||||
|
||||
private:
|
||||
void setup();
|
||||
void paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const;
|
||||
|
@ -249,21 +257,22 @@ private:
|
|||
void setActionSel(int32 actionSel);
|
||||
float64 aboveShadowOpacity() const;
|
||||
|
||||
void readVisibleSets();
|
||||
|
||||
void installSet(uint64 setId);
|
||||
void installDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
bool installFail(uint64 setId, const RPCError &error);
|
||||
void readFeaturedDone(const MTPBool &result);
|
||||
bool readFeaturedFail(const RPCError &error);
|
||||
|
||||
Section _section;
|
||||
Stickers::Order _archivedIds;
|
||||
|
||||
int32 _rowHeight;
|
||||
struct StickerSetRow {
|
||||
StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, bool installed, bool official, bool unread, bool disabled, bool recent, int32 pixw, int32 pixh) : id(id)
|
||||
StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool disabled, bool recent, int32 pixw, int32 pixh) : id(id)
|
||||
, sticker(sticker)
|
||||
, count(count)
|
||||
, title(title)
|
||||
, titleWidth(titleWidth)
|
||||
, installed(installed)
|
||||
, official(official)
|
||||
, unread(unread)
|
||||
|
@ -277,6 +286,7 @@ private:
|
|||
DocumentData *sticker;
|
||||
int32 count;
|
||||
QString title;
|
||||
int titleWidth;
|
||||
bool installed, official, unread, disabled, recent;
|
||||
int32 pixw, pixh;
|
||||
anim::ivalue yadd;
|
||||
|
@ -286,7 +296,7 @@ private:
|
|||
void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth);
|
||||
void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const;
|
||||
int fillSetCount(const Stickers::Set &set) const;
|
||||
QString fillSetTitle(const Stickers::Set &set, int maxNameWidth) const;
|
||||
QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const;
|
||||
void fillSetFlags(const Stickers::Set &set, bool *outRecent, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outDisabled);
|
||||
|
||||
int countMaxNameWidth() const;
|
||||
|
@ -297,7 +307,9 @@ private:
|
|||
anim::fvalue _aboveShadowFadeOpacity = { 0., 0. };
|
||||
Animation _a_shifting;
|
||||
|
||||
int32 _itemsTop;
|
||||
int _visibleTop = 0;
|
||||
int _visibleBottom = 0;
|
||||
int _itemsTop = 0;
|
||||
|
||||
bool _saving = false;
|
||||
|
||||
|
@ -312,9 +324,6 @@ private:
|
|||
bool _hasFeaturedButton = false;
|
||||
bool _hasArchivedButton = false;
|
||||
|
||||
// Remember all the unread set ids to display unread dots.
|
||||
OrderedSet<uint64> _unreadSets;
|
||||
|
||||
QPoint _mouse;
|
||||
int _selected = -3; // -2 - featured stickers button, -1 - archived stickers button
|
||||
int _pressed = -2;
|
||||
|
|
|
@ -1275,8 +1275,8 @@ public:
|
|||
template <typename R, typename... Args>
|
||||
class NullFunctionImplementation : public FunctionImplementation<R, Args...> {
|
||||
public:
|
||||
virtual R call(Args... args) { return R(); }
|
||||
virtual void destroy() {}
|
||||
R call(Args... args) override { return R(); }
|
||||
void destroy() override {}
|
||||
static NullFunctionImplementation<R, Args...> SharedInstance;
|
||||
|
||||
};
|
||||
|
@ -1325,7 +1325,7 @@ class WrappedFunction : public FunctionImplementation<R, Args...> {
|
|||
public:
|
||||
using Method = R(*)(Args... args);
|
||||
WrappedFunction(Method method) : _method(method) {}
|
||||
virtual R call(Args... args) { return (*_method)(args...); }
|
||||
R call(Args... args) override { return (*_method)(args...); }
|
||||
|
||||
private:
|
||||
Method _method;
|
||||
|
@ -1341,7 +1341,7 @@ class ObjectFunction : public FunctionImplementation<R, Args...> {
|
|||
public:
|
||||
using Method = R(I::*)(Args... args);
|
||||
ObjectFunction(O *obj, Method method) : _obj(obj), _method(method) {}
|
||||
virtual R call(Args... args) { return (_obj->*_method)(args...); }
|
||||
R call(Args... args) override { return (_obj->*_method)(args...); }
|
||||
|
||||
private:
|
||||
O *_obj;
|
||||
|
|
|
@ -26,6 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "boxes/confirmbox.h"
|
||||
#include "core/qthelp_regex.h"
|
||||
#include "core/qthelp_url.h"
|
||||
#include "localstorage.h"
|
||||
|
||||
QString UrlClickHandler::copyToClipboardContextItemText() const {
|
||||
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);
|
||||
|
@ -113,6 +114,20 @@ void HiddenUrlClickHandler::onClick(Qt::MouseButton button) const {
|
|||
}
|
||||
}
|
||||
|
||||
void BotGameUrlClickHandler::onClick(Qt::MouseButton button) const {
|
||||
auto u = url();
|
||||
|
||||
u = tryConvertUrlToLocal(u);
|
||||
|
||||
if (u.startsWith(qstr("tg://"))) {
|
||||
App::openLocalUrl(u);
|
||||
} else if (!_bot || Local::isBotTrusted(_bot)) {
|
||||
doOpen(u);
|
||||
} else {
|
||||
Ui::showLayer(new ConfirmBotGameBox(_bot, u));
|
||||
}
|
||||
}
|
||||
|
||||
QString HiddenUrlClickHandler::getExpandedLinkText(ExpandLinksMode mode, const QStringRef &textPart) const {
|
||||
QString result;
|
||||
if (mode == ExpandLinksAll) {
|
||||
|
|
|
@ -122,6 +122,17 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class BotGameUrlClickHandler : public UrlClickHandler {
|
||||
public:
|
||||
BotGameUrlClickHandler(UserData *bot, QString url) : UrlClickHandler(url, false), _bot(bot) {
|
||||
}
|
||||
void onClick(Qt::MouseButton button) const override;
|
||||
|
||||
private:
|
||||
UserData *_bot;
|
||||
|
||||
};
|
||||
|
||||
class MentionClickHandler : public TextClickHandler {
|
||||
public:
|
||||
MentionClickHandler(const QString &tag) : _tag(tag) {
|
||||
|
|
|
@ -372,3 +372,42 @@ public:
|
|||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
// While we still use Function<>
|
||||
|
||||
template <typename FunctionType>
|
||||
struct LambdaFunctionHelper;
|
||||
|
||||
template <typename Lambda, typename R, typename ...Args>
|
||||
struct LambdaFunctionHelper<R(Lambda::*)(Args...) const> {
|
||||
using FunctionType = Function<R, Args...>;
|
||||
using UniqueType = base::lambda_unique<R(Args...)>;
|
||||
};
|
||||
|
||||
template <typename FunctionType>
|
||||
using LambdaGetFunction = typename LambdaFunctionHelper<FunctionType>::FunctionType;
|
||||
|
||||
template <typename FunctionType>
|
||||
using LambdaGetUnique = typename LambdaFunctionHelper<FunctionType>::UniqueType;
|
||||
|
||||
template <typename R, typename ...Args>
|
||||
class LambdaFunctionImplementation : public FunctionImplementation<R, Args...> {
|
||||
public:
|
||||
LambdaFunctionImplementation(base::lambda_unique<R(Args...)> &&lambda) : _lambda(std_::move(lambda)) {
|
||||
}
|
||||
R call(Args... args) override { return _lambda(std_::forward<Args>(args)...); }
|
||||
|
||||
private:
|
||||
base::lambda_unique<R(Args...)> _lambda;
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename ...Args>
|
||||
inline Function<R, Args...> lambda_wrap_helper(base::lambda_unique<R(Args...)> &&lambda) {
|
||||
return Function<R, Args...>(new LambdaFunctionImplementation<R, Args...>(std_::move(lambda)));
|
||||
}
|
||||
|
||||
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
|
||||
inline LambdaGetFunction<decltype(&Lambda::operator())> func(Lambda &&lambda) {
|
||||
return lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
|
||||
}
|
||||
|
|
|
@ -71,6 +71,16 @@ void IndexedList::adjustByPos(const RowsByLetter &links) {
|
|||
}
|
||||
}
|
||||
|
||||
void IndexedList::moveToTop(PeerData *peer) {
|
||||
if (_list.moveToTop(peer->id)) {
|
||||
for_const (auto ch, peer->chars) {
|
||||
if (auto list = _index.value(ch)) {
|
||||
list->moveToTop(peer->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IndexedList::peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
|
||||
t_assert(_sortMode != SortMode::Date);
|
||||
if (_sortMode == SortMode::Name) {
|
||||
|
|
|
@ -34,6 +34,7 @@ public:
|
|||
RowsByLetter addToEnd(History *history);
|
||||
Row *addByName(History *history);
|
||||
void adjustByPos(const RowsByLetter &links);
|
||||
void moveToTop(PeerData *peer);
|
||||
|
||||
// For sortMode != SortMode::Date
|
||||
void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
|
||||
|
|
|
@ -189,6 +189,14 @@ void List::adjustByPos(Row *row) {
|
|||
}
|
||||
}
|
||||
|
||||
bool List::moveToTop(PeerId peerId) {
|
||||
auto i = _rowByPeer.find(peerId);
|
||||
if (i == _rowByPeer.cend()) return false;
|
||||
|
||||
insertBefore(i.value(), _begin);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool List::del(PeerId peerId, Row *replacedBy) {
|
||||
auto i = _rowByPeer.find(peerId);
|
||||
if (i == _rowByPeer.cend()) return false;
|
||||
|
|
|
@ -53,10 +53,9 @@ public:
|
|||
|
||||
void paint(Painter &p, int32 w, int32 hFrom, int32 hTo, PeerData *act, PeerData *sel, bool onlyBackground) const;
|
||||
Row *addToEnd(History *history);
|
||||
bool insertBefore(Row *row, Row *before);
|
||||
bool insertAfter(Row *row, Row *after);
|
||||
Row *adjustByName(const PeerData *peer);
|
||||
Row *addByName(History *history);
|
||||
bool moveToTop(PeerId peerId);
|
||||
void adjustByPos(Row *row);
|
||||
bool del(PeerId peerId, Row *replacedBy = nullptr);
|
||||
void remove(Row *row);
|
||||
|
@ -114,6 +113,8 @@ public:
|
|||
|
||||
private:
|
||||
void adjustCurrent(int y, int h) const;
|
||||
bool insertBefore(Row *row, Row *before);
|
||||
bool insertAfter(Row *row, Row *after);
|
||||
static Row *next(Row *row) {
|
||||
return row->_next;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,7 +27,6 @@ class Dropdown : public TWidget {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Dropdown(QWidget *parent, const style::dropdown &st = st::dropdownDef);
|
||||
|
||||
IconedButton *addButton(IconedButton *button);
|
||||
|
@ -61,11 +60,9 @@ public:
|
|||
}
|
||||
|
||||
signals:
|
||||
|
||||
void hiding();
|
||||
|
||||
public slots:
|
||||
|
||||
void hideStart();
|
||||
void hideFinish();
|
||||
|
||||
|
@ -75,20 +72,19 @@ public slots:
|
|||
void buttonStateChanged(int oldState, ButtonStateChangeSource source);
|
||||
|
||||
private:
|
||||
|
||||
void adjustButtons();
|
||||
|
||||
bool _ignore;
|
||||
bool _ignore = false;
|
||||
|
||||
typedef QVector<IconedButton*> Buttons;
|
||||
Buttons _buttons;
|
||||
|
||||
int32 _selected;
|
||||
int32 _selected = -1;
|
||||
|
||||
const style::dropdown &_st;
|
||||
|
||||
int32 _width, _height;
|
||||
bool _hiding;
|
||||
bool _hiding = false;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
Animation _a_appearance;
|
||||
|
@ -103,7 +99,6 @@ class DragArea : public TWidget {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
DragArea(QWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
@ -133,18 +128,15 @@ public:
|
|||
}
|
||||
|
||||
signals:
|
||||
|
||||
void dropped(const QMimeData *data);
|
||||
|
||||
public slots:
|
||||
|
||||
void hideStart();
|
||||
void hideFinish();
|
||||
|
||||
void showStart();
|
||||
|
||||
private:
|
||||
|
||||
bool _hiding, _in;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
|
@ -156,588 +148,3 @@ private:
|
|||
QString _text, _subtext;
|
||||
|
||||
};
|
||||
|
||||
namespace InlineBots {
|
||||
namespace Layout {
|
||||
class ItemBase;
|
||||
} // namespace Layout
|
||||
class Result;
|
||||
} // namespace InlineBots
|
||||
|
||||
namespace internal {
|
||||
|
||||
constexpr int InlineItemsMaxPerRow = 5;
|
||||
constexpr int EmojiColorsCount = 5;
|
||||
|
||||
using InlineResult = InlineBots::Result;
|
||||
using InlineResults = QList<InlineBots::Result*>;
|
||||
using InlineItem = InlineBots::Layout::ItemBase;
|
||||
|
||||
struct InlineCacheEntry {
|
||||
~InlineCacheEntry() {
|
||||
clearResults();
|
||||
}
|
||||
QString nextOffset;
|
||||
QString switchPmText, switchPmStartToken;
|
||||
InlineResults results; // owns this results list
|
||||
void clearResults();
|
||||
};
|
||||
|
||||
class EmojiColorPicker : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
EmojiColorPicker();
|
||||
|
||||
void showEmoji(uint32 code);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
void showStart();
|
||||
|
||||
void clearSelection(bool fast = false);
|
||||
|
||||
public slots:
|
||||
|
||||
void hideStart(bool fast = false);
|
||||
|
||||
signals:
|
||||
|
||||
void emojiSelected(EmojiPtr emoji);
|
||||
void hidden();
|
||||
|
||||
private:
|
||||
|
||||
void drawVariant(Painter &p, int variant);
|
||||
|
||||
void updateSelected();
|
||||
|
||||
bool _ignoreShow;
|
||||
|
||||
EmojiPtr _variants[EmojiColorsCount + 1];
|
||||
|
||||
typedef QMap<int32, uint64> EmojiAnimations; // index - showing, -index - hiding
|
||||
EmojiAnimations _emojiAnimations;
|
||||
Animation _a_selected;
|
||||
|
||||
float64 _hovers[EmojiColorsCount + 1];
|
||||
|
||||
int32 _selected, _pressedSel;
|
||||
QPoint _lastMousePos;
|
||||
|
||||
bool _hiding;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
Animation _a_appearance;
|
||||
|
||||
QTimer _hideTimer;
|
||||
|
||||
BoxShadow _shadow;
|
||||
|
||||
};
|
||||
|
||||
class EmojiPanel;
|
||||
class EmojiPanInner : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
EmojiPanInner();
|
||||
|
||||
void setMaxHeight(int32 h);
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
void leaveToChildEvent(QEvent *e, QWidget *child) override;
|
||||
void enterFromChildEvent(QEvent *e, QWidget *child) override;
|
||||
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
void hideFinish();
|
||||
|
||||
void showEmojiPack(DBIEmojiTab packIndex);
|
||||
|
||||
void clearSelection(bool fast = false);
|
||||
|
||||
DBIEmojiTab currentTab(int yOffset) const;
|
||||
|
||||
void refreshRecent();
|
||||
|
||||
void setScrollTop(int top);
|
||||
|
||||
void fillPanels(QVector<EmojiPanel*> &panels);
|
||||
void refreshPanels(QVector<EmojiPanel*> &panels);
|
||||
|
||||
public slots:
|
||||
|
||||
void updateSelected();
|
||||
|
||||
void onShowPicker();
|
||||
void onPickerHidden();
|
||||
void onColorSelected(EmojiPtr emoji);
|
||||
|
||||
bool checkPickerHide();
|
||||
|
||||
signals:
|
||||
|
||||
void selected(EmojiPtr emoji);
|
||||
|
||||
void switchToStickers();
|
||||
|
||||
void scrollToY(int y);
|
||||
void disableScroll(bool dis);
|
||||
|
||||
void needRefreshPanels();
|
||||
void saveConfigDelayed(int32 delay);
|
||||
|
||||
private:
|
||||
|
||||
int32 _maxHeight;
|
||||
|
||||
int32 countHeight();
|
||||
void selectEmoji(EmojiPtr emoji);
|
||||
|
||||
QRect emojiRect(int tab, int sel);
|
||||
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _animations;
|
||||
Animation _a_selected;
|
||||
|
||||
int32 _top, _counts[emojiTabCount];
|
||||
|
||||
QVector<EmojiPtr> _emojis[emojiTabCount];
|
||||
QVector<float64> _hovers[emojiTabCount];
|
||||
|
||||
int32 _esize;
|
||||
|
||||
int32 _selected, _pressedSel, _pickerSel;
|
||||
QPoint _lastMousePos;
|
||||
|
||||
EmojiColorPicker _picker;
|
||||
QTimer _showPickerTimer;
|
||||
};
|
||||
|
||||
struct StickerIcon {
|
||||
StickerIcon(uint64 setId) : setId(setId), sticker(0), pixw(0), pixh(0) {
|
||||
}
|
||||
StickerIcon(uint64 setId, DocumentData *sticker, int32 pixw, int32 pixh) : setId(setId), sticker(sticker), pixw(pixw), pixh(pixh) {
|
||||
}
|
||||
uint64 setId;
|
||||
DocumentData *sticker;
|
||||
int32 pixw, pixh;
|
||||
};
|
||||
|
||||
class StickerPanInner : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
StickerPanInner();
|
||||
|
||||
void setMaxHeight(int32 h);
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
void leaveToChildEvent(QEvent *e, QWidget *child) override;
|
||||
void enterFromChildEvent(QEvent *e, QWidget *child) override;
|
||||
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
|
||||
void hideFinish(bool completely);
|
||||
void showFinish();
|
||||
void showStickerSet(uint64 setId);
|
||||
void updateShowingSavedGifs();
|
||||
|
||||
bool showSectionIcons() const;
|
||||
void clearSelection(bool fast = false);
|
||||
|
||||
void refreshStickers();
|
||||
void refreshRecentStickers(bool resize = true);
|
||||
void refreshSavedGifs();
|
||||
int refreshInlineRows(UserData *bot, const InlineCacheEntry *results, bool resultsDeleted);
|
||||
void refreshRecent();
|
||||
void inlineBotChanged();
|
||||
void hideInlineRowsPanel();
|
||||
void clearInlineRowsPanel();
|
||||
|
||||
void fillIcons(QList<StickerIcon> &icons);
|
||||
void fillPanels(QVector<EmojiPanel*> &panels);
|
||||
void refreshPanels(QVector<EmojiPanel*> &panels);
|
||||
|
||||
void setScrollTop(int top);
|
||||
void preloadImages();
|
||||
|
||||
uint64 currentSet(int yOffset) const;
|
||||
|
||||
void notify_inlineItemLayoutChanged(const InlineItem *layout);
|
||||
void ui_repaintInlineItem(const InlineItem *layout);
|
||||
bool ui_isInlineItemVisible(const InlineItem *layout);
|
||||
bool ui_isInlineItemBeingChosen();
|
||||
|
||||
bool inlineResultsShown() const {
|
||||
return _showingInlineItems && !_showingSavedGifs;
|
||||
}
|
||||
int32 countHeight(bool plain = false);
|
||||
|
||||
~StickerPanInner();
|
||||
|
||||
private slots:
|
||||
|
||||
void updateSelected();
|
||||
void onSettings();
|
||||
void onPreview();
|
||||
void onUpdateInlineItems();
|
||||
void onSwitchPm();
|
||||
|
||||
signals:
|
||||
|
||||
void selected(DocumentData *sticker);
|
||||
void selected(PhotoData *photo);
|
||||
void selected(InlineBots::Result *result, UserData *bot);
|
||||
|
||||
void removing(quint64 setId);
|
||||
|
||||
void refreshIcons();
|
||||
void emptyInlineRows();
|
||||
|
||||
void switchToEmoji();
|
||||
|
||||
void scrollToY(int y);
|
||||
void scrollUpdated();
|
||||
void disableScroll(bool dis);
|
||||
void needRefreshPanels();
|
||||
|
||||
void saveConfigDelayed(int32 delay);
|
||||
|
||||
private:
|
||||
|
||||
void paintInlineItems(Painter &p, const QRect &r);
|
||||
void paintStickers(Painter &p, const QRect &r);
|
||||
|
||||
void refreshSwitchPmButton(const InlineCacheEntry *entry);
|
||||
|
||||
void appendSet(uint64 setId);
|
||||
|
||||
void selectEmoji(EmojiPtr emoji);
|
||||
QRect stickerRect(int tab, int sel);
|
||||
|
||||
int32 _maxHeight;
|
||||
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _animations;
|
||||
Animation _a_selected;
|
||||
|
||||
int32 _top;
|
||||
|
||||
struct DisplayedSet {
|
||||
DisplayedSet(uint64 id, MTPDstickerSet::Flags flags, const QString &title, int32 hoversSize, const StickerPack &pack = StickerPack()) : id(id), flags(flags), title(title), hovers(hoversSize, 0), pack(pack) {
|
||||
}
|
||||
uint64 id;
|
||||
MTPDstickerSet::Flags flags;
|
||||
QString title;
|
||||
QVector<float64> hovers;
|
||||
StickerPack pack;
|
||||
};
|
||||
QList<DisplayedSet> _sets;
|
||||
QList<bool> _custom;
|
||||
|
||||
bool _showingSavedGifs, _showingInlineItems;
|
||||
bool _setGifCommand;
|
||||
UserData *_inlineBot;
|
||||
QString _inlineBotTitle;
|
||||
uint64 _lastScrolled;
|
||||
QTimer _updateInlineItems;
|
||||
bool _inlineWithThumb;
|
||||
|
||||
std_::unique_ptr<BoxButton> _switchPmButton;
|
||||
QString _switchPmStartToken;
|
||||
|
||||
typedef QVector<InlineItem*> InlineItems;
|
||||
struct InlineRow {
|
||||
InlineRow() : height(0) {
|
||||
}
|
||||
int32 height;
|
||||
InlineItems items;
|
||||
};
|
||||
typedef QVector<InlineRow> InlineRows;
|
||||
InlineRows _inlineRows;
|
||||
void clearInlineRows(bool resultsDeleted);
|
||||
|
||||
using GifLayouts = QMap<DocumentData*, InlineItem*>;
|
||||
GifLayouts _gifLayouts;
|
||||
InlineItem *layoutPrepareSavedGif(DocumentData *doc, int32 position);
|
||||
|
||||
using InlineLayouts = QMap<InlineResult*, InlineItem*>;
|
||||
InlineLayouts _inlineLayouts;
|
||||
InlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
|
||||
|
||||
bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth);
|
||||
bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false);
|
||||
|
||||
InlineRow &layoutInlineRow(InlineRow &row, int32 sumWidth = 0);
|
||||
void deleteUnusedGifLayouts();
|
||||
|
||||
void deleteUnusedInlineLayouts();
|
||||
|
||||
int32 validateExistingInlineRows(const InlineResults &results);
|
||||
int32 _selected, _pressedSel;
|
||||
QPoint _lastMousePos;
|
||||
|
||||
LinkButton _settings;
|
||||
|
||||
QTimer _previewTimer;
|
||||
bool _previewShown;
|
||||
};
|
||||
|
||||
class EmojiPanel : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
EmojiPanel(QWidget *parent, const QString &text, uint64 setId, bool special, int32 wantedY); // Stickers::NoneSetId if in emoji
|
||||
void setText(const QString &text);
|
||||
void setDeleteVisible(bool isVisible);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
|
||||
int32 wantedY() const {
|
||||
return _wantedY;
|
||||
}
|
||||
void setWantedY(int32 y) {
|
||||
_wantedY = y;
|
||||
}
|
||||
|
||||
signals:
|
||||
|
||||
void deleteClicked(quint64 setId);
|
||||
void mousePressed();
|
||||
|
||||
public slots:
|
||||
|
||||
void onDelete();
|
||||
|
||||
private:
|
||||
|
||||
void updateText();
|
||||
|
||||
int32 _wantedY;
|
||||
QString _text, _fullText;
|
||||
uint64 _setId;
|
||||
bool _special, _deleteVisible;
|
||||
IconedButton *_delete;
|
||||
|
||||
};
|
||||
|
||||
class EmojiSwitchButton : public Button {
|
||||
public:
|
||||
|
||||
EmojiSwitchButton(QWidget *parent, bool toStickers); // otherwise toEmoji
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void updateText(const QString &inlineBotUsername = QString());
|
||||
|
||||
protected:
|
||||
|
||||
bool _toStickers;
|
||||
QString _text;
|
||||
int32 _textWidth;
|
||||
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
class EmojiPan : public TWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
EmojiPan(QWidget *parent);
|
||||
|
||||
void setMaxHeight(int32 h);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
void moveBottom(int32 bottom, bool force = false);
|
||||
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void otherEnter();
|
||||
void otherLeave();
|
||||
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
|
||||
bool event(QEvent *e);
|
||||
|
||||
void fastHide();
|
||||
bool hiding() const {
|
||||
return _hiding || _hideTimer.isActive();
|
||||
}
|
||||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void step_slide(float64 ms, bool timer);
|
||||
void step_icons(uint64 ms, bool timer);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *e);
|
||||
void stickersInstalled(uint64 setId);
|
||||
|
||||
void queryInlineBot(UserData *bot, PeerData *peer, QString query);
|
||||
void clearInlineBot();
|
||||
|
||||
bool overlaps(const QRect &globalRect) {
|
||||
if (isHidden() || !_cache.isNull()) return false;
|
||||
|
||||
return QRect(st::dropdownDef.padding.left(),
|
||||
st::dropdownDef.padding.top(),
|
||||
_width - st::dropdownDef.padding.left() - st::dropdownDef.padding.right(),
|
||||
_height - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom()
|
||||
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||
}
|
||||
|
||||
void notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout);
|
||||
void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
|
||||
bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
|
||||
bool ui_isInlineItemBeingChosen();
|
||||
|
||||
bool inlineResultsShown() const {
|
||||
return s_inner.inlineResultsShown();
|
||||
}
|
||||
|
||||
public slots:
|
||||
|
||||
void refreshStickers();
|
||||
void refreshSavedGifs();
|
||||
|
||||
void hideStart();
|
||||
void hideFinish();
|
||||
|
||||
void showStart();
|
||||
void onWndActiveChanged();
|
||||
|
||||
void onTabChange();
|
||||
void onScrollEmoji();
|
||||
void onScrollStickers();
|
||||
void onSwitch();
|
||||
|
||||
void onRemoveSet(quint64 setId);
|
||||
void onRemoveSetSure();
|
||||
void onDelayedHide();
|
||||
|
||||
void onRefreshIcons();
|
||||
void onRefreshPanels();
|
||||
|
||||
void onSaveConfig();
|
||||
void onSaveConfigDelayed(int32 delay);
|
||||
|
||||
void onInlineRequest();
|
||||
void onEmptyInlineRows();
|
||||
|
||||
signals:
|
||||
|
||||
void emojiSelected(EmojiPtr emoji);
|
||||
void stickerSelected(DocumentData *sticker);
|
||||
void photoSelected(PhotoData *photo);
|
||||
void inlineResultSelected(InlineBots::Result *result, UserData *bot);
|
||||
|
||||
void updateStickers();
|
||||
|
||||
private:
|
||||
void paintStickerSettingsIcon(Painter &p) const;
|
||||
|
||||
void validateSelectedIcon(bool animated = false);
|
||||
|
||||
int32 _maxHeight, _contentMaxHeight, _contentHeight, _contentHeightEmoji, _contentHeightStickers;
|
||||
bool _horizontal;
|
||||
void updateContentHeight();
|
||||
|
||||
void leaveToChildEvent(QEvent *e, QWidget *child);
|
||||
void hideAnimated();
|
||||
void prepareShowHideCache();
|
||||
|
||||
void updateSelected();
|
||||
void updateIcons();
|
||||
|
||||
void prepareTab(int32 &left, int32 top, int32 _width, FlatRadiobutton &tab);
|
||||
void updatePanelsPositions(const QVector<internal::EmojiPanel*> &panels, int32 st);
|
||||
|
||||
void showAll();
|
||||
void hideAll();
|
||||
|
||||
bool _noTabUpdate;
|
||||
|
||||
int32 _width, _height, _bottom;
|
||||
bool _hiding;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
Animation _a_appearance;
|
||||
|
||||
QTimer _hideTimer;
|
||||
|
||||
BoxShadow _shadow;
|
||||
|
||||
FlatRadiobutton _recent, _people, _nature, _food, _activity, _travel, _objects, _symbols;
|
||||
QList<internal::StickerIcon> _icons;
|
||||
QVector<float64> _iconHovers;
|
||||
int32 _iconOver, _iconSel, _iconDown;
|
||||
bool _iconsDragging;
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _iconAnimations;
|
||||
Animation _a_icons;
|
||||
QPoint _iconsMousePos, _iconsMouseDown;
|
||||
int32 _iconsLeft, _iconsTop;
|
||||
int32 _iconsStartX, _iconsMax;
|
||||
anim::ivalue _iconsX, _iconSelX;
|
||||
uint64 _iconsStartAnim;
|
||||
|
||||
bool _stickersShown, _shownFromInlineQuery;
|
||||
QPixmap _fromCache, _toCache;
|
||||
anim::ivalue a_fromCoord, a_toCoord;
|
||||
anim::fvalue a_fromAlpha, a_toAlpha;
|
||||
Animation _a_slide;
|
||||
|
||||
ScrollArea e_scroll;
|
||||
internal::EmojiPanInner e_inner;
|
||||
QVector<internal::EmojiPanel*> e_panels;
|
||||
internal::EmojiSwitchButton e_switch;
|
||||
ScrollArea s_scroll;
|
||||
internal::StickerPanInner s_inner;
|
||||
QVector<internal::EmojiPanel*> s_panels;
|
||||
internal::EmojiSwitchButton s_switch;
|
||||
|
||||
uint64 _removingSetId;
|
||||
|
||||
QTimer _saveConfigTimer;
|
||||
|
||||
// inline bots
|
||||
typedef QMap<QString, internal::InlineCacheEntry*> InlineCache;
|
||||
InlineCache _inlineCache;
|
||||
QTimer _inlineRequestTimer;
|
||||
|
||||
void inlineBotChanged();
|
||||
int32 showInlineRows(bool newResults);
|
||||
bool hideOnNoInlineResults();
|
||||
void recountContentMaxHeight();
|
||||
bool refreshInlineRows(int32 *added = 0);
|
||||
UserData *_inlineBot;
|
||||
PeerData *_inlineQueryPeer = nullptr;
|
||||
QString _inlineQuery, _inlineNextQuery, _inlineNextOffset;
|
||||
mtpRequestId _inlineRequestId;
|
||||
void inlineResultsDone(const MTPmessages_BotResults &result);
|
||||
bool inlineResultsFail(const RPCError &error);
|
||||
|
||||
};
|
||||
|
|
|
@ -55,7 +55,7 @@ void activateBotCommand(const HistoryItem *msg, int row, int col) {
|
|||
const HistoryMessageReplyMarkup::Button *button = nullptr;
|
||||
if (auto markup = msg->Get<HistoryMessageReplyMarkup>()) {
|
||||
if (row < markup->rows.size()) {
|
||||
const auto &buttonRow(markup->rows.at(row));
|
||||
auto &buttonRow = markup->rows[row];
|
||||
if (col < buttonRow.size()) {
|
||||
button = &buttonRow.at(col);
|
||||
}
|
||||
|
@ -63,37 +63,39 @@ void activateBotCommand(const HistoryItem *msg, int row, int col) {
|
|||
}
|
||||
if (!button) return;
|
||||
|
||||
using ButtonType = HistoryMessageReplyMarkup::Button::Type;
|
||||
switch (button->type) {
|
||||
case HistoryMessageReplyMarkup::Button::Default: {
|
||||
case ButtonType::Default: {
|
||||
// Copy string before passing it to the sending method
|
||||
// because the original button can be destroyed inside.
|
||||
MsgId replyTo = (msg->id > 0) ? msg->id : 0;
|
||||
sendBotCommand(msg->history()->peer, msg->fromOriginal()->asUser(), QString(button->text), replyTo);
|
||||
} break;
|
||||
|
||||
case HistoryMessageReplyMarkup::Button::Callback: {
|
||||
if (MainWidget *m = main()) {
|
||||
case ButtonType::Callback:
|
||||
case ButtonType::Game: {
|
||||
if (auto m = main()) {
|
||||
m->app_sendBotCallback(button, msg, row, col);
|
||||
}
|
||||
} break;
|
||||
|
||||
case HistoryMessageReplyMarkup::Button::Url: {
|
||||
case ButtonType::Url: {
|
||||
auto url = QString::fromUtf8(button->data);
|
||||
UrlClickHandler(url).onClick(Qt::LeftButton);
|
||||
HiddenUrlClickHandler(url).onClick(Qt::LeftButton);
|
||||
} break;
|
||||
|
||||
case HistoryMessageReplyMarkup::Button::RequestLocation: {
|
||||
case ButtonType::RequestLocation: {
|
||||
Ui::showLayer(new InformBox(lang(lng_bot_share_location_unavailable)));
|
||||
} break;
|
||||
|
||||
case HistoryMessageReplyMarkup::Button::RequestPhone: {
|
||||
case ButtonType::RequestPhone: {
|
||||
SharePhoneConfirmBox *box = new SharePhoneConfirmBox(msg->history()->peer);
|
||||
box->connect(box, SIGNAL(confirmed(PeerData*)), App::main(), SLOT(onSharePhoneWithBot(PeerData*)));
|
||||
Ui::showLayer(box);
|
||||
} break;
|
||||
|
||||
case HistoryMessageReplyMarkup::Button::SwitchInlineSame:
|
||||
case HistoryMessageReplyMarkup::Button::SwitchInline: {
|
||||
case ButtonType::SwitchInlineSame:
|
||||
case ButtonType::SwitchInline: {
|
||||
if (auto m = App::main()) {
|
||||
auto getMessageBot = [msg]() -> UserData* {
|
||||
if (auto bot = msg->viaBot()) {
|
||||
|
@ -107,7 +109,7 @@ void activateBotCommand(const HistoryItem *msg, int row, int col) {
|
|||
};
|
||||
if (auto bot = getMessageBot()) {
|
||||
auto tryFastSwitch = [bot, &button, msgId = msg->id]() -> bool {
|
||||
auto samePeer = (button->type == HistoryMessageReplyMarkup::Button::SwitchInlineSame);
|
||||
auto samePeer = (button->type == ButtonType::SwitchInlineSame);
|
||||
if (samePeer) {
|
||||
Notify::switchInlineBotButtonReceived(QString::fromUtf8(button->data), bot, msgId);
|
||||
return true;
|
||||
|
|
|
@ -193,11 +193,12 @@ enum Flags {
|
|||
|
||||
namespace Stickers {
|
||||
|
||||
static const uint64 DefaultSetId = 0; // for backward compatibility
|
||||
static const uint64 CustomSetId = 0xFFFFFFFFFFFFFFFFULL;
|
||||
static const uint64 RecentSetId = 0xFFFFFFFFFFFFFFFEULL; // for emoji/stickers panel, should not appear in Sets
|
||||
static const uint64 NoneSetId = 0xFFFFFFFFFFFFFFFDULL; // for emoji/stickers panel, should not appear in Sets
|
||||
static const uint64 CloudRecentSetId = 0xFFFFFFFFFFFFFFFCULL; // for cloud-stored recent stickers
|
||||
constexpr uint64 DefaultSetId = 0; // for backward compatibility
|
||||
constexpr uint64 CustomSetId = 0xFFFFFFFFFFFFFFFFULL;
|
||||
constexpr uint64 RecentSetId = 0xFFFFFFFFFFFFFFFEULL; // for emoji/stickers panel, should not appear in Sets
|
||||
constexpr uint64 NoneSetId = 0xFFFFFFFFFFFFFFFDULL; // for emoji/stickers panel, should not appear in Sets
|
||||
constexpr uint64 CloudRecentSetId = 0xFFFFFFFFFFFFFFFCULL; // for cloud-stored recent stickers
|
||||
constexpr uint64 FeaturedSetId = 0xFFFFFFFFFFFFFFFBULL; // for emoji/stickers panel, should not appear in Sets
|
||||
struct Set {
|
||||
Set(uint64 id, uint64 access, const QString &title, const QString &shortName, int32 count, int32 hash, MTPDstickerSet::Flags flags)
|
||||
: id(id)
|
||||
|
|
|
@ -674,9 +674,9 @@ void checkForSwitchInlineButton(HistoryItem *item) {
|
|||
return;
|
||||
}
|
||||
if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
|
||||
for_const (const auto &row, markup->rows) {
|
||||
for_const (const auto &button, row) {
|
||||
if (button.type == HistoryMessageReplyMarkup::Button::SwitchInline) {
|
||||
for_const (auto &row, markup->rows) {
|
||||
for_const (auto &button, row) {
|
||||
if (button.type == HistoryMessageReplyMarkup::Button::Type::SwitchInline) {
|
||||
Notify::switchInlineBotButtonReceived(QString::fromUtf8(button.data));
|
||||
return;
|
||||
}
|
||||
|
@ -2222,7 +2222,7 @@ public:
|
|||
// Copy to clipboard support.
|
||||
void copyToClipboard() const override {
|
||||
if (auto button = getButton()) {
|
||||
if (button->type == HistoryMessageReplyMarkup::Button::Url) {
|
||||
if (button->type == HistoryMessageReplyMarkup::Button::Type::Url) {
|
||||
auto url = QString::fromUtf8(button->data);
|
||||
if (!url.isEmpty()) {
|
||||
QApplication::clipboard()->setText(url);
|
||||
|
@ -2232,7 +2232,7 @@ public:
|
|||
}
|
||||
QString copyToClipboardContextItemText() const override {
|
||||
if (auto button = getButton()) {
|
||||
if (button->type == HistoryMessageReplyMarkup::Button::Url) {
|
||||
if (button->type == HistoryMessageReplyMarkup::Button::Type::Url) {
|
||||
return lang(lng_context_copy_link);
|
||||
}
|
||||
}
|
||||
|
@ -2247,7 +2247,7 @@ public:
|
|||
if (auto item = App::histItemById(_itemId)) {
|
||||
if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
|
||||
if (_row < markup->rows.size()) {
|
||||
const HistoryMessageReplyMarkup::ButtonRow &row(markup->rows.at(_row));
|
||||
auto &row = markup->rows.at(_row);
|
||||
if (_col < row.size()) {
|
||||
return &row.at(_col);
|
||||
}
|
||||
|
@ -2292,14 +2292,14 @@ ReplyKeyboard::ReplyKeyboard(const HistoryItem *item, StylePtr &&s)
|
|||
if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
|
||||
_rows.reserve(markup->rows.size());
|
||||
for (int i = 0, l = markup->rows.size(); i != l; ++i) {
|
||||
const HistoryMessageReplyMarkup::ButtonRow &row(markup->rows.at(i));
|
||||
auto &row = markup->rows.at(i);
|
||||
int s = row.size();
|
||||
ButtonRow newRow(s, Button());
|
||||
for (int j = 0; j != s; ++j) {
|
||||
Button &button(newRow[j]);
|
||||
QString str = row.at(j).text;
|
||||
auto &button = newRow[j];
|
||||
auto str = row.at(j).text;
|
||||
button.type = row.at(j).type;
|
||||
button.link.reset(new ReplyMarkupClickHandler(item, i, j));
|
||||
button.link = MakeShared<ReplyMarkupClickHandler>(item, i, j);
|
||||
button.text.setText(_st->textFont(), textOneLine(str), _textPlainOptions);
|
||||
button.characters = str.isEmpty() ? 1 : str.size();
|
||||
}
|
||||
|
@ -2323,14 +2323,14 @@ void ReplyKeyboard::resize(int width, int height) {
|
|||
|
||||
auto markup = _item->Get<HistoryMessageReplyMarkup>();
|
||||
float64 y = 0, buttonHeight = _rows.isEmpty() ? _st->buttonHeight() : (float64(height + _st->buttonSkip()) / _rows.size());
|
||||
for (ButtonRow &row : _rows) {
|
||||
for (auto &row : _rows) {
|
||||
int s = row.size();
|
||||
|
||||
int widthForButtons = _width - ((s - 1) * _st->buttonSkip());
|
||||
int widthForText = widthForButtons;
|
||||
int widthOfText = 0;
|
||||
int maxMinButtonWidth = 0;
|
||||
for_const (const Button &button, row) {
|
||||
for_const (auto &button, row) {
|
||||
widthOfText += qMax(button.text.maxWidth(), 1);
|
||||
int minButtonWidth = _st->minButtonWidth(button.type);
|
||||
widthForText -= minButtonWidth;
|
||||
|
@ -2368,10 +2368,10 @@ void ReplyKeyboard::resize(int width, int height) {
|
|||
}
|
||||
|
||||
bool ReplyKeyboard::isEnoughSpace(int width, const style::botKeyboardButton &st) const {
|
||||
for_const (const auto &row, _rows) {
|
||||
for_const (auto &row, _rows) {
|
||||
int s = row.size();
|
||||
int widthLeft = width - ((s - 1) * st.margin + s * 2 * st.padding);
|
||||
for_const (const auto &button, row) {
|
||||
for_const (auto &button, row) {
|
||||
widthLeft -= qMax(button.text.maxWidth(), 1);
|
||||
if (widthLeft < 0) {
|
||||
if (row.size() > 3) {
|
||||
|
@ -2416,8 +2416,8 @@ void ReplyKeyboard::paint(Painter &p, const QRect &clip) const {
|
|||
t_assert(_width > 0);
|
||||
|
||||
_st->startPaint(p);
|
||||
for_const (const ButtonRow &row, _rows) {
|
||||
for_const (const Button &button, row) {
|
||||
for_const (auto &row, _rows) {
|
||||
for_const (auto &button, row) {
|
||||
QRect rect(button.rect);
|
||||
if (rect.y() >= clip.y() + clip.height()) return;
|
||||
if (rect.y() + rect.height() < clip.y()) continue;
|
||||
|
@ -2433,8 +2433,8 @@ void ReplyKeyboard::paint(Painter &p, const QRect &clip) const {
|
|||
ClickHandlerPtr ReplyKeyboard::getState(int x, int y) const {
|
||||
t_assert(_width > 0);
|
||||
|
||||
for_const (const ButtonRow &row, _rows) {
|
||||
for_const (const Button &button, row) {
|
||||
for_const (auto &row, _rows) {
|
||||
for_const (auto &button, row) {
|
||||
QRect rect(button.rect);
|
||||
|
||||
// just ignore the buttons that didn't layout well
|
||||
|
@ -2453,7 +2453,7 @@ void ReplyKeyboard::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool act
|
|||
|
||||
bool startAnimation = false;
|
||||
for (int i = 0, rows = _rows.size(); i != rows; ++i) {
|
||||
const ButtonRow &row(_rows.at(i));
|
||||
auto &row = _rows.at(i);
|
||||
for (int j = 0, cols = row.size(); j != cols; ++j) {
|
||||
if (row.at(j).link == p) {
|
||||
bool startAnimation = _animations.isEmpty();
|
||||
|
@ -2514,8 +2514,9 @@ void ReplyKeyboard::Style::paintButton(Painter &p, const ReplyKeyboard::Button &
|
|||
|
||||
paintButtonBg(p, rect, pressed, button.howMuchOver);
|
||||
paintButtonIcon(p, rect, button.type);
|
||||
if (button.type == HistoryMessageReplyMarkup::Button::Callback) {
|
||||
if (const HistoryMessageReplyMarkup::Button *data = button.link->getButton()) {
|
||||
if (button.type == HistoryMessageReplyMarkup::Button::Type::Callback
|
||||
|| button.type == HistoryMessageReplyMarkup::Button::Type::Game) {
|
||||
if (auto data = button.link->getButton()) {
|
||||
if (data->requestId) {
|
||||
paintButtonLoading(p, rect);
|
||||
}
|
||||
|
@ -2541,43 +2542,48 @@ void HistoryMessageReplyMarkup::createFromButtonRows(const QVector<MTPKeyboardBu
|
|||
}
|
||||
|
||||
rows.reserve(v.size());
|
||||
for_const (const auto &row, v) {
|
||||
for_const (auto &row, v) {
|
||||
switch (row.type()) {
|
||||
case mtpc_keyboardButtonRow: {
|
||||
const auto &r(row.c_keyboardButtonRow());
|
||||
const auto &b(r.vbuttons.c_vector().v);
|
||||
auto &r = row.c_keyboardButtonRow();
|
||||
auto &b = r.vbuttons.c_vector().v;
|
||||
if (!b.isEmpty()) {
|
||||
ButtonRow buttonRow;
|
||||
buttonRow.reserve(b.size());
|
||||
for_const (const auto &button, b) {
|
||||
switch (button.type()) {
|
||||
case mtpc_keyboardButton: {
|
||||
buttonRow.push_back({ Button::Default, qs(button.c_keyboardButton().vtext), QByteArray(), 0 });
|
||||
buttonRow.push_back({ Button::Type::Default, qs(button.c_keyboardButton().vtext), QByteArray(), 0 });
|
||||
} break;
|
||||
case mtpc_keyboardButtonCallback: {
|
||||
const auto &buttonData(button.c_keyboardButtonCallback());
|
||||
buttonRow.push_back({ Button::Callback, qs(buttonData.vtext), qba(buttonData.vdata), 0 });
|
||||
auto &buttonData = button.c_keyboardButtonCallback();
|
||||
buttonRow.push_back({ Button::Type::Callback, qs(buttonData.vtext), qba(buttonData.vdata), 0 });
|
||||
} break;
|
||||
case mtpc_keyboardButtonRequestGeoLocation: {
|
||||
buttonRow.push_back({ Button::RequestLocation, qs(button.c_keyboardButtonRequestGeoLocation().vtext), QByteArray(), 0 });
|
||||
buttonRow.push_back({ Button::Type::RequestLocation, qs(button.c_keyboardButtonRequestGeoLocation().vtext), QByteArray(), 0 });
|
||||
} break;
|
||||
case mtpc_keyboardButtonRequestPhone: {
|
||||
buttonRow.push_back({ Button::RequestPhone, qs(button.c_keyboardButtonRequestPhone().vtext), QByteArray(), 0 });
|
||||
buttonRow.push_back({ Button::Type::RequestPhone, qs(button.c_keyboardButtonRequestPhone().vtext), QByteArray(), 0 });
|
||||
} break;
|
||||
case mtpc_keyboardButtonUrl: {
|
||||
const auto &buttonData(button.c_keyboardButtonUrl());
|
||||
buttonRow.push_back({ Button::Url, qs(buttonData.vtext), qba(buttonData.vurl), 0 });
|
||||
auto &buttonData = button.c_keyboardButtonUrl();
|
||||
buttonRow.push_back({ Button::Type::Url, qs(buttonData.vtext), qba(buttonData.vurl), 0 });
|
||||
} break;
|
||||
case mtpc_keyboardButtonSwitchInline: {
|
||||
auto &buttonData = button.c_keyboardButtonSwitchInline();
|
||||
auto buttonType = buttonData.is_same_peer() ? Button::SwitchInlineSame : Button::SwitchInline;
|
||||
auto buttonType = buttonData.is_same_peer() ? Button::Type::SwitchInlineSame : Button::Type::SwitchInline;
|
||||
buttonRow.push_back({ buttonType, qs(buttonData.vtext), qba(buttonData.vquery), 0 });
|
||||
if (buttonType == Button::SwitchInline) {
|
||||
if (buttonType == Button::Type::SwitchInline) {
|
||||
// Optimization flag.
|
||||
// Fast check on all new messages if there is a switch button to auto-click it.
|
||||
flags |= MTPDreplyKeyboardMarkup_ClientFlag::f_has_switch_inline_button;
|
||||
}
|
||||
} break;
|
||||
case mtpc_keyboardButtonGame: {
|
||||
auto &buttonData = button.c_keyboardButtonGame();
|
||||
auto strData = QString::number(buttonData.vgame_id.v) + ',' + qs(buttonData.vgame_title);
|
||||
buttonRow.push_back({ Button::Type::Game, qs(buttonData.vtext), strData.toUtf8(), 0 });
|
||||
} break;
|
||||
}
|
||||
}
|
||||
if (!buttonRow.isEmpty()) rows.push_back(buttonRow);
|
||||
|
@ -6614,11 +6620,11 @@ void HistoryMessage::KeyboardStyle::paintButtonIcon(Painter &p, const QRect &rec
|
|||
using Button = HistoryMessageReplyMarkup::Button;
|
||||
style::sprite sprite;
|
||||
switch (type) {
|
||||
case Button::Url: sprite = st::msgBotKbUrlIcon; break;
|
||||
// case Button::RequestPhone: sprite = st::msgBotKbRequestPhoneIcon; break;
|
||||
// case Button::RequestLocation: sprite = st::msgBotKbRequestLocationIcon; break;
|
||||
case Button::SwitchInlineSame:
|
||||
case Button::SwitchInline: sprite = st::msgBotKbSwitchPmIcon; break;
|
||||
case Button::Type::Url: sprite = st::msgBotKbUrlIcon; break;
|
||||
// case Button::Type::RequestPhone: sprite = st::msgBotKbRequestPhoneIcon; break;
|
||||
// case Button::Type::RequestLocation: sprite = st::msgBotKbRequestLocationIcon; break;
|
||||
case Button::Type::SwitchInlineSame:
|
||||
case Button::Type::SwitchInline: sprite = st::msgBotKbSwitchPmIcon; break;
|
||||
}
|
||||
if (!sprite.isEmpty()) {
|
||||
p.drawSprite(rect.x() + rect.width() - sprite.pxWidth() - st::msgBotKbIconPadding, rect.y() + st::msgBotKbIconPadding, sprite);
|
||||
|
@ -6634,12 +6640,13 @@ int HistoryMessage::KeyboardStyle::minButtonWidth(HistoryMessageReplyMarkup::But
|
|||
using Button = HistoryMessageReplyMarkup::Button;
|
||||
int result = 2 * buttonPadding(), iconWidth = 0;
|
||||
switch (type) {
|
||||
case Button::Url: iconWidth = st::msgBotKbUrlIcon.pxWidth(); break;
|
||||
//case Button::RequestPhone: iconWidth = st::msgBotKbRequestPhoneIcon.pxWidth(); break;
|
||||
//case Button::RequestLocation: iconWidth = st::msgBotKbRequestLocationIcon.pxWidth(); break;
|
||||
case Button::SwitchInlineSame:
|
||||
case Button::SwitchInline: iconWidth = st::msgBotKbSwitchPmIcon.pxWidth(); break;
|
||||
case Button::Callback: iconWidth = st::msgInvSendingImg.pxWidth(); break;
|
||||
case Button::Type::Url: iconWidth = st::msgBotKbUrlIcon.pxWidth(); break;
|
||||
//case Button::Type::RequestPhone: iconWidth = st::msgBotKbRequestPhoneIcon.pxWidth(); break;
|
||||
//case Button::Type::RequestLocation: iconWidth = st::msgBotKbRequestLocationIcon.pxWidth(); break;
|
||||
case Button::Type::SwitchInlineSame:
|
||||
case Button::Type::SwitchInline: iconWidth = st::msgBotKbSwitchPmIcon.pxWidth(); break;
|
||||
case Button::Type::Callback:
|
||||
case Button::Type::Game: iconWidth = st::msgInvSendingImg.pxWidth(); break;
|
||||
}
|
||||
if (iconWidth > 0) {
|
||||
result = std::max(result, 2 * iconWidth + 4 * int(st::msgBotKbIconPadding));
|
||||
|
@ -7871,23 +7878,25 @@ HistoryMessage::~HistoryMessage() {
|
|||
}
|
||||
|
||||
void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
QList<ClickHandlerPtr> links;
|
||||
LangString text = lang(lng_message_empty);
|
||||
QString from = textcmdLink(1, _from->name);
|
||||
auto text = lang(lng_message_empty);
|
||||
auto from = textcmdLink(1, _from->name);
|
||||
|
||||
Links links;
|
||||
links.push_back(MakeShared<PeerOpenClickHandler>(_from));
|
||||
|
||||
switch (action.type()) {
|
||||
case mtpc_messageActionChatAddUser: {
|
||||
const auto &d(action.c_messageActionChatAddUser());
|
||||
const auto &v(d.vusers.c_vector().v);
|
||||
auto &d = action.c_messageActionChatAddUser();
|
||||
auto &v = d.vusers.c_vector().v;
|
||||
bool foundSelf = false;
|
||||
for (int32 i = 0, l = v.size(); i < l; ++i) {
|
||||
for (int i = 0, l = v.size(); i < l; ++i) {
|
||||
if (v.at(i).v == MTP::authedId()) {
|
||||
foundSelf = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (v.size() == 1) {
|
||||
UserData *u = App::user(peerFromUser(v.at(0)));
|
||||
auto u = App::user(peerFromUser(v.at(0)));
|
||||
if (u == _from) {
|
||||
text = lng_action_user_joined(lt_from, from);
|
||||
} else {
|
||||
|
@ -7897,9 +7906,9 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
|||
} else if (v.isEmpty()) {
|
||||
text = lng_action_add_user(lt_from, from, lt_user, "somebody");
|
||||
} else {
|
||||
for (int32 i = 0, l = v.size(); i < l; ++i) {
|
||||
UserData *u = App::user(peerFromUser(v.at(i)));
|
||||
QString linkText = textcmdLink(i + 2, u->name);
|
||||
for (int i = 0, l = v.size(); i < l; ++i) {
|
||||
auto u = App::user(peerFromUser(v.at(i)));
|
||||
auto linkText = textcmdLink(i + 2, u->name);
|
||||
if (i == 0) {
|
||||
text = linkText;
|
||||
} else if (i + 1 < l) {
|
||||
|
@ -7919,7 +7928,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
|||
} break;
|
||||
|
||||
case mtpc_messageActionChatJoinedByLink: {
|
||||
const auto &d(action.c_messageActionChatJoinedByLink());
|
||||
auto &d = action.c_messageActionChatJoinedByLink();
|
||||
//if (true || peerFromUser(d.vinviter_id) == _from->id) {
|
||||
text = lng_action_user_joined_by_link(lt_from, from);
|
||||
//} else {
|
||||
|
@ -7933,12 +7942,12 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
|||
} break;
|
||||
|
||||
case mtpc_messageActionChatCreate: {
|
||||
const auto &d(action.c_messageActionChatCreate());
|
||||
auto &d = action.c_messageActionChatCreate();
|
||||
text = lng_action_created_chat(lt_from, from, lt_title, textClean(qs(d.vtitle)));
|
||||
} break;
|
||||
|
||||
case mtpc_messageActionChannelCreate: {
|
||||
const auto &d(action.c_messageActionChannelCreate());
|
||||
auto &d = action.c_messageActionChannelCreate();
|
||||
if (isPost()) {
|
||||
text = lng_action_created_channel(lt_title, textClean(qs(d.vtitle)));
|
||||
} else {
|
||||
|
@ -7955,18 +7964,18 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
|||
} break;
|
||||
|
||||
case mtpc_messageActionChatDeleteUser: {
|
||||
const auto &d(action.c_messageActionChatDeleteUser());
|
||||
auto &d = action.c_messageActionChatDeleteUser();
|
||||
if (peerFromUser(d.vuser_id) == _from->id) {
|
||||
text = lng_action_user_left(lt_from, from);
|
||||
} else {
|
||||
UserData *u = App::user(peerFromUser(d.vuser_id));
|
||||
auto u = App::user(peerFromUser(d.vuser_id));
|
||||
links.push_back(MakeShared<PeerOpenClickHandler>(u));
|
||||
text = lng_action_kick_user(lt_from, from, lt_user, textcmdLink(2, u->name));
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_messageActionChatEditPhoto: {
|
||||
const auto &d(action.c_messageActionChatEditPhoto());
|
||||
auto &d = action.c_messageActionChatEditPhoto();
|
||||
if (d.vphoto.type() == mtpc_photo) {
|
||||
_media.reset(new HistoryPhoto(this, history()->peer, d.vphoto.c_photo(), st::msgServicePhotoWidth));
|
||||
}
|
||||
|
@ -7974,13 +7983,13 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
|||
} break;
|
||||
|
||||
case mtpc_messageActionChatEditTitle: {
|
||||
const auto &d(action.c_messageActionChatEditTitle());
|
||||
auto &d = action.c_messageActionChatEditTitle();
|
||||
text = isPost() ? lng_action_changed_title_channel(lt_title, textClean(qs(d.vtitle))) : lng_action_changed_title(lt_from, from, lt_title, textClean(qs(d.vtitle)));
|
||||
} break;
|
||||
|
||||
case mtpc_messageActionChatMigrateTo: {
|
||||
_flags |= MTPDmessage_ClientFlag::f_is_group_migrate;
|
||||
const auto &d(action.c_messageActionChatMigrateTo());
|
||||
auto &d = action.c_messageActionChatMigrateTo();
|
||||
if (true/*PeerData *channel = App::channelLoaded(d.vchannel_id.v)*/) {
|
||||
text = lang(lng_action_group_migrate);
|
||||
} else {
|
||||
|
@ -7990,7 +7999,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
|||
|
||||
case mtpc_messageActionChannelMigrateFrom: {
|
||||
_flags |= MTPDmessage_ClientFlag::f_is_group_migrate;
|
||||
const auto &d(action.c_messageActionChannelMigrateFrom());
|
||||
auto &d = action.c_messageActionChannelMigrateFrom();
|
||||
if (true/*PeerData *chat = App::chatLoaded(d.vchat_id.v)*/) {
|
||||
text = lang(lng_action_group_migrate);
|
||||
} else {
|
||||
|
@ -7999,74 +8008,63 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
|||
} break;
|
||||
|
||||
case mtpc_messageActionPinMessage: {
|
||||
if (updatePinnedText(&from, &text)) {
|
||||
auto pinned = Get<HistoryServicePinned>();
|
||||
t_assert(pinned != nullptr);
|
||||
preparePinnedText(from, &text, &links);
|
||||
} break;
|
||||
|
||||
links.push_back(pinned->lnk);
|
||||
}
|
||||
case mtpc_messageActionGameScore: {
|
||||
prepareGameScoreText(from, &text, &links);
|
||||
} break;
|
||||
|
||||
default: from = QString(); break;
|
||||
}
|
||||
|
||||
textstyleSet(&st::serviceTextStyle);
|
||||
_text.setText(st::msgServiceFont, text, _historySrvOptions);
|
||||
textstyleRestore();
|
||||
if (!from.isEmpty()) {
|
||||
_text.setLink(1, MakeShared<PeerOpenClickHandler>(_from));
|
||||
}
|
||||
for (int32 i = 0, l = links.size(); i < l; ++i) {
|
||||
_text.setLink(i + 2, links.at(i));
|
||||
setServiceText(text, links);
|
||||
for (int i = 0, count = links.size(); i != count; ++i) {
|
||||
_text.setLink(1 + i, links.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
bool HistoryService::updatePinned(bool force) {
|
||||
auto pinned = Get<HistoryServicePinned>();
|
||||
t_assert(pinned != nullptr);
|
||||
bool HistoryService::updateDependent(bool force) {
|
||||
auto dependent = GetDependentData();
|
||||
t_assert(dependent != nullptr);
|
||||
|
||||
if (!force) {
|
||||
if (!pinned->msgId || pinned->msg) {
|
||||
if (!dependent->msgId || dependent->msg) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pinned->lnk) {
|
||||
pinned->lnk.reset(new GoToMessageClickHandler(history()->peer->id, pinned->msgId));
|
||||
if (!dependent->lnk) {
|
||||
dependent->lnk.reset(new GoToMessageClickHandler(history()->peer->id, dependent->msgId));
|
||||
}
|
||||
bool gotDependencyItem = false;
|
||||
if (!pinned->msg) {
|
||||
pinned->msg = App::histItemById(channelId(), pinned->msgId);
|
||||
if (pinned->msg) {
|
||||
App::historyRegDependency(this, pinned->msg);
|
||||
if (!dependent->msg) {
|
||||
dependent->msg = App::histItemById(channelId(), dependent->msgId);
|
||||
if (dependent->msg) {
|
||||
App::historyRegDependency(this, dependent->msg);
|
||||
gotDependencyItem = true;
|
||||
}
|
||||
}
|
||||
if (pinned->msg) {
|
||||
updatePinnedText();
|
||||
if (dependent->msg) {
|
||||
updateDependentText();
|
||||
} else if (force) {
|
||||
if (pinned->msgId > 0) {
|
||||
pinned->msgId = 0;
|
||||
if (dependent->msgId > 0) {
|
||||
dependent->msgId = 0;
|
||||
gotDependencyItem = true;
|
||||
}
|
||||
updatePinnedText();
|
||||
updateDependentText();
|
||||
}
|
||||
if (force) {
|
||||
if (gotDependencyItem && App::wnd()) {
|
||||
App::wnd()->notifySettingGot();
|
||||
}
|
||||
}
|
||||
return (pinned->msg || !pinned->msgId);
|
||||
return (dependent->msg || !dependent->msgId);
|
||||
}
|
||||
|
||||
bool HistoryService::updatePinnedText(const QString *pfrom, QString *ptext) {
|
||||
bool HistoryService::preparePinnedText(const QString &from, QString *outText, Links *outLinks) {
|
||||
bool result = false;
|
||||
QString from, text;
|
||||
if (pfrom) {
|
||||
from = *pfrom;
|
||||
} else {
|
||||
from = textcmdLink(1, _from->name);
|
||||
}
|
||||
QString text;
|
||||
|
||||
ClickHandlerPtr second;
|
||||
auto pinned = Get<HistoryServicePinned>();
|
||||
|
@ -8112,21 +8110,47 @@ bool HistoryService::updatePinnedText(const QString *pfrom, QString *ptext) {
|
|||
} else {
|
||||
text = lng_action_pinned_media(lt_from, from, lt_media, lang(lng_deleted_message));
|
||||
}
|
||||
if (ptext) {
|
||||
*ptext = text;
|
||||
*outText = text;
|
||||
if (second) {
|
||||
outLinks->push_back(second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool HistoryService::prepareGameScoreText(const QString &from, QString *outText, Links *outLinks) {
|
||||
bool result = false;
|
||||
QString text;
|
||||
|
||||
ClickHandlerPtr second;
|
||||
auto gamescore = Get<HistoryServiceGameScore>();
|
||||
if (gamescore && gamescore->msg) {
|
||||
auto getGameTitle = [item = gamescore->msg, &second]() -> QString {
|
||||
if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
|
||||
for (int i = 0, rowsCount = markup->rows.size(); i != rowsCount; ++i) {
|
||||
auto &row = markup->rows[i];
|
||||
for (int j = 0, buttonsCount = row.size(); j != buttonsCount; ++j) {
|
||||
auto &button = row[j];
|
||||
if (button.type == HistoryMessageReplyMarkup::Button::Type::Game) {
|
||||
auto strData = QString::fromUtf8(button.data);
|
||||
second = MakeShared<ReplyMarkupClickHandler>(item, i, j);
|
||||
return textcmdLink(2, strData.mid(strData.indexOf(',') + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return lang(lng_deleted_message);
|
||||
};
|
||||
text = lng_action_game_score(lt_from, from, lt_score, QString::number(gamescore->score), lt_game, getGameTitle());
|
||||
result = true;
|
||||
} else if (gamescore && gamescore->msgId) {
|
||||
text = lng_action_game_score(lt_from, from, lt_score, QString::number(gamescore->score), lt_game, lang(lng_contacts_loading));
|
||||
result = true;
|
||||
} else {
|
||||
setServiceText(text);
|
||||
_text.setLink(1, MakeShared<PeerOpenClickHandler>(_from));
|
||||
if (second) {
|
||||
_text.setLink(2, second);
|
||||
}
|
||||
if (history()->textCachedFor == this) {
|
||||
history()->textCachedFor = 0;
|
||||
}
|
||||
if (App::main()) {
|
||||
App::main()->dlgUpdated(history(), id);
|
||||
}
|
||||
App::historyUpdateDependent(this);
|
||||
text = lng_action_game_score(lt_from, from, lt_score, QString::number(gamescore->score), lt_game, lang(lng_deleted_message));
|
||||
}
|
||||
*outText = text;
|
||||
if (second) {
|
||||
outLinks->push_back(second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -8134,10 +8158,17 @@ bool HistoryService::updatePinnedText(const QString *pfrom, QString *ptext) {
|
|||
HistoryService::HistoryService(History *history, const MTPDmessageService &msg) :
|
||||
HistoryItem(history, msg.vid.v, mtpCastFlags(msg.vflags.v), ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) {
|
||||
if (msg.has_reply_to_msg_id()) {
|
||||
UpdateComponents(HistoryServicePinned::Bit());
|
||||
MsgId pinnedMsgId = Get<HistoryServicePinned>()->msgId = msg.vreply_to_msg_id.v;
|
||||
if (!updatePinned() && App::api()) {
|
||||
App::api()->requestMessageData(history->peer->asChannel(), pinnedMsgId, std_::make_unique<HistoryDependentItemCallback>(fullId()));
|
||||
if (msg.vaction.type() == mtpc_messageActionPinMessage) {
|
||||
UpdateComponents(HistoryServicePinned::Bit());
|
||||
} else if (msg.vaction.type() == mtpc_messageActionGameScore) {
|
||||
UpdateComponents(HistoryServiceGameScore::Bit());
|
||||
Get<HistoryServiceGameScore>()->score = msg.vaction.c_messageActionGameScore().vscore.v;
|
||||
}
|
||||
if (auto dependent = GetDependentData()) {
|
||||
dependent->msgId = msg.vreply_to_msg_id.v;
|
||||
if (!updateDependent() && App::api()) {
|
||||
App::api()->requestMessageData(history->peer->asChannel(), dependent->msgId, std_::make_unique<HistoryDependentItemCallback>(fullId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
setMessageByAction(msg.vaction);
|
||||
|
@ -8145,7 +8176,7 @@ HistoryService::HistoryService(History *history, const MTPDmessageService &msg)
|
|||
|
||||
HistoryService::HistoryService(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags, int32 from) :
|
||||
HistoryItem(history, msgId, flags, date, from) {
|
||||
_text.setText(st::msgServiceFont, msg, _historySrvOptions);
|
||||
setServiceText(msg, Links());
|
||||
}
|
||||
|
||||
void HistoryService::initDimensions() {
|
||||
|
@ -8154,6 +8185,13 @@ void HistoryService::initDimensions() {
|
|||
if (_media) _media->initDimensions();
|
||||
}
|
||||
|
||||
bool HistoryService::updateDependencyItem() {
|
||||
if (GetDependentData()) {
|
||||
return updateDependent(true);
|
||||
}
|
||||
return HistoryItem::updateDependencyItem();
|
||||
}
|
||||
|
||||
void HistoryService::countPositionAndSize(int32 &left, int32 &width) const {
|
||||
left = st::msgServiceMargin.left();
|
||||
int32 maxwidth = _history->width;
|
||||
|
@ -8176,10 +8214,14 @@ QString HistoryService::inReplyText() const {
|
|||
return result.trimmed().startsWith(author()->name) ? result.trimmed().mid(author()->name.size()).trimmed() : result;
|
||||
}
|
||||
|
||||
void HistoryService::setServiceText(const QString &text) {
|
||||
void HistoryService::setServiceText(const QString &text, const Links &links) {
|
||||
textstyleSet(&st::serviceTextStyle);
|
||||
_text.setText(st::msgServiceFont, text, _historySrvOptions);
|
||||
textstyleRestore();
|
||||
for (int i = 0, count = links.size(); i != count; ++i) {
|
||||
_text.setLink(1 + i, links.at(i));
|
||||
}
|
||||
|
||||
setPendingInitDimensions();
|
||||
_textWidth = -1;
|
||||
_textHeight = 0;
|
||||
|
@ -8296,13 +8338,19 @@ HistoryTextState HistoryService::getState(int x, int y, HistoryStateRequest requ
|
|||
if (_media) {
|
||||
height -= st::msgServiceMargin.top() + _media->height();
|
||||
}
|
||||
QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding));
|
||||
auto outer = QRect(left, st::msgServiceMargin.top(), width, height);
|
||||
auto trect = outer.marginsAdded(-st::msgServicePadding);
|
||||
if (trect.contains(x, y)) {
|
||||
textstyleSet(&st::serviceTextStyle);
|
||||
auto textRequest = request.forText();
|
||||
textRequest.align = style::al_center;
|
||||
result = _text.getState(x - trect.x(), y - trect.y(), trect.width(), textRequest);
|
||||
textstyleRestore();
|
||||
if (auto gamescore = Get<HistoryServiceGameScore>()) {
|
||||
if (!result.link && outer.contains(x, y)) {
|
||||
result.link = gamescore->lnk;
|
||||
}
|
||||
}
|
||||
} else if (_media) {
|
||||
result = _media->getState(x - st::msgServiceMargin.left() - (width - _media->maxWidth()) / 2, y - st::msgServiceMargin.top() - height - st::msgServiceMargin.top(), request);
|
||||
}
|
||||
|
@ -8311,9 +8359,12 @@ HistoryTextState HistoryService::getState(int x, int y, HistoryStateRequest requ
|
|||
|
||||
void HistoryService::applyEditionToEmpty() {
|
||||
TextWithEntities textWithEntities = { QString(), EntitiesInText() };
|
||||
setServiceText(QString());
|
||||
setServiceText(QString(), Links());
|
||||
removeMedia();
|
||||
|
||||
clearDependency();
|
||||
UpdateComponents(0);
|
||||
|
||||
finishEditionToEmpty();
|
||||
}
|
||||
|
||||
|
@ -8352,25 +8403,58 @@ void HistoryService::eraseFromOverview() {
|
|||
}
|
||||
}
|
||||
|
||||
HistoryService::~HistoryService() {
|
||||
if (auto pinned = Get<HistoryServicePinned>()) {
|
||||
if (pinned->msg) {
|
||||
App::historyUnregDependency(this, pinned->msg);
|
||||
bool HistoryService::updateDependentText() {
|
||||
auto result = false;
|
||||
auto from = textcmdLink(1, _from->name);
|
||||
QString text;
|
||||
Links links;
|
||||
links.push_back(MakeShared<PeerOpenClickHandler>(_from));
|
||||
if (Has<HistoryServicePinned>()) {
|
||||
result = preparePinnedText(from, &text, &links);
|
||||
} else if (Has<HistoryServiceGameScore>()) {
|
||||
result = prepareGameScoreText(from, &text, &links);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
|
||||
setServiceText(text, links);
|
||||
if (history()->textCachedFor == this) {
|
||||
history()->textCachedFor = 0;
|
||||
}
|
||||
if (App::main()) {
|
||||
App::main()->dlgUpdated(history(), id);
|
||||
}
|
||||
App::historyUpdateDependent(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
void HistoryService::clearDependency() {
|
||||
if (auto dependent = GetDependentData()) {
|
||||
if (dependent->msg) {
|
||||
App::historyUnregDependency(this, dependent->msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HistoryService::~HistoryService() {
|
||||
clearDependency();
|
||||
_media.clear();
|
||||
}
|
||||
|
||||
HistoryJoined::HistoryJoined(History *history, const QDateTime &inviteDate, UserData *inviter, MTPDmessage::Flags flags)
|
||||
: HistoryService(history, clientMsgId(), inviteDate, QString(), flags) {
|
||||
textstyleSet(&st::serviceTextStyle);
|
||||
if (peerToUser(inviter->id) == MTP::authedId()) {
|
||||
_text.setText(st::msgServiceFont, lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined), _historySrvOptions);
|
||||
} else {
|
||||
_text.setText(st::msgServiceFont, history->isMegagroup() ? lng_action_add_you_group(lt_from, textcmdLink(1, inviter->name)) : lng_action_add_you(lt_from, textcmdLink(1, inviter->name)), _historySrvOptions);
|
||||
_text.setLink(1, MakeShared<PeerOpenClickHandler>(inviter));
|
||||
}
|
||||
textstyleRestore();
|
||||
Links links;
|
||||
auto text = ([history, inviter, &links]() {
|
||||
if (peerToUser(inviter->id) == MTP::authedId()) {
|
||||
return lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined);
|
||||
}
|
||||
links.push_back(MakeShared<PeerOpenClickHandler>(inviter));
|
||||
if (history->isMegagroup()) {
|
||||
return lng_action_add_you_group(lt_from, textcmdLink(1, inviter->name));
|
||||
}
|
||||
return lng_action_add_you(lt_from, textcmdLink(1, inviter->name));
|
||||
})();
|
||||
setServiceText(text, links);
|
||||
}
|
||||
|
||||
void GoToMessageClickHandler::onClickImpl() const {
|
||||
|
|
|
@ -813,7 +813,7 @@ struct HistoryMessageReplyMarkup : public BaseComponent<HistoryMessageReplyMarku
|
|||
void create(const MTPReplyMarkup &markup);
|
||||
|
||||
struct Button {
|
||||
enum Type {
|
||||
enum class Type {
|
||||
Default,
|
||||
Url,
|
||||
Callback,
|
||||
|
@ -821,6 +821,7 @@ struct HistoryMessageReplyMarkup : public BaseComponent<HistoryMessageReplyMarku
|
|||
RequestLocation,
|
||||
SwitchInline,
|
||||
SwitchInlineSame,
|
||||
Game,
|
||||
};
|
||||
Type type;
|
||||
QString text;
|
||||
|
@ -2757,12 +2758,19 @@ inline MTPDmessage::Flags newMessageFlags(PeerData *p) {
|
|||
return result;
|
||||
}
|
||||
|
||||
struct HistoryServicePinned : public BaseComponent<HistoryServicePinned> {
|
||||
struct HistoryServiceDependentData {
|
||||
MsgId msgId = 0;
|
||||
HistoryItem *msg = nullptr;
|
||||
ClickHandlerPtr lnk;
|
||||
};
|
||||
|
||||
struct HistoryServicePinned : public BaseComponent<HistoryServicePinned>, public HistoryServiceDependentData {
|
||||
};
|
||||
|
||||
struct HistoryServiceGameScore : public BaseComponent<HistoryServiceGameScore>, public HistoryServiceDependentData {
|
||||
int score = 0;
|
||||
};
|
||||
|
||||
namespace HistoryLayout {
|
||||
class ServiceMessagePainter;
|
||||
} // namespace HistoryLayout
|
||||
|
@ -2776,18 +2784,16 @@ public:
|
|||
return _create(history, msgId, date, msg, flags, from);
|
||||
}
|
||||
|
||||
bool updateDependencyItem() override {
|
||||
return updatePinned(true);
|
||||
}
|
||||
bool updateDependencyItem() override;
|
||||
MsgId dependencyMsgId() const override {
|
||||
if (const HistoryServicePinned *pinned = Get<HistoryServicePinned>()) {
|
||||
return pinned->msgId;
|
||||
if (auto dependent = GetDependentData()) {
|
||||
return dependent->msgId;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
bool notificationReady() const override {
|
||||
if (const HistoryServicePinned *pinned = Get<HistoryServicePinned>()) {
|
||||
return (pinned->msg || !pinned->msgId);
|
||||
if (auto dependent = GetDependentData()) {
|
||||
return (dependent->msg || !dependent->msgId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -2826,8 +2832,6 @@ public:
|
|||
QString inDialogsText() const override;
|
||||
QString inReplyText() const override;
|
||||
|
||||
void setServiceText(const QString &text);
|
||||
|
||||
~HistoryService();
|
||||
|
||||
protected:
|
||||
|
@ -2840,11 +2844,31 @@ protected:
|
|||
void initDimensions() override;
|
||||
int resizeGetHeight_(int width) override;
|
||||
|
||||
using Links = QList<ClickHandlerPtr>;
|
||||
void setServiceText(const QString &text, const Links &links);
|
||||
|
||||
void removeMedia();
|
||||
|
||||
private:
|
||||
HistoryServiceDependentData *GetDependentData() {
|
||||
if (auto pinned = Get<HistoryServicePinned>()) {
|
||||
return pinned;
|
||||
} else if (auto gamescore = Get<HistoryServiceGameScore>()) {
|
||||
return gamescore;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
const HistoryServiceDependentData *GetDependentData() const {
|
||||
return const_cast<HistoryService*>(this)->GetDependentData();
|
||||
}
|
||||
bool updateDependent(bool force = false);
|
||||
bool updateDependentText();
|
||||
void clearDependency();
|
||||
|
||||
void setMessageByAction(const MTPmessageAction &action);
|
||||
bool updatePinned(bool force = false);
|
||||
bool updatePinnedText(const QString *pfrom = nullptr, QString *ptext = nullptr);
|
||||
|
||||
bool preparePinnedText(const QString &from, QString *outText, Links *outLinks);
|
||||
bool prepareGameScoreText(const QString &from, QString *outText, Links *outLinks);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "styles/style_dialogs.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "boxes/photosendbox.h"
|
||||
#include "boxes/sharebox.h"
|
||||
#include "ui/filedialog.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/buttons/history_down_button.h"
|
||||
|
@ -34,8 +35,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "history/history_service_layout.h"
|
||||
#include "profile/profile_members_widget.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "stickers/emoji_pan.h"
|
||||
#include "lang.h"
|
||||
#include "application.h"
|
||||
#include "dropdown.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "passcodewidget.h"
|
||||
|
@ -3054,11 +3057,11 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
|||
connect(&_field, SIGNAL(linksChanged()), this, SLOT(onPreviewCheck()));
|
||||
connect(App::wnd()->windowHandle(), SIGNAL(visibleChanged(bool)), this, SLOT(onWindowVisibleChanged()));
|
||||
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
|
||||
connect(&_emojiPan, SIGNAL(emojiSelected(EmojiPtr)), &_field, SLOT(onEmojiInsert(EmojiPtr)));
|
||||
connect(&_emojiPan, SIGNAL(stickerSelected(DocumentData*)), this, SLOT(onStickerSend(DocumentData*)));
|
||||
connect(&_emojiPan, SIGNAL(photoSelected(PhotoData*)), this, SLOT(onPhotoSend(PhotoData*)));
|
||||
connect(&_emojiPan, SIGNAL(inlineResultSelected(InlineBots::Result*,UserData*)), this, SLOT(onInlineResultSend(InlineBots::Result*,UserData*)));
|
||||
connect(&_emojiPan, SIGNAL(updateStickers()), this, SLOT(updateStickers()));
|
||||
connect(_emojiPan, SIGNAL(emojiSelected(EmojiPtr)), &_field, SLOT(onEmojiInsert(EmojiPtr)));
|
||||
connect(_emojiPan, SIGNAL(stickerSelected(DocumentData*)), this, SLOT(onStickerSend(DocumentData*)));
|
||||
connect(_emojiPan, SIGNAL(photoSelected(PhotoData*)), this, SLOT(onPhotoSend(PhotoData*)));
|
||||
connect(_emojiPan, SIGNAL(inlineResultSelected(InlineBots::Result*,UserData*)), this, SLOT(onInlineResultSend(InlineBots::Result*,UserData*)));
|
||||
connect(_emojiPan, SIGNAL(updateStickers()), this, SLOT(updateStickers()));
|
||||
connect(&_sendActionStopTimer, SIGNAL(timeout()), this, SLOT(onCancelSendAction()));
|
||||
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreviewTimeout()));
|
||||
if (audioCapture()) {
|
||||
|
@ -3129,25 +3132,25 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
|||
_silent.hide();
|
||||
_cmdStart.hide();
|
||||
|
||||
_attachDocument.installEventFilter(&_attachType);
|
||||
_attachPhoto.installEventFilter(&_attachType);
|
||||
_attachEmoji.installEventFilter(&_emojiPan);
|
||||
_attachDocument.installEventFilter(_attachType);
|
||||
_attachPhoto.installEventFilter(_attachType);
|
||||
_attachEmoji.installEventFilter(_emojiPan);
|
||||
|
||||
connect(&_kbShow, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
||||
connect(&_kbHide, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
||||
connect(&_cmdStart, SIGNAL(clicked()), this, SLOT(onCmdStart()));
|
||||
|
||||
connect(_attachType.addButton(new IconedButton(this, st::dropdownAttachDocument, lang(lng_attach_file))), SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
|
||||
connect(_attachType.addButton(new IconedButton(this, st::dropdownAttachPhoto, lang(lng_attach_photo))), SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
|
||||
_attachType.hide();
|
||||
_emojiPan.hide();
|
||||
_attachDragDocument.hide();
|
||||
_attachDragPhoto.hide();
|
||||
connect(_attachType->addButton(new IconedButton(this, st::dropdownAttachDocument, lang(lng_attach_file))), SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
|
||||
connect(_attachType->addButton(new IconedButton(this, st::dropdownAttachPhoto, lang(lng_attach_photo))), SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
|
||||
_attachType->hide();
|
||||
_emojiPan->hide();
|
||||
_attachDragDocument->hide();
|
||||
_attachDragPhoto->hide();
|
||||
|
||||
_topShadow.hide();
|
||||
|
||||
connect(&_attachDragDocument, SIGNAL(dropped(const QMimeData*)), this, SLOT(onDocumentDrop(const QMimeData*)));
|
||||
connect(&_attachDragPhoto, SIGNAL(dropped(const QMimeData*)), this, SLOT(onPhotoDrop(const QMimeData*)));
|
||||
connect(_attachDragDocument, SIGNAL(dropped(const QMimeData*)), this, SLOT(onDocumentDrop(const QMimeData*)));
|
||||
connect(_attachDragPhoto, SIGNAL(dropped(const QMimeData*)), this, SLOT(onPhotoDrop(const QMimeData*)));
|
||||
|
||||
connect(&_updateEditTimeLeftDisplay, SIGNAL(timeout()), this, SLOT(updateField()));
|
||||
|
||||
|
@ -3156,7 +3159,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
|||
|
||||
void HistoryWidget::start() {
|
||||
connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated()));
|
||||
connect(App::main(), SIGNAL(savedGifsUpdated()), &_emojiPan, SLOT(refreshSavedGifs()));
|
||||
connect(App::main(), SIGNAL(savedGifsUpdated()), _emojiPan, SLOT(refreshSavedGifs()));
|
||||
|
||||
updateRecentStickers();
|
||||
if (App::main()) emit App::main()->savedGifsUpdated();
|
||||
|
@ -3165,7 +3168,7 @@ void HistoryWidget::start() {
|
|||
}
|
||||
|
||||
void HistoryWidget::onStickersUpdated() {
|
||||
_emojiPan.refreshStickers();
|
||||
_emojiPan->refreshStickers();
|
||||
updateStickersByEmoji();
|
||||
}
|
||||
|
||||
|
@ -3227,9 +3230,9 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) {
|
|||
inlineBotChanged();
|
||||
}
|
||||
if (_inlineBot->username == cInlineGifBotUsername() && query.isEmpty()) {
|
||||
_emojiPan.clearInlineBot();
|
||||
_emojiPan->clearInlineBot();
|
||||
} else {
|
||||
_emojiPan.queryInlineBot(_inlineBot, _peer, query);
|
||||
_emojiPan->queryInlineBot(_inlineBot, _peer, query);
|
||||
}
|
||||
if (!_fieldAutocomplete->isHidden()) {
|
||||
_fieldAutocomplete->hideStart();
|
||||
|
@ -3449,11 +3452,11 @@ void HistoryWidget::updateSendAction(History *history, SendActionType type, int3
|
|||
}
|
||||
|
||||
void HistoryWidget::updateRecentStickers() {
|
||||
_emojiPan.refreshStickers();
|
||||
_emojiPan->refreshStickers();
|
||||
}
|
||||
|
||||
void HistoryWidget::stickersInstalled(uint64 setId) {
|
||||
_emojiPan.stickersInstalled(setId);
|
||||
_emojiPan->stickersInstalled(setId);
|
||||
}
|
||||
|
||||
void HistoryWidget::sendActionDone(const MTPBool &result, mtpRequestId req) {
|
||||
|
@ -3527,7 +3530,8 @@ void HistoryWidget::updateStickers() {
|
|||
}
|
||||
if (!Global::LastRecentStickersUpdate() || now >= Global::LastRecentStickersUpdate() + StickersUpdateTimeout) {
|
||||
if (!_recentStickersUpdateRequest) {
|
||||
_recentStickersUpdateRequest = MTP::send(MTPmessages_GetRecentStickers(MTP_int(Local::countRecentStickersHash())), rpcDone(&HistoryWidget::recentStickersGot), rpcFail(&HistoryWidget::recentStickersFailed));
|
||||
MTPmessages_GetRecentStickers::Flags flags = 0;
|
||||
_recentStickersUpdateRequest = MTP::send(MTPmessages_GetRecentStickers(MTP_flags(flags), MTP_int(Local::countRecentStickersHash())), rpcDone(&HistoryWidget::recentStickersGot), rpcFail(&HistoryWidget::recentStickersFailed));
|
||||
}
|
||||
}
|
||||
if (!Global::LastFeaturedStickersUpdate() || now >= Global::LastFeaturedStickersUpdate() + StickersUpdateTimeout) {
|
||||
|
@ -3833,14 +3837,14 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic
|
|||
_featuredStickersUpdateRequest = 0;
|
||||
|
||||
if (stickers.type() != mtpc_messages_featuredStickers) return;
|
||||
auto &d(stickers.c_messages_featuredStickers());
|
||||
auto &d = stickers.c_messages_featuredStickers();
|
||||
|
||||
OrderedSet<uint64> unread;
|
||||
for_const (auto &unreadSetId, d.vunread.c_vector().v) {
|
||||
unread.insert(unreadSetId.v);
|
||||
}
|
||||
|
||||
auto &d_sets(d.vsets.c_vector().v);
|
||||
auto &d_sets = d.vsets.c_vector().v;
|
||||
|
||||
auto &setsOrder = Global::RefFeaturedStickerSetsOrder();
|
||||
setsOrder.clear();
|
||||
|
@ -3851,37 +3855,53 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic
|
|||
set.flags &= ~MTPDstickerSet_ClientFlag::f_featured; // mark for removing
|
||||
}
|
||||
for (int i = 0, l = d_sets.size(); i != l; ++i) {
|
||||
if (d_sets.at(i).type() == mtpc_stickerSetCovered && d_sets.at(i).c_stickerSetCovered().vset.type() == mtpc_stickerSet) {
|
||||
const auto &set(d_sets.at(i).c_stickerSetCovered().vset.c_stickerSet());
|
||||
auto it = sets.find(set.vid.v);
|
||||
QString title = stickerSetTitle(set);
|
||||
auto &setData = d_sets[i];
|
||||
const MTPDstickerSet *set = nullptr;
|
||||
switch (setData.type()) {
|
||||
case mtpc_stickerSetCovered: {
|
||||
auto &d = setData.c_stickerSetCovered();
|
||||
if (d.vset.type() == mtpc_stickerSet) {
|
||||
set = &d.vset.c_stickerSet();
|
||||
}
|
||||
} break;
|
||||
case mtpc_stickerSetMultiCovered: {
|
||||
auto &d = setData.c_stickerSetMultiCovered();
|
||||
if (d.vset.type() == mtpc_stickerSet) {
|
||||
set = &d.vset.c_stickerSet();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
if (set) {
|
||||
auto it = sets.find(set->vid.v);
|
||||
QString title = stickerSetTitle(*set);
|
||||
if (it == sets.cend()) {
|
||||
auto setClientFlags = MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded;
|
||||
if (unread.contains(set.vid.v)) {
|
||||
if (unread.contains(set->vid.v)) {
|
||||
setClientFlags |= MTPDstickerSet_ClientFlag::f_unread;
|
||||
}
|
||||
it = sets.insert(set.vid.v, Stickers::Set(set.vid.v, set.vaccess_hash.v, title, qs(set.vshort_name), set.vcount.v, set.vhash.v, set.vflags.v | setClientFlags));
|
||||
it = sets.insert(set->vid.v, Stickers::Set(set->vid.v, set->vaccess_hash.v, title, qs(set->vshort_name), set->vcount.v, set->vhash.v, set->vflags.v | setClientFlags));
|
||||
} else {
|
||||
it->access = set.vaccess_hash.v;
|
||||
it->access = set->vaccess_hash.v;
|
||||
it->title = title;
|
||||
it->shortName = qs(set.vshort_name);
|
||||
it->shortName = qs(set->vshort_name);
|
||||
auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_special);
|
||||
it->flags = set.vflags.v | clientFlags;
|
||||
it->flags = set->vflags.v | clientFlags;
|
||||
it->flags |= MTPDstickerSet_ClientFlag::f_featured;
|
||||
if (unread.contains(it->id)) {
|
||||
it->flags |= MTPDstickerSet_ClientFlag::f_unread;
|
||||
} else {
|
||||
it->flags &= ~MTPDstickerSet_ClientFlag::f_unread;
|
||||
}
|
||||
if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) {
|
||||
it->count = set.vcount.v;
|
||||
it->hash = set.vhash.v;
|
||||
if (it->count != set->vcount.v || it->hash != set->vhash.v || it->emoji.isEmpty()) {
|
||||
it->count = set->vcount.v;
|
||||
it->hash = set->vhash.v;
|
||||
it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; // need to request this set
|
||||
}
|
||||
}
|
||||
setsOrder.push_back(set.vid.v);
|
||||
setsOrder.push_back(set->vid.v);
|
||||
if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
|
||||
setsToRequest.insert(set.vid.v, set.vaccess_hash.v);
|
||||
setsToRequest.insert(set->vid.v, set->vaccess_hash.v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4363,11 +4383,11 @@ void HistoryWidget::updateNotifySettings() {
|
|||
}
|
||||
|
||||
bool HistoryWidget::contentOverlapped(const QRect &globalRect) {
|
||||
return (_attachDragDocument.overlaps(globalRect) ||
|
||||
_attachDragPhoto.overlaps(globalRect) ||
|
||||
_attachType.overlaps(globalRect) ||
|
||||
return (_attachDragDocument->overlaps(globalRect) ||
|
||||
_attachDragPhoto->overlaps(globalRect) ||
|
||||
_attachType->overlaps(globalRect) ||
|
||||
_fieldAutocomplete->overlaps(globalRect) ||
|
||||
_emojiPan.overlaps(globalRect));
|
||||
_emojiPan->overlaps(globalRect));
|
||||
}
|
||||
|
||||
void HistoryWidget::updateReportSpamStatus() {
|
||||
|
@ -4499,8 +4519,8 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
_kbShow.hide();
|
||||
_kbHide.hide();
|
||||
_cmdStart.hide();
|
||||
_attachType.hide();
|
||||
_emojiPan.hide();
|
||||
_attachType->hide();
|
||||
_emojiPan->hide();
|
||||
if (_pinnedBar) {
|
||||
_pinnedBar->cancel.hide();
|
||||
_pinnedBar->shadow.hide();
|
||||
|
@ -4562,8 +4582,8 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
_kbShow.hide();
|
||||
_kbHide.hide();
|
||||
_cmdStart.hide();
|
||||
_attachType.hide();
|
||||
_emojiPan.hide();
|
||||
_attachType->hide();
|
||||
_emojiPan->hide();
|
||||
if (!_field.isHidden()) {
|
||||
_field.hide();
|
||||
resizeEvent(0);
|
||||
|
@ -4698,8 +4718,8 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
_kbShow.hide();
|
||||
_kbHide.hide();
|
||||
_cmdStart.hide();
|
||||
_attachType.hide();
|
||||
_emojiPan.hide();
|
||||
_attachType->hide();
|
||||
_emojiPan->hide();
|
||||
_kbScroll.hide();
|
||||
if (!_field.isHidden()) {
|
||||
_field.hide();
|
||||
|
@ -5240,8 +5260,8 @@ void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
|
|||
onDraftSave();
|
||||
|
||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
||||
if (!_attachType.isHidden()) _attachType.hideStart();
|
||||
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
|
||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
||||
|
||||
if (replyTo < 0) cancelReply(lastKeyboardUsed);
|
||||
if (_previewData && _previewData->pendingTill) previewCancel();
|
||||
|
@ -5569,7 +5589,7 @@ void HistoryWidget::onPhotoSelect() {
|
|||
_attachDocument.clearState();
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.show();
|
||||
_attachType.fastHide();
|
||||
_attachType->fastHide();
|
||||
|
||||
if (cDefaultAttach() != dbidaPhoto) {
|
||||
cSetDefaultAttach(dbidaPhoto);
|
||||
|
@ -5597,7 +5617,7 @@ void HistoryWidget::onDocumentSelect() {
|
|||
_attachPhoto.clearState();
|
||||
_attachPhoto.hide();
|
||||
_attachDocument.show();
|
||||
_attachType.fastHide();
|
||||
_attachType->fastHide();
|
||||
|
||||
if (cDefaultAttach() != dbidaDocument) {
|
||||
cSetDefaultAttach(dbidaDocument);
|
||||
|
@ -5634,14 +5654,14 @@ void HistoryWidget::dragEnterEvent(QDragEnterEvent *e) {
|
|||
}
|
||||
|
||||
void HistoryWidget::dragLeaveEvent(QDragLeaveEvent *e) {
|
||||
if (_attachDrag != DragStateNone || !_attachDragPhoto.isHidden() || !_attachDragDocument.isHidden()) {
|
||||
if (_attachDrag != DragStateNone || !_attachDragPhoto->isHidden() || !_attachDragDocument->isHidden()) {
|
||||
_attachDrag = DragStateNone;
|
||||
updateDragAreas();
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::leaveEvent(QEvent *e) {
|
||||
if (_attachDrag != DragStateNone || !_attachDragPhoto.isHidden() || !_attachDragDocument.isHidden()) {
|
||||
if (_attachDrag != DragStateNone || !_attachDragPhoto->isHidden() || !_attachDragDocument->isHidden()) {
|
||||
_attachDrag = DragStateNone;
|
||||
updateDragAreas();
|
||||
}
|
||||
|
@ -5689,7 +5709,7 @@ void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
|
|||
_replyForwardPressed = false;
|
||||
update(0, _field.y() - st::sendPadding - st::replyHeight, width(), st::replyHeight);
|
||||
}
|
||||
if (_attachDrag != DragStateNone || !_attachDragPhoto.isHidden() || !_attachDragDocument.isHidden()) {
|
||||
if (_attachDrag != DragStateNone || !_attachDragPhoto->isHidden() || !_attachDragDocument->isHidden()) {
|
||||
_attachDrag = DragStateNone;
|
||||
updateDragAreas();
|
||||
}
|
||||
|
@ -5763,8 +5783,28 @@ void HistoryWidget::app_sendBotCallback(const HistoryMessageReplyMarkup::Button
|
|||
|
||||
bool lastKeyboardUsed = (_keyboard.forMsgId() == FullMsgId(_channel, _history->lastKeyboardId)) && (_keyboard.forMsgId() == FullMsgId(_channel, msg->id));
|
||||
|
||||
BotCallbackInfo info = { msg->fullId(), row, col };
|
||||
button->requestId = MTP::send(MTPmessages_GetBotCallbackAnswer(_peer->input, MTP_int(msg->id), MTP_bytes(button->data)), rpcDone(&HistoryWidget::botCallbackDone, info), rpcFail(&HistoryWidget::botCallbackFail, info));
|
||||
auto bot = msg->viaBot();
|
||||
if (!bot) {
|
||||
bot = msg->from()->asUser();
|
||||
if (bot && !bot->botInfo) {
|
||||
bot = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
using ButtonType = HistoryMessageReplyMarkup::Button::Type;
|
||||
BotCallbackInfo info = { bot, msg->fullId(), row, col, (button->type == ButtonType::Game) };
|
||||
MTPmessages_GetBotCallbackAnswer::Flags flags = 0;
|
||||
QByteArray sendData;
|
||||
int32 sendGameId = 0;
|
||||
if (info.game) {
|
||||
flags = MTPmessages_GetBotCallbackAnswer::Flag::f_game_id;
|
||||
auto strData = QString::fromUtf8(button->data);
|
||||
sendGameId = strData.midRef(0, strData.indexOf(',')).toInt();
|
||||
} else if (button->type == ButtonType::Callback) {
|
||||
flags = MTPmessages_GetBotCallbackAnswer::Flag::f_data;
|
||||
sendData = button->data;
|
||||
}
|
||||
button->requestId = MTP::send(MTPmessages_GetBotCallbackAnswer(MTP_flags(flags), _peer->input, MTP_int(msg->id), MTP_bytes(sendData), MTP_int(sendGameId)), rpcDone(&HistoryWidget::botCallbackDone, info), rpcFail(&HistoryWidget::botCallbackFail, info));
|
||||
Ui::repaintHistoryItem(msg);
|
||||
|
||||
if (_replyToId == msg->id) {
|
||||
|
@ -5777,7 +5817,7 @@ void HistoryWidget::app_sendBotCallback(const HistoryMessageReplyMarkup::Button
|
|||
}
|
||||
|
||||
void HistoryWidget::botCallbackDone(BotCallbackInfo info, const MTPmessages_BotCallbackAnswer &answer, mtpRequestId req) {
|
||||
if (HistoryItem *item = App::histItemById(info.msgId)) {
|
||||
if (auto item = App::histItemById(info.msgId)) {
|
||||
if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
|
||||
if (info.row < markup->rows.size() && info.col < markup->rows.at(info.row).size()) {
|
||||
if (markup->rows.at(info.row).at(info.col).requestId == req) {
|
||||
|
@ -5788,7 +5828,7 @@ void HistoryWidget::botCallbackDone(BotCallbackInfo info, const MTPmessages_BotC
|
|||
}
|
||||
}
|
||||
if (answer.type() == mtpc_messages_botCallbackAnswer) {
|
||||
const auto &answerData(answer.c_messages_botCallbackAnswer());
|
||||
auto &answerData = answer.c_messages_botCallbackAnswer();
|
||||
if (answerData.has_message()) {
|
||||
if (answerData.is_alert()) {
|
||||
Ui::showLayer(new InformBox(qs(answerData.vmessage)));
|
||||
|
@ -5798,7 +5838,13 @@ void HistoryWidget::botCallbackDone(BotCallbackInfo info, const MTPmessages_BotC
|
|||
Ui::Toast::Show(App::wnd(), toast);
|
||||
}
|
||||
} else if (answerData.has_url()) {
|
||||
UrlClickHandler(qs(answerData.vurl)).onClick(Qt::LeftButton);
|
||||
auto url = qs(answerData.vurl);
|
||||
if (info.game) {
|
||||
url = appendShareGameScoreUrl(url, info.msgId);
|
||||
BotGameUrlClickHandler(info.bot, url).onClick(Qt::LeftButton);
|
||||
} else {
|
||||
UrlClickHandler(url).onClick(Qt::LeftButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5928,24 +5974,24 @@ void HistoryWidget::updateDragAreas() {
|
|||
_field.setAcceptDrops(!_attachDrag);
|
||||
switch (_attachDrag) {
|
||||
case DragStateNone:
|
||||
_attachDragDocument.otherLeave();
|
||||
_attachDragPhoto.otherLeave();
|
||||
_attachDragDocument->otherLeave();
|
||||
_attachDragPhoto->otherLeave();
|
||||
break;
|
||||
case DragStateFiles:
|
||||
_attachDragDocument.otherEnter();
|
||||
_attachDragDocument.setText(lang(lng_drag_files_here), lang(lng_drag_to_send_files));
|
||||
_attachDragPhoto.fastHide();
|
||||
_attachDragDocument->otherEnter();
|
||||
_attachDragDocument->setText(lang(lng_drag_files_here), lang(lng_drag_to_send_files));
|
||||
_attachDragPhoto->fastHide();
|
||||
break;
|
||||
case DragStatePhotoFiles:
|
||||
_attachDragDocument.otherEnter();
|
||||
_attachDragDocument.setText(lang(lng_drag_images_here), lang(lng_drag_to_send_no_compression));
|
||||
_attachDragPhoto.otherEnter();
|
||||
_attachDragPhoto.setText(lang(lng_drag_photos_here), lang(lng_drag_to_send_quick));
|
||||
_attachDragDocument->otherEnter();
|
||||
_attachDragDocument->setText(lang(lng_drag_images_here), lang(lng_drag_to_send_no_compression));
|
||||
_attachDragPhoto->otherEnter();
|
||||
_attachDragPhoto->setText(lang(lng_drag_photos_here), lang(lng_drag_to_send_quick));
|
||||
break;
|
||||
case DragStateImage:
|
||||
_attachDragDocument.fastHide();
|
||||
_attachDragPhoto.otherEnter();
|
||||
_attachDragPhoto.setText(lang(lng_drag_images_here), lang(lng_drag_to_send_quick));
|
||||
_attachDragDocument->fastHide();
|
||||
_attachDragPhoto->otherEnter();
|
||||
_attachDragPhoto->setText(lang(lng_drag_images_here), lang(lng_drag_to_send_quick));
|
||||
break;
|
||||
};
|
||||
resizeEvent(0);
|
||||
|
@ -6427,8 +6473,8 @@ void HistoryWidget::moveFieldControls() {
|
|||
|
||||
right = w;
|
||||
_fieldBarCancel.move(right - _fieldBarCancel.width(), _field.y() - st::sendPadding - _fieldBarCancel.height());
|
||||
_attachType.move(0, _attachDocument.y() - _attachType.height());
|
||||
_emojiPan.moveBottom(_attachEmoji.y());
|
||||
_attachType->move(0, _attachDocument.y() - _attachType->height());
|
||||
_emojiPan->moveBottom(_attachEmoji.y());
|
||||
|
||||
_botStart.setGeometry(0, bottom - _botStart.height(), w, _botStart.height());
|
||||
_unblock.setGeometry(0, bottom - _unblock.height(), w, _unblock.height());
|
||||
|
@ -6458,7 +6504,7 @@ void HistoryWidget::clearInlineBot() {
|
|||
inlineBotChanged();
|
||||
_field.finishPlaceholder();
|
||||
}
|
||||
_emojiPan.clearInlineBot();
|
||||
_emojiPan->clearInlineBot();
|
||||
onCheckFieldAutocomplete();
|
||||
}
|
||||
|
||||
|
@ -6679,7 +6725,9 @@ void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, bool silent, const M
|
|||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
auto caption = item->getMedia() ? item->getMedia()->getCaption() : TextWithEntities();
|
||||
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_flags(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedPhoto(file, MTP_string(caption.text)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId);
|
||||
MTPDinputMediaUploadedPhoto::Flags mediaFlags = 0;
|
||||
auto media = MTP_inputMediaUploadedPhoto(MTP_flags(mediaFlags), file, MTP_string(caption.text), MTPVector<MTPInputDocument>());
|
||||
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_flags(sendFlags), item->history()->peer->input, MTP_int(replyTo), media, MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6697,7 +6745,8 @@ namespace {
|
|||
if (document->type == AnimatedDocument) {
|
||||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
} else if (document->type == StickerDocument && document->sticker()) {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(document->sticker()->alt), document->sticker()->set));
|
||||
MTPDdocumentAttributeSticker::Flags stickerFlags = 0;
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_flags(stickerFlags), MTP_string(document->sticker()->alt), document->sticker()->set, MTPMaskCoords()));
|
||||
} else if (document->type == SongDocument && document->song()) {
|
||||
attributes.push_back(MTP_documentAttributeAudio(MTP_flags(MTPDdocumentAttributeAudio::Flag::f_title | MTPDdocumentAttributeAudio::Flag::f_performer), MTP_int(document->song()->duration), MTP_string(document->song()->title), MTP_string(document->song()->performer), MTPstring()));
|
||||
} else if (document->type == VoiceDocument && document->voice()) {
|
||||
|
@ -6728,7 +6777,9 @@ void HistoryWidget::onDocumentUploaded(const FullMsgId &newId, bool silent, cons
|
|||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
auto caption = item->getMedia() ? item->getMedia()->getCaption() : TextWithEntities();
|
||||
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_flags(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedDocument(file, MTP_string(document->mime), _composeDocumentAttributes(document), MTP_string(caption.text)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId);
|
||||
MTPDinputMediaUploadedDocument::Flags mediaFlags = 0;
|
||||
auto media = MTP_inputMediaUploadedDocument(MTP_flags(mediaFlags), file, MTP_string(document->mime), _composeDocumentAttributes(document), MTP_string(caption.text), MTPVector<MTPInputDocument>());
|
||||
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_flags(sendFlags), item->history()->peer->input, MTP_int(replyTo), media, MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6754,7 +6805,9 @@ void HistoryWidget::onThumbDocumentUploaded(const FullMsgId &newId, bool silent,
|
|||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
auto caption = item->getMedia() ? item->getMedia()->getCaption() : TextWithEntities();
|
||||
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_flags(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedThumbDocument(file, thumb, MTP_string(document->mime), _composeDocumentAttributes(document), MTP_string(caption.text)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId);
|
||||
MTPDinputMediaUploadedThumbDocument::Flags mediaFlags = 0;
|
||||
auto media = MTP_inputMediaUploadedThumbDocument(MTP_flags(mediaFlags), file, thumb, MTP_string(document->mime), _composeDocumentAttributes(document), MTP_string(caption.text), MTPVector<MTPInputDocument>());
|
||||
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_flags(sendFlags), item->history()->peer->input, MTP_int(replyTo), media, MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6925,15 +6978,15 @@ void HistoryWidget::onUpdateHistoryItems() {
|
|||
}
|
||||
|
||||
void HistoryWidget::ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout) {
|
||||
_emojiPan.ui_repaintInlineItem(layout);
|
||||
_emojiPan->ui_repaintInlineItem(layout);
|
||||
}
|
||||
|
||||
bool HistoryWidget::ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) {
|
||||
return _emojiPan.ui_isInlineItemVisible(layout);
|
||||
return _emojiPan->ui_isInlineItemVisible(layout);
|
||||
}
|
||||
|
||||
bool HistoryWidget::ui_isInlineItemBeingChosen() {
|
||||
return _emojiPan.ui_isInlineItemBeingChosen();
|
||||
return _emojiPan->ui_isInlineItemBeingChosen();
|
||||
}
|
||||
|
||||
PeerData *HistoryWidget::ui_getPeerForMouseAction() {
|
||||
|
@ -6947,7 +7000,7 @@ void HistoryWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {
|
|||
}
|
||||
|
||||
void HistoryWidget::notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) {
|
||||
_emojiPan.notify_inlineItemLayoutChanged(layout);
|
||||
_emojiPan->notify_inlineItemLayoutChanged(layout);
|
||||
}
|
||||
|
||||
void HistoryWidget::notify_handlePendingHistoryUpdate() {
|
||||
|
@ -6982,25 +7035,25 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
|
|||
|
||||
_historyToEnd->moveToRight(st::historyToDownPosition.x(), _scroll.y() + _scroll.height() - _historyToEnd->height() - st::historyToDownPosition.y());
|
||||
|
||||
_emojiPan.setMaxHeight(height() - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom() - _attachEmoji.height());
|
||||
_emojiPan->setMaxHeight(height() - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom() - _attachEmoji.height());
|
||||
if (_membersDropdown) {
|
||||
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
|
||||
}
|
||||
|
||||
switch (_attachDrag) {
|
||||
case DragStateFiles:
|
||||
_attachDragDocument.resize(width() - st::dragMargin.left() - st::dragMargin.right(), height() - st::dragMargin.top() - st::dragMargin.bottom());
|
||||
_attachDragDocument.move(st::dragMargin.left(), st::dragMargin.top());
|
||||
_attachDragDocument->resize(width() - st::dragMargin.left() - st::dragMargin.right(), height() - st::dragMargin.top() - st::dragMargin.bottom());
|
||||
_attachDragDocument->move(st::dragMargin.left(), st::dragMargin.top());
|
||||
break;
|
||||
case DragStatePhotoFiles:
|
||||
_attachDragDocument.resize(width() - st::dragMargin.left() - st::dragMargin.right(), (height() - st::dragMargin.top() - st::dragMargin.bottom()) / 2);
|
||||
_attachDragDocument.move(st::dragMargin.left(), st::dragMargin.top());
|
||||
_attachDragPhoto.resize(_attachDragDocument.width(), _attachDragDocument.height());
|
||||
_attachDragPhoto.move(st::dragMargin.left(), height() - _attachDragPhoto.height() - st::dragMargin.bottom());
|
||||
_attachDragDocument->resize(width() - st::dragMargin.left() - st::dragMargin.right(), (height() - st::dragMargin.top() - st::dragMargin.bottom()) / 2);
|
||||
_attachDragDocument->move(st::dragMargin.left(), st::dragMargin.top());
|
||||
_attachDragPhoto->resize(_attachDragDocument->width(), _attachDragDocument->height());
|
||||
_attachDragPhoto->move(st::dragMargin.left(), height() - _attachDragPhoto->height() - st::dragMargin.bottom());
|
||||
break;
|
||||
case DragStateImage:
|
||||
_attachDragPhoto.resize(width() - st::dragMargin.left() - st::dragMargin.right(), height() - st::dragMargin.top() - st::dragMargin.bottom());
|
||||
_attachDragPhoto.move(st::dragMargin.left(), st::dragMargin.top());
|
||||
_attachDragPhoto->resize(width() - st::dragMargin.left() - st::dragMargin.right(), height() - st::dragMargin.top() - st::dragMargin.bottom());
|
||||
_attachDragPhoto->move(st::dragMargin.left(), st::dragMargin.top());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -7423,8 +7476,8 @@ void HistoryWidget::onFieldTabbed() {
|
|||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::onStickerSend(DocumentData *sticker) {
|
||||
sendExistingDocument(sticker, QString());
|
||||
bool HistoryWidget::onStickerSend(DocumentData *sticker) {
|
||||
return sendExistingDocument(sticker, QString());
|
||||
}
|
||||
|
||||
void HistoryWidget::onPhotoSend(PhotoData *photo) {
|
||||
|
@ -7497,8 +7550,8 @@ void HistoryWidget::onInlineResultSend(InlineBots::Result *result, UserData *bot
|
|||
}
|
||||
|
||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
||||
if (!_attachType.isHidden()) _attachType.hideStart();
|
||||
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
|
||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
||||
|
||||
_field.setFocus();
|
||||
}
|
||||
|
@ -7567,10 +7620,10 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
|
|||
if (_membersDropdown) {
|
||||
_membersDropdown->raise();
|
||||
}
|
||||
_attachType.raise();
|
||||
_emojiPan.raise();
|
||||
_attachDragDocument.raise();
|
||||
_attachDragPhoto.raise();
|
||||
_attachType->raise();
|
||||
_emojiPan->raise();
|
||||
_attachDragDocument->raise();
|
||||
_attachDragPhoto->raise();
|
||||
|
||||
updatePinnedBar();
|
||||
result = true;
|
||||
|
@ -7611,14 +7664,14 @@ void HistoryWidget::ReplyEditMessageDataCallback::call(ChannelData *channel, Msg
|
|||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &caption) {
|
||||
bool HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &caption) {
|
||||
if (!_history || !doc || !canSendMessages(_peer)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
MTPInputDocument mtpInput = doc->mtpInput();
|
||||
if (mtpInput.type() == mtpc_inputDocumentEmpty) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
App::main()->readServerHistory(_history);
|
||||
|
@ -7668,10 +7721,11 @@ void HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &capti
|
|||
}
|
||||
|
||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
||||
if (!_attachType.isHidden()) _attachType.hideStart();
|
||||
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
|
||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
||||
|
||||
_field.setFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
void HistoryWidget::sendExistingPhoto(PhotoData *photo, const QString &caption) {
|
||||
|
@ -7714,8 +7768,8 @@ void HistoryWidget::sendExistingPhoto(PhotoData *photo, const QString &caption)
|
|||
App::historyRegRandom(randomId, newId);
|
||||
|
||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
||||
if (!_attachType.isHidden()) _attachType.hideStart();
|
||||
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
|
||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
||||
|
||||
_field.setFocus();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include "localimageloader.h"
|
||||
#include "ui/boxshadow.h"
|
||||
#include "dropdown.h"
|
||||
#include "history/history_common.h"
|
||||
#include "history/field_autocomplete.h"
|
||||
#include "window/section_widget.h"
|
||||
|
@ -39,6 +38,10 @@ class HistoryDownButton;
|
|||
class InnerDropdown;
|
||||
} // namespace Ui
|
||||
|
||||
class Dropdown;
|
||||
class DragArea;
|
||||
class EmojiPan;
|
||||
|
||||
class HistoryWidget;
|
||||
class HistoryInner : public TWidget, public AbstractTooltipShower {
|
||||
Q_OBJECT
|
||||
|
@ -800,7 +803,7 @@ public slots:
|
|||
void onTextChange();
|
||||
|
||||
void onFieldTabbed();
|
||||
void onStickerSend(DocumentData *sticker);
|
||||
bool onStickerSend(DocumentData *sticker);
|
||||
void onPhotoSend(PhotoData *photo);
|
||||
void onInlineResultSend(InlineBots::Result *result, UserData *bot);
|
||||
|
||||
|
@ -910,7 +913,7 @@ private:
|
|||
void call(ChannelData *channel, MsgId msgId) const override;
|
||||
};
|
||||
|
||||
void sendExistingDocument(DocumentData *doc, const QString &caption);
|
||||
bool sendExistingDocument(DocumentData *doc, const QString &caption);
|
||||
void sendExistingPhoto(PhotoData *photo, const QString &caption);
|
||||
|
||||
void drawField(Painter &p, const QRect &rect);
|
||||
|
@ -958,8 +961,10 @@ private:
|
|||
void addMessagesToBack(PeerData *peer, const QVector<MTPMessage> &messages);
|
||||
|
||||
struct BotCallbackInfo {
|
||||
UserData *bot;
|
||||
FullMsgId msgId;
|
||||
int row, col;
|
||||
bool game;
|
||||
};
|
||||
void botCallbackDone(BotCallbackInfo info, const MTPmessages_BotCallbackAnswer &answer, mtpRequestId req);
|
||||
bool botCallbackFail(BotCallbackInfo info, const RPCError &error, mtpRequestId req);
|
||||
|
@ -1123,10 +1128,10 @@ private:
|
|||
ChildWidget<Ui::InnerDropdown> _membersDropdown = { nullptr };
|
||||
QTimer _membersDropdownShowTimer;
|
||||
|
||||
Dropdown _attachType;
|
||||
EmojiPan _emojiPan;
|
||||
ChildWidget<Dropdown> _attachType;
|
||||
ChildWidget<EmojiPan> _emojiPan;
|
||||
DragState _attachDrag = DragStateNone;
|
||||
DragArea _attachDragDocument, _attachDragPhoto;
|
||||
ChildWidget<DragArea> _attachDragDocument, _attachDragPhoto;
|
||||
|
||||
int32 _selCount; // < 0 - text selected, focus list, not _field
|
||||
|
||||
|
|
|
@ -27,6 +27,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "mainwindow.h"
|
||||
#include "mainwidget.h"
|
||||
#include "ui/filedialog.h"
|
||||
#include "styles/style_stickers.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kStickerPreviewEmojiLimit = 10;
|
||||
|
||||
} // namespace
|
||||
|
||||
void LayerWidget::setInnerFocus() {
|
||||
auto focused = App::wnd()->focusWidget();
|
||||
|
@ -339,6 +346,7 @@ void LayerStackWidget::activateLayer(LayerWidget *l) {
|
|||
startShow();
|
||||
} else {
|
||||
l->show();
|
||||
l->showDone();
|
||||
if (App::wnd()) App::wnd()->setInnerFocus();
|
||||
updateLayerBox();
|
||||
}
|
||||
|
@ -426,7 +434,8 @@ LayerStackWidget::~LayerStackWidget() {
|
|||
|
||||
MediaPreviewWidget::MediaPreviewWidget(QWidget *parent) : TWidget(parent)
|
||||
, a_shown(0, 0)
|
||||
, _a_shown(animation(this, &MediaPreviewWidget::step_shown)) {
|
||||
, _a_shown(animation(this, &MediaPreviewWidget::step_shown))
|
||||
, _emojiSize(EmojiSizes[EIndex + 1] / cIntRetinaFactor()) {
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
|
||||
}
|
||||
|
@ -435,8 +444,8 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) {
|
|||
Painter p(this);
|
||||
QRect r(e->rect());
|
||||
|
||||
const QPixmap &draw(currentImage());
|
||||
int w = draw.width() / cIntRetinaFactor(), h = draw.height() / cIntRetinaFactor();
|
||||
auto &image = currentImage();
|
||||
int w = image.width() / cIntRetinaFactor(), h = image.height() / cIntRetinaFactor();
|
||||
if (_a_shown.animating()) {
|
||||
float64 shown = a_shown.current();
|
||||
p.setOpacity(shown);
|
||||
|
@ -444,7 +453,17 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) {
|
|||
// h = qMax(qRound(h * (st::stickerPreviewMin + ((1. - st::stickerPreviewMin) * shown)) / 2.) * 2 + int(h % 2), 1);
|
||||
}
|
||||
p.fillRect(r, st::stickerPreviewBg);
|
||||
p.drawPixmap((width() - w) / 2, (height() - h) / 2, draw);
|
||||
p.drawPixmap((width() - w) / 2, (height() - h) / 2, image);
|
||||
if (!_emojiList.isEmpty()) {
|
||||
int emojiCount = _emojiList.size();
|
||||
int emojiWidth = emojiCount * _emojiSize + (emojiCount - 1) * st::stickerEmojiSkip;
|
||||
int emojiLeft = (width() - emojiWidth) / 2;
|
||||
int esize = _emojiSize * cIntRetinaFactor();
|
||||
for_const (auto emoji, _emojiList) {
|
||||
p.drawPixmapLeft(emojiLeft, (height() - h) / 2 - _emojiSize * 2, width(), App::emojiLarge(), QRect(emoji->x * esize, emoji->y * esize, esize, esize));
|
||||
emojiLeft += _emojiSize + st::stickerEmojiSkip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPreviewWidget::resizeEvent(QResizeEvent *e) {
|
||||
|
@ -472,6 +491,7 @@ void MediaPreviewWidget::showPreview(DocumentData *document) {
|
|||
startShow();
|
||||
_photo = nullptr;
|
||||
_document = document;
|
||||
fillEmojiString();
|
||||
resetGifAndCache();
|
||||
}
|
||||
|
||||
|
@ -510,6 +530,42 @@ void MediaPreviewWidget::hidePreview() {
|
|||
resetGifAndCache();
|
||||
}
|
||||
|
||||
void MediaPreviewWidget::fillEmojiString() {
|
||||
auto getStickerEmojiList = [this](uint64 setId) {
|
||||
QList<EmojiPtr> result;
|
||||
auto &sets = Global::StickerSets();
|
||||
auto it = sets.constFind(setId);
|
||||
if (it == sets.cend()) {
|
||||
return result;
|
||||
}
|
||||
for (auto i = it->emoji.cbegin(), e = it->emoji.cend(); i != e; ++i) {
|
||||
for_const (auto document, *i) {
|
||||
if (document == _document) {
|
||||
result.append(i.key());
|
||||
if (result.size() >= kStickerPreviewEmojiLimit) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
if (auto sticker = _document->sticker()) {
|
||||
auto &inputSet = sticker->set;
|
||||
if (inputSet.type() == mtpc_inputStickerSetID) {
|
||||
_emojiList = getStickerEmojiList(inputSet.c_inputStickerSetID().vid.v);
|
||||
} else {
|
||||
_emojiList.clear();
|
||||
if (auto emoji = emojiFromText(sticker->alt)) {
|
||||
_emojiList.append(emoji);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_emojiList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPreviewWidget::resetGifAndCache() {
|
||||
if (_gif) {
|
||||
if (gif()) {
|
||||
|
|
|
@ -133,7 +133,6 @@ class MediaPreviewWidget : public TWidget {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MediaPreviewWidget(QWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
@ -148,10 +147,10 @@ public:
|
|||
~MediaPreviewWidget();
|
||||
|
||||
private:
|
||||
|
||||
QSize currentDimensions() const;
|
||||
QPixmap currentImage() const;
|
||||
void startShow();
|
||||
void fillEmojiString();
|
||||
void resetGifAndCache();
|
||||
|
||||
anim::fvalue a_shown;
|
||||
|
@ -163,6 +162,9 @@ private:
|
|||
return (!_gif || _gif == Media::Clip::BadReader) ? false : true;
|
||||
}
|
||||
|
||||
int _emojiSize;
|
||||
QList<EmojiPtr> _emojiList;
|
||||
|
||||
void clipCallback(Media::Clip::Notification notification);
|
||||
|
||||
enum CacheStatus {
|
||||
|
|
|
@ -386,13 +386,15 @@ void FileLoadTask::process() {
|
|||
full.save(&buffer, "JPG", 77);
|
||||
}
|
||||
|
||||
photo = MTP_photo(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_vector<MTPPhotoSize>(photoSizes));
|
||||
MTPDphoto::Flags photoFlags = 0;
|
||||
photo = MTP_photo(MTP_flags(photoFlags), MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_vector<MTPPhotoSize>(photoSizes));
|
||||
}
|
||||
|
||||
QByteArray thumbFormat = "JPG";
|
||||
int32 thumbQuality = 87;
|
||||
if (!animated && filemime == stickerMime && w > 0 && h > 0 && w <= StickerMaxSize && h <= StickerMaxSize && filesize < StickerInMemory) {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(""), MTP_inputStickerSetEmpty()));
|
||||
MTPDdocumentAttributeSticker::Flags stickerFlags = 0;
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_flags(stickerFlags), MTP_string(""), MTP_inputStickerSetEmpty(), MTPMaskCoords()));
|
||||
thumbFormat = "webp";
|
||||
thumbname = qsl("thumb.webp");
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -22,165 +22,170 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include "core/basic_types.h"
|
||||
|
||||
namespace _local_inner {
|
||||
namespace Local {
|
||||
|
||||
class Manager : public QObject {
|
||||
void start();
|
||||
void finish();
|
||||
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
void writeUserSettings();
|
||||
void writeMtpData();
|
||||
|
||||
void reset();
|
||||
|
||||
bool checkPasscode(const QByteArray &passcode);
|
||||
void setPasscode(const QByteArray &passcode);
|
||||
|
||||
enum ClearManagerTask {
|
||||
ClearManagerAll = 0xFFFF,
|
||||
ClearManagerDownloads = 0x01,
|
||||
ClearManagerStorage = 0x02,
|
||||
};
|
||||
|
||||
struct ClearManagerData;
|
||||
class ClearManager : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
public:
|
||||
ClearManager();
|
||||
bool addTask(int task);
|
||||
bool hasTask(ClearManagerTask task);
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
Manager();
|
||||
signals:
|
||||
void succeed(int task, void *manager);
|
||||
void failed(int task, void *manager);
|
||||
|
||||
void writeMap(bool fast);
|
||||
void writingMap();
|
||||
void writeLocations(bool fast);
|
||||
void writingLocations();
|
||||
void finish();
|
||||
private slots:
|
||||
void onStart();
|
||||
|
||||
private:
|
||||
~ClearManager();
|
||||
|
||||
ClearManagerData *data;
|
||||
|
||||
};
|
||||
|
||||
enum ReadMapState {
|
||||
ReadMapFailed = 0,
|
||||
ReadMapDone = 1,
|
||||
ReadMapPassNeeded = 2,
|
||||
};
|
||||
ReadMapState readMap(const QByteArray &pass);
|
||||
int32 oldMapVersion();
|
||||
|
||||
int32 oldSettingsVersion();
|
||||
|
||||
using TextWithTags = FlatTextarea::TextWithTags;
|
||||
struct MessageDraft {
|
||||
MessageDraft(MsgId msgId = 0, TextWithTags textWithTags = TextWithTags(), bool previewCancelled = false)
|
||||
: msgId(msgId)
|
||||
, textWithTags(textWithTags)
|
||||
, previewCancelled(previewCancelled) {
|
||||
}
|
||||
MsgId msgId;
|
||||
TextWithTags textWithTags;
|
||||
bool previewCancelled;
|
||||
};
|
||||
void writeDrafts(const PeerId &peer, const MessageDraft &localDraft, const MessageDraft &editDraft);
|
||||
void readDraftsWithCursors(History *h);
|
||||
void writeDraftCursors(const PeerId &peer, const MessageCursor &localCursor, const MessageCursor &editCursor);
|
||||
bool hasDraftCursors(const PeerId &peer);
|
||||
bool hasDraft(const PeerId &peer);
|
||||
|
||||
void writeFileLocation(MediaKey location, const FileLocation &local);
|
||||
FileLocation readFileLocation(MediaKey location, bool check = true);
|
||||
|
||||
void writeImage(const StorageKey &location, const ImagePtr &img);
|
||||
void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true);
|
||||
TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader);
|
||||
int32 hasImages();
|
||||
qint64 storageImagesSize();
|
||||
|
||||
void writeStickerImage(const StorageKey &location, const QByteArray &data, bool overwrite = true);
|
||||
TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader);
|
||||
bool willStickerImageLoad(const StorageKey &location);
|
||||
bool copyStickerImage(const StorageKey &oldLocation, const StorageKey &newLocation);
|
||||
int32 hasStickers();
|
||||
qint64 storageStickersSize();
|
||||
|
||||
void writeAudio(const StorageKey &location, const QByteArray &data, bool overwrite = true);
|
||||
TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader);
|
||||
bool copyAudio(const StorageKey &oldLocation, const StorageKey &newLocation);
|
||||
int32 hasAudios();
|
||||
qint64 storageAudiosSize();
|
||||
|
||||
void writeWebFile(const QString &url, const QByteArray &data, bool overwrite = true);
|
||||
TaskId startWebFileLoad(const QString &url, webFileLoader *loader);
|
||||
int32 hasWebFiles();
|
||||
qint64 storageWebFilesSize();
|
||||
|
||||
void countVoiceWaveform(DocumentData *document);
|
||||
|
||||
void cancelTask(TaskId id);
|
||||
|
||||
void writeInstalledStickers();
|
||||
void writeFeaturedStickers();
|
||||
void writeRecentStickers();
|
||||
void writeArchivedStickers();
|
||||
void readInstalledStickers();
|
||||
void readFeaturedStickers();
|
||||
void readRecentStickers();
|
||||
void readArchivedStickers();
|
||||
int32 countStickersHash(bool checkOutdatedInfo = false);
|
||||
int32 countRecentStickersHash();
|
||||
int32 countFeaturedStickersHash();
|
||||
|
||||
void writeSavedGifs();
|
||||
void readSavedGifs();
|
||||
int32 countSavedGifsHash();
|
||||
|
||||
void writeBackground(int32 id, const QImage &img);
|
||||
bool readBackground();
|
||||
|
||||
void writeRecentHashtagsAndBots();
|
||||
void readRecentHashtagsAndBots();
|
||||
|
||||
void addSavedPeer(PeerData *peer, const QDateTime &position);
|
||||
void removeSavedPeer(PeerData *peer);
|
||||
void readSavedPeers();
|
||||
|
||||
void writeReportSpamStatuses();
|
||||
|
||||
void makeBotTrusted(UserData *bot);
|
||||
bool isBotTrusted(UserData *bot);
|
||||
|
||||
bool encrypt(const void *src, void *dst, uint32 len, const void *key128);
|
||||
bool decrypt(const void *src, void *dst, uint32 len, const void *key128);
|
||||
|
||||
namespace internal {
|
||||
|
||||
class Manager : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Manager();
|
||||
|
||||
void writeMap(bool fast);
|
||||
void writingMap();
|
||||
void writeLocations(bool fast);
|
||||
void writingLocations();
|
||||
void finish();
|
||||
|
||||
public slots:
|
||||
|
||||
void mapWriteTimeout();
|
||||
void locationsWriteTimeout();
|
||||
void mapWriteTimeout();
|
||||
void locationsWriteTimeout();
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
QTimer _mapWriteTimer;
|
||||
QTimer _locationsWriteTimer;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace Local {
|
||||
|
||||
void start();
|
||||
void finish();
|
||||
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
void writeUserSettings();
|
||||
void writeMtpData();
|
||||
|
||||
void reset();
|
||||
|
||||
bool checkPasscode(const QByteArray &passcode);
|
||||
void setPasscode(const QByteArray &passcode);
|
||||
|
||||
enum ClearManagerTask {
|
||||
ClearManagerAll = 0xFFFF,
|
||||
ClearManagerDownloads = 0x01,
|
||||
ClearManagerStorage = 0x02,
|
||||
};
|
||||
|
||||
struct ClearManagerData;
|
||||
class ClearManager : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClearManager();
|
||||
bool addTask(int task);
|
||||
bool hasTask(ClearManagerTask task);
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void succeed(int task, void *manager);
|
||||
void failed(int task, void *manager);
|
||||
|
||||
private slots:
|
||||
void onStart();
|
||||
|
||||
private:
|
||||
~ClearManager();
|
||||
|
||||
ClearManagerData *data;
|
||||
|
||||
};
|
||||
|
||||
enum ReadMapState {
|
||||
ReadMapFailed = 0,
|
||||
ReadMapDone = 1,
|
||||
ReadMapPassNeeded = 2,
|
||||
};
|
||||
ReadMapState readMap(const QByteArray &pass);
|
||||
int32 oldMapVersion();
|
||||
|
||||
int32 oldSettingsVersion();
|
||||
|
||||
using TextWithTags = FlatTextarea::TextWithTags;
|
||||
struct MessageDraft {
|
||||
MessageDraft(MsgId msgId = 0, TextWithTags textWithTags = TextWithTags(), bool previewCancelled = false)
|
||||
: msgId(msgId)
|
||||
, textWithTags(textWithTags)
|
||||
, previewCancelled(previewCancelled) {
|
||||
}
|
||||
MsgId msgId;
|
||||
TextWithTags textWithTags;
|
||||
bool previewCancelled;
|
||||
};
|
||||
void writeDrafts(const PeerId &peer, const MessageDraft &localDraft, const MessageDraft &editDraft);
|
||||
void readDraftsWithCursors(History *h);
|
||||
void writeDraftCursors(const PeerId &peer, const MessageCursor &localCursor, const MessageCursor &editCursor);
|
||||
bool hasDraftCursors(const PeerId &peer);
|
||||
bool hasDraft(const PeerId &peer);
|
||||
|
||||
void writeFileLocation(MediaKey location, const FileLocation &local);
|
||||
FileLocation readFileLocation(MediaKey location, bool check = true);
|
||||
|
||||
void writeImage(const StorageKey &location, const ImagePtr &img);
|
||||
void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true);
|
||||
TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader);
|
||||
int32 hasImages();
|
||||
qint64 storageImagesSize();
|
||||
|
||||
void writeStickerImage(const StorageKey &location, const QByteArray &data, bool overwrite = true);
|
||||
TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader);
|
||||
bool willStickerImageLoad(const StorageKey &location);
|
||||
bool copyStickerImage(const StorageKey &oldLocation, const StorageKey &newLocation);
|
||||
int32 hasStickers();
|
||||
qint64 storageStickersSize();
|
||||
|
||||
void writeAudio(const StorageKey &location, const QByteArray &data, bool overwrite = true);
|
||||
TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader);
|
||||
bool copyAudio(const StorageKey &oldLocation, const StorageKey &newLocation);
|
||||
int32 hasAudios();
|
||||
qint64 storageAudiosSize();
|
||||
|
||||
void writeWebFile(const QString &url, const QByteArray &data, bool overwrite = true);
|
||||
TaskId startWebFileLoad(const QString &url, webFileLoader *loader);
|
||||
int32 hasWebFiles();
|
||||
qint64 storageWebFilesSize();
|
||||
|
||||
void countVoiceWaveform(DocumentData *document);
|
||||
|
||||
void cancelTask(TaskId id);
|
||||
|
||||
void writeInstalledStickers();
|
||||
void writeFeaturedStickers();
|
||||
void writeRecentStickers();
|
||||
void writeArchivedStickers();
|
||||
void readInstalledStickers();
|
||||
void readFeaturedStickers();
|
||||
void readRecentStickers();
|
||||
void readArchivedStickers();
|
||||
int32 countStickersHash(bool checkOutdatedInfo = false);
|
||||
int32 countRecentStickersHash();
|
||||
int32 countFeaturedStickersHash();
|
||||
|
||||
void writeSavedGifs();
|
||||
void readSavedGifs();
|
||||
int32 countSavedGifsHash();
|
||||
|
||||
void writeBackground(int32 id, const QImage &img);
|
||||
bool readBackground();
|
||||
|
||||
void writeRecentHashtagsAndBots();
|
||||
void readRecentHashtagsAndBots();
|
||||
|
||||
void addSavedPeer(PeerData *peer, const QDateTime &position);
|
||||
void removeSavedPeer(PeerData *peer);
|
||||
void readSavedPeers();
|
||||
|
||||
void writeReportSpamStatuses();
|
||||
QTimer _mapWriteTimer;
|
||||
QTimer _locationsWriteTimer;
|
||||
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Local
|
||||
|
|
|
@ -28,6 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "window/section_widget.h"
|
||||
#include "window/top_bar_widget.h"
|
||||
#include "data/data_drafts.h"
|
||||
#include "dropdown.h"
|
||||
#include "observer_peer.h"
|
||||
#include "apiwrap.h"
|
||||
#include "dialogswidget.h"
|
||||
|
@ -45,6 +46,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "boxes/contactsbox.h"
|
||||
#include "boxes/downloadpathbox.h"
|
||||
#include "boxes/confirmphonebox.h"
|
||||
#include "boxes/sharebox.h"
|
||||
#include "localstorage.h"
|
||||
#include "shortcuts.h"
|
||||
#include "media/media_audio.h"
|
||||
|
@ -1710,6 +1712,10 @@ void MainWidget::onShareContactCancel() {
|
|||
_history->cancelShareContact();
|
||||
}
|
||||
|
||||
bool MainWidget::onSendSticker(DocumentData *document) {
|
||||
return _history->onStickerSend(document);
|
||||
}
|
||||
|
||||
void MainWidget::dialogsCancelled() {
|
||||
if (_hider) {
|
||||
_hider->startHide();
|
||||
|
@ -2045,14 +2051,14 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
|
|||
}
|
||||
}
|
||||
|
||||
dlgUpdated();
|
||||
if (back || (way == Ui::ShowWay::ClearStack)) {
|
||||
dlgUpdated();
|
||||
_peerInStack = nullptr;
|
||||
_msgIdInStack = 0;
|
||||
dlgUpdated();
|
||||
} else {
|
||||
saveSectionInStack();
|
||||
}
|
||||
dlgUpdated();
|
||||
|
||||
PeerData *wasActivePeer = activePeer();
|
||||
|
||||
|
@ -2191,11 +2197,8 @@ void MainWidget::saveSectionInStack() {
|
|||
} else if (_wideSection) {
|
||||
_stack.push_back(std_::make_unique<StackItemSection>(_wideSection->createMemento()));
|
||||
} else if (_history->peer()) {
|
||||
dlgUpdated();
|
||||
_peerInStack = _history->peer();
|
||||
_msgIdInStack = _history->msgId();
|
||||
dlgUpdated();
|
||||
|
||||
_stack.push_back(std_::make_unique<StackItemHistory>(_peerInStack, _msgIdInStack, _history->replyReturns()));
|
||||
}
|
||||
}
|
||||
|
@ -3299,33 +3302,34 @@ bool MainWidget::started() {
|
|||
}
|
||||
|
||||
void MainWidget::openLocalUrl(const QString &url) {
|
||||
QString u(url.trimmed());
|
||||
if (u.size() > 8192) u = u.mid(0, 8192);
|
||||
auto urlTrimmed = url.trimmed();
|
||||
if (urlTrimmed.size() > 8192) urlTrimmed = urlTrimmed.mid(0, 8192);
|
||||
|
||||
if (!u.startsWith(qstr("tg://"), Qt::CaseInsensitive)) {
|
||||
if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive)) {
|
||||
return;
|
||||
}
|
||||
auto command = urlTrimmed.midRef(qstr("tg://").size());
|
||||
|
||||
using namespace qthelp;
|
||||
auto matchOptions = RegExOption::CaseInsensitive;
|
||||
if (auto joinChatMatch = regex_match(qsl("^tg://join/?\\?invite=([a-zA-Z0-9\\.\\_\\-]+)(&|$)"), u, matchOptions)) {
|
||||
if (auto joinChatMatch = regex_match(qsl("^join/?\\?invite=([a-zA-Z0-9\\.\\_\\-]+)(&|$)"), command, matchOptions)) {
|
||||
joinGroupByHash(joinChatMatch->captured(1));
|
||||
} else if (auto stickerSetMatch = regex_match(qsl("^tg://addstickers/?\\?set=([a-zA-Z0-9\\.\\_]+)(&|$)"), u, matchOptions)) {
|
||||
} else if (auto stickerSetMatch = regex_match(qsl("^addstickers/?\\?set=([a-zA-Z0-9\\.\\_]+)(&|$)"), command, matchOptions)) {
|
||||
stickersBox(MTP_inputStickerSetShortName(MTP_string(stickerSetMatch->captured(1))));
|
||||
} else if (auto shareUrlMatch = regex_match(qsl("^tg://msg_url/?\\?(.+)(#|$)"), u, matchOptions)) {
|
||||
} else if (auto shareUrlMatch = regex_match(qsl("^msg_url/?\\?(.+)(#|$)"), command, matchOptions)) {
|
||||
auto params = url_parse_params(shareUrlMatch->captured(1), UrlParamNameTransform::ToLower);
|
||||
auto url = params.value(qsl("url"));
|
||||
if (!url.isEmpty()) {
|
||||
shareUrlLayer(url, params.value("text"));
|
||||
}
|
||||
} else if (auto confirmPhoneMatch = regex_match(qsl("^tg://confirmphone/?\\?(.+)(#|$)"), u, matchOptions)) {
|
||||
} else if (auto confirmPhoneMatch = regex_match(qsl("^confirmphone/?\\?(.+)(#|$)"), command, matchOptions)) {
|
||||
auto params = url_parse_params(confirmPhoneMatch->captured(1), UrlParamNameTransform::ToLower);
|
||||
auto phone = params.value(qsl("phone"));
|
||||
auto hash = params.value(qsl("hash"));
|
||||
if (!phone.isEmpty() && !hash.isEmpty()) {
|
||||
ConfirmPhoneBox::start(phone, hash);
|
||||
}
|
||||
} else if (auto usernameMatch = regex_match(qsl("^tg://resolve/?\\?(.+)(#|$)"), u, matchOptions)) {
|
||||
} else if (auto usernameMatch = regex_match(qsl("^resolve/?\\?(.+)(#|$)"), command, matchOptions)) {
|
||||
auto params = url_parse_params(usernameMatch->captured(1), UrlParamNameTransform::ToLower);
|
||||
auto domain = params.value(qsl("domain"));
|
||||
if (auto domainMatch = regex_match(qsl("^[a-zA-Z0-9\\.\\_]+$"), domain, matchOptions)) {
|
||||
|
@ -3345,6 +3349,9 @@ void MainWidget::openLocalUrl(const QString &url) {
|
|||
}
|
||||
openPeerByName(domain, post, startToken);
|
||||
}
|
||||
} else if (auto shareGameScoreMatch = regex_match(qsl("^share_game_score/?\\?(.+)(#|$)"), command, matchOptions)) {
|
||||
auto params = url_parse_params(shareGameScoreMatch->captured(1), UrlParamNameTransform::ToLower);
|
||||
shareGameScoreByHash(params.value(qsl("hash")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4673,91 +4680,97 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
|||
auto &set = d.vstickerset.c_messages_stickerSet();
|
||||
if (set.vset.type() == mtpc_stickerSet) {
|
||||
auto &s = set.vset.c_stickerSet();
|
||||
|
||||
auto &sets = Global::RefStickerSets();
|
||||
auto it = sets.find(s.vid.v);
|
||||
if (it == sets.cend()) {
|
||||
it = sets.insert(s.vid.v, Stickers::Set(s.vid.v, s.vaccess_hash.v, stickerSetTitle(s), qs(s.vshort_name), s.vcount.v, s.vhash.v, s.vflags.v | MTPDstickerSet::Flag::f_installed));
|
||||
} else {
|
||||
it->flags |= MTPDstickerSet::Flag::f_installed;
|
||||
if (it->flags & MTPDstickerSet::Flag::f_archived) {
|
||||
it->flags &= ~MTPDstickerSet::Flag::f_archived;
|
||||
writeArchived = true;
|
||||
}
|
||||
}
|
||||
|
||||
const auto &v(set.vdocuments.c_vector().v);
|
||||
it->stickers.clear();
|
||||
it->stickers.reserve(v.size());
|
||||
for (int32 i = 0, l = v.size(); i < l; ++i) {
|
||||
DocumentData *doc = App::feedDocument(v.at(i));
|
||||
if (!doc || !doc->sticker()) continue;
|
||||
|
||||
it->stickers.push_back(doc);
|
||||
}
|
||||
it->emoji.clear();
|
||||
auto &packs = set.vpacks.c_vector().v;
|
||||
for (int32 i = 0, l = packs.size(); i < l; ++i) {
|
||||
if (packs.at(i).type() != mtpc_stickerPack) continue;
|
||||
auto &pack = packs.at(i).c_stickerPack();
|
||||
if (EmojiPtr e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) {
|
||||
auto &stickers = pack.vdocuments.c_vector().v;
|
||||
StickerPack p;
|
||||
p.reserve(stickers.size());
|
||||
for (int32 j = 0, c = stickers.size(); j < c; ++j) {
|
||||
DocumentData *doc = App::document(stickers.at(j).v);
|
||||
if (!doc || !doc->sticker()) continue;
|
||||
|
||||
p.push_back(doc);
|
||||
if (!s.is_masks()) {
|
||||
auto &sets = Global::RefStickerSets();
|
||||
auto it = sets.find(s.vid.v);
|
||||
if (it == sets.cend()) {
|
||||
it = sets.insert(s.vid.v, Stickers::Set(s.vid.v, s.vaccess_hash.v, stickerSetTitle(s), qs(s.vshort_name), s.vcount.v, s.vhash.v, s.vflags.v | MTPDstickerSet::Flag::f_installed));
|
||||
} else {
|
||||
it->flags |= MTPDstickerSet::Flag::f_installed;
|
||||
if (it->flags & MTPDstickerSet::Flag::f_archived) {
|
||||
it->flags &= ~MTPDstickerSet::Flag::f_archived;
|
||||
writeArchived = true;
|
||||
}
|
||||
it->emoji.insert(e, p);
|
||||
}
|
||||
}
|
||||
auto inputSet = MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access));
|
||||
auto &v = set.vdocuments.c_vector().v;
|
||||
it->stickers.clear();
|
||||
it->stickers.reserve(v.size());
|
||||
for (int i = 0, l = v.size(); i < l; ++i) {
|
||||
auto doc = App::feedDocument(v.at(i));
|
||||
if (!doc || !doc->sticker()) continue;
|
||||
|
||||
auto &order(Global::RefStickerSetsOrder());
|
||||
int32 insertAtIndex = 0, currentIndex = order.indexOf(s.vid.v);
|
||||
if (currentIndex != insertAtIndex) {
|
||||
if (currentIndex > 0) {
|
||||
order.removeAt(currentIndex);
|
||||
it->stickers.push_back(doc);
|
||||
if (doc->sticker()->set.type() != mtpc_inputStickerSetID) {
|
||||
doc->sticker()->set = inputSet;
|
||||
}
|
||||
}
|
||||
order.insert(insertAtIndex, s.vid.v);
|
||||
}
|
||||
it->emoji.clear();
|
||||
auto &packs = set.vpacks.c_vector().v;
|
||||
for (int i = 0, l = packs.size(); i < l; ++i) {
|
||||
if (packs.at(i).type() != mtpc_stickerPack) continue;
|
||||
auto &pack = packs.at(i).c_stickerPack();
|
||||
if (auto e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) {
|
||||
auto &stickers = pack.vdocuments.c_vector().v;
|
||||
StickerPack p;
|
||||
p.reserve(stickers.size());
|
||||
for (int j = 0, c = stickers.size(); j < c; ++j) {
|
||||
auto doc = App::document(stickers.at(j).v);
|
||||
if (!doc || !doc->sticker()) continue;
|
||||
|
||||
auto custom = sets.find(Stickers::CustomSetId);
|
||||
if (custom != sets.cend()) {
|
||||
for (int32 i = 0, l = it->stickers.size(); i < l; ++i) {
|
||||
int32 removeIndex = custom->stickers.indexOf(it->stickers.at(i));
|
||||
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
|
||||
p.push_back(doc);
|
||||
}
|
||||
it->emoji.insert(e, p);
|
||||
}
|
||||
}
|
||||
if (custom->stickers.isEmpty()) {
|
||||
sets.erase(custom);
|
||||
|
||||
auto &order(Global::RefStickerSetsOrder());
|
||||
int32 insertAtIndex = 0, currentIndex = order.indexOf(s.vid.v);
|
||||
if (currentIndex != insertAtIndex) {
|
||||
if (currentIndex > 0) {
|
||||
order.removeAt(currentIndex);
|
||||
}
|
||||
order.insert(insertAtIndex, s.vid.v);
|
||||
}
|
||||
|
||||
auto custom = sets.find(Stickers::CustomSetId);
|
||||
if (custom != sets.cend()) {
|
||||
for (int32 i = 0, l = it->stickers.size(); i < l; ++i) {
|
||||
int32 removeIndex = custom->stickers.indexOf(it->stickers.at(i));
|
||||
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
|
||||
}
|
||||
if (custom->stickers.isEmpty()) {
|
||||
sets.erase(custom);
|
||||
}
|
||||
}
|
||||
Local::writeInstalledStickers();
|
||||
if (writeArchived) Local::writeArchivedStickers();
|
||||
emit stickersUpdated();
|
||||
}
|
||||
Local::writeInstalledStickers();
|
||||
if (writeArchived) Local::writeArchivedStickers();
|
||||
emit stickersUpdated();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateStickerSetsOrder: {
|
||||
auto &d = update.c_updateStickerSetsOrder();
|
||||
auto &order = d.vorder.c_vector().v;
|
||||
auto &sets = Global::StickerSets();
|
||||
Stickers::Order result;
|
||||
for (int32 i = 0, l = order.size(); i < l; ++i) {
|
||||
if (sets.constFind(order.at(i).v) == sets.cend()) {
|
||||
break;
|
||||
if (!d.is_masks()) {
|
||||
auto &order = d.vorder.c_vector().v;
|
||||
auto &sets = Global::StickerSets();
|
||||
Stickers::Order result;
|
||||
for (int i = 0, l = order.size(); i < l; ++i) {
|
||||
if (sets.constFind(order.at(i).v) == sets.cend()) {
|
||||
break;
|
||||
}
|
||||
result.push_back(order.at(i).v);
|
||||
}
|
||||
if (result.size() != Global::StickerSetsOrder().size() || result.size() != order.size()) {
|
||||
Global::SetLastStickersUpdate(0);
|
||||
App::main()->updateStickers();
|
||||
} else {
|
||||
Global::SetStickerSetsOrder(result);
|
||||
Local::writeInstalledStickers();
|
||||
emit stickersUpdated();
|
||||
}
|
||||
result.push_back(order.at(i).v);
|
||||
}
|
||||
if (result.size() != Global::StickerSetsOrder().size() || result.size() != order.size()) {
|
||||
Global::SetLastStickersUpdate(0);
|
||||
App::main()->updateStickers();
|
||||
} else {
|
||||
Global::SetStickerSetsOrder(result);
|
||||
Local::writeInstalledStickers();
|
||||
emit stickersUpdated();
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -4772,16 +4785,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
|||
} break;
|
||||
|
||||
case mtpc_updateReadFeaturedStickers: {
|
||||
for (auto &set : Global::RefStickerSets()) {
|
||||
if (set.flags & MTPDstickerSet_ClientFlag::f_unread) {
|
||||
set.flags &= ~MTPDstickerSet_ClientFlag::f_unread;
|
||||
}
|
||||
}
|
||||
if (Global::FeaturedStickerSetsUnreadCount()) {
|
||||
Global::SetFeaturedStickerSetsUnreadCount(0);
|
||||
Local::writeFeaturedStickers();
|
||||
emit stickersUpdated();
|
||||
}
|
||||
// We read some of the featured stickers, perhaps not all of them.
|
||||
// Here we don't know what featured sticker sets were read, so we
|
||||
// request all of them once again.
|
||||
Global::SetLastFeaturedStickersUpdate(0);
|
||||
App::main()->updateStickers();
|
||||
} break;
|
||||
|
||||
////// Cloud saved GIFs
|
||||
|
|
|
@ -212,6 +212,7 @@ public:
|
|||
void onSendFileCancel(const FileLoadResultPtr &file);
|
||||
void onShareContactConfirm(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, bool ctrlShiftEnter);
|
||||
void onShareContactCancel();
|
||||
bool onSendSticker(DocumentData *sticker);
|
||||
|
||||
void destroyData();
|
||||
void updateOnlineDisplayIn(int32 msecs);
|
||||
|
|
|
@ -146,12 +146,12 @@ inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile
|
|||
inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile;
|
||||
|
||||
inputMediaEmpty#9664f57f = InputMedia;
|
||||
inputMediaUploadedPhoto#f7aff1c0 file:InputFile caption:string = InputMedia;
|
||||
inputMediaUploadedPhoto#630c9af1 flags:# file:InputFile caption:string stickers:flags.0?Vector<InputDocument> = InputMedia;
|
||||
inputMediaPhoto#e9bfb4f3 id:InputPhoto caption:string = InputMedia;
|
||||
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
|
||||
inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia;
|
||||
inputMediaUploadedDocument#1d89306d file:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string = InputMedia;
|
||||
inputMediaUploadedThumbDocument#ad613491 file:InputFile thumb:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string = InputMedia;
|
||||
inputMediaUploadedDocument#d070f1e9 flags:# file:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string stickers:flags.0?Vector<InputDocument> = InputMedia;
|
||||
inputMediaUploadedThumbDocument#50d88cae flags:# file:InputFile thumb:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string stickers:flags.0?Vector<InputDocument> = InputMedia;
|
||||
inputMediaDocument#1a77f29c id:InputDocument caption:string = InputMedia;
|
||||
inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia;
|
||||
inputMediaGifExternal#4843b0fd url:string q:string = InputMedia;
|
||||
|
@ -159,8 +159,8 @@ inputMediaPhotoExternal#b55f4f18 url:string caption:string = InputMedia;
|
|||
inputMediaDocumentExternal#e5e9607c url:string caption:string = InputMedia;
|
||||
|
||||
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
|
||||
inputChatUploadedPhoto#94254732 file:InputFile crop:InputPhotoCrop = InputChatPhoto;
|
||||
inputChatPhoto#b2e1bf08 id:InputPhoto crop:InputPhotoCrop = InputChatPhoto;
|
||||
inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
|
||||
inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;
|
||||
|
||||
inputGeoPointEmpty#e4c123d6 = InputGeoPoint;
|
||||
inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint;
|
||||
|
@ -172,9 +172,6 @@ inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLo
|
|||
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
|
||||
inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation;
|
||||
|
||||
inputPhotoCropAuto#ade6b004 = InputPhotoCrop;
|
||||
inputPhotoCrop#d9915325 crop_left:double crop_top:double crop_width:double = InputPhotoCrop;
|
||||
|
||||
inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
|
||||
|
||||
peerUser#9db1bc6d user_id:int = Peer;
|
||||
|
@ -253,11 +250,12 @@ messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction;
|
|||
messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction;
|
||||
messageActionPinMessage#94bd38ed = MessageAction;
|
||||
messageActionHistoryClear#9fbab604 = MessageAction;
|
||||
messageActionGameScore#3a14cfa5 game_id:int score:int = MessageAction;
|
||||
|
||||
dialog#66ffba14 flags:# peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
|
||||
|
||||
photoEmpty#2331b22d id:long = Photo;
|
||||
photo#cded42fe id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo;
|
||||
photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo;
|
||||
|
||||
photoSizeEmpty#e17e23c type:string = PhotoSize;
|
||||
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
|
||||
|
@ -382,16 +380,16 @@ updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update;
|
|||
updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update;
|
||||
updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update;
|
||||
updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
|
||||
updateStickerSetsOrder#f0dfb451 order:Vector<long> = Update;
|
||||
updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update;
|
||||
updateStickerSets#43ae3dec = Update;
|
||||
updateSavedGifs#9375341e = Update;
|
||||
updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update;
|
||||
updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update;
|
||||
updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update;
|
||||
updateChannelPinnedMessage#98592475 channel_id:int id:int = Update;
|
||||
updateBotCallbackQuery#a68c688c query_id:long user_id:int peer:Peer msg_id:int data:bytes = Update;
|
||||
updateBotCallbackQuery#81c5615f flags:# query_id:long user_id:int peer:Peer msg_id:int data:flags.0?bytes game_id:flags.1?int = Update;
|
||||
updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update;
|
||||
updateInlineBotCallbackQuery#2cbd95af query_id:long user_id:int msg_id:InputBotInlineMessageID data:bytes = Update;
|
||||
updateInlineBotCallbackQuery#d618a28b flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID data:flags.0?bytes game_id:flags.1?int = Update;
|
||||
updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update;
|
||||
updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update;
|
||||
updateReadFeaturedStickers#571d2742 = Update;
|
||||
|
@ -508,10 +506,11 @@ accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;
|
|||
|
||||
documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
|
||||
documentAttributeAnimated#11b58939 = DocumentAttribute;
|
||||
documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute;
|
||||
documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute;
|
||||
documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute;
|
||||
documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute;
|
||||
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
|
||||
documentAttributeHasStickers#9801d2f7 = DocumentAttribute;
|
||||
|
||||
messages.stickersNotModified#f1749a22 = messages.Stickers;
|
||||
messages.stickers#8a8ecd32 hash:string stickers:Vector<Document> = messages.Stickers;
|
||||
|
@ -559,7 +558,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet;
|
|||
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
|
||||
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
|
||||
|
||||
stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
|
||||
stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
|
||||
|
||||
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
|
||||
|
||||
|
@ -573,6 +572,7 @@ keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton;
|
|||
keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton;
|
||||
keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
|
||||
keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
|
||||
keyboardButtonGame#28fc3164 text:string game_title:string game_id:int start_param:string = KeyboardButton;
|
||||
|
||||
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
|
||||
|
||||
|
@ -714,6 +714,12 @@ messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallRes
|
|||
messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered> = messages.StickerSetInstallResult;
|
||||
|
||||
stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered;
|
||||
stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered;
|
||||
|
||||
maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;
|
||||
|
||||
inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia;
|
||||
inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia;
|
||||
|
||||
---functions---
|
||||
|
||||
|
@ -739,6 +745,7 @@ auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery;
|
|||
auth.recoverPassword#4ea56e92 code:string = auth.Authorization;
|
||||
auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
|
||||
auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
|
||||
auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
|
||||
|
||||
account.registerDevice#637ea878 token_type:int token:string = Bool;
|
||||
account.unregisterDevice#65c55b40 token_type:int token:string = Bool;
|
||||
|
@ -796,7 +803,7 @@ messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
|
|||
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
|
||||
messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
|
||||
messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates;
|
||||
messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates;
|
||||
messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates;
|
||||
messages.reportSpam#cf1592db peer:InputPeer = Bool;
|
||||
messages.hideReportSpam#a8f1709b peer:InputPeer = Bool;
|
||||
messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings;
|
||||
|
@ -819,7 +826,6 @@ messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:
|
|||
messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
|
||||
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
|
||||
messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages;
|
||||
messages.getStickers#ae22e045 emoticon:string hash:string = messages.Stickers;
|
||||
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
|
||||
messages.getWebPagePreview#25223e24 message:string = MessageMedia;
|
||||
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
|
||||
|
@ -834,7 +840,7 @@ messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates;
|
|||
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
|
||||
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
|
||||
messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
messages.reorderStickerSets#9fcfbc30 order:Vector<long> = Bool;
|
||||
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool;
|
||||
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
|
||||
messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs;
|
||||
messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
|
||||
|
@ -845,25 +851,28 @@ messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:fla
|
|||
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
|
||||
messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
|
||||
messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
|
||||
messages.getBotCallbackAnswer#a6e94f04 peer:InputPeer msg_id:int data:bytes = messages.BotCallbackAnswer;
|
||||
messages.getBotCallbackAnswer#6c996518 flags:# peer:InputPeer msg_id:int data:flags.0?bytes game_id:flags.1?int = messages.BotCallbackAnswer;
|
||||
messages.setBotCallbackAnswer#c927d44b flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string = Bool;
|
||||
messages.getPeerDialogs#2d9776b9 peers:Vector<InputPeer> = messages.PeerDialogs;
|
||||
messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
|
||||
messages.getAllDrafts#6a3f8d65 = Updates;
|
||||
messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers;
|
||||
messages.readFeaturedStickers#e21cbb = Bool;
|
||||
messages.getRecentStickers#99197c2c hash:int = messages.RecentStickers;
|
||||
messages.saveRecentSticker#348e39bf id:InputDocument unsave:Bool = Bool;
|
||||
messages.clearRecentStickers#ab02e5d2 = Bool;
|
||||
messages.getUnusedStickers#4309d65b limit:int = Vector<StickerSetCovered>;
|
||||
messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool;
|
||||
messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers;
|
||||
messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool;
|
||||
messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool;
|
||||
messages.getArchivedStickers#906e241f offset_id:long limit:int = messages.ArchivedStickers;
|
||||
messages.setGameScore#dfbc7c1f flags:# edit_message:flags.0?true peer:InputPeer id:int user_id:InputUser game_id:int score:int = Updates;
|
||||
messages.setInlineGameScore#54f882f1 flags:# edit_message:flags.0?true id:InputBotInlineMessageID user_id:InputUser game_id:int score:int = Bool;
|
||||
messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers;
|
||||
messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector<StickerSetCovered>;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference;
|
||||
updates.getChannelDifference#bb32d7c0 channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
|
||||
|
||||
photos.updateProfilePhoto#eef579a0 id:InputPhoto crop:InputPhotoCrop = UserProfilePhoto;
|
||||
photos.uploadProfilePhoto#d50f9c88 file:InputFile caption:string geo_point:InputGeoPoint crop:InputPhotoCrop = photos.Photo;
|
||||
photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto;
|
||||
photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo;
|
||||
photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>;
|
||||
photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos;
|
||||
|
||||
|
@ -908,4 +917,4 @@ channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
|
|||
channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates;
|
||||
channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats;
|
||||
|
||||
// LAYER 55
|
||||
// LAYER 56
|
||||
|
|
|
@ -588,6 +588,8 @@ void _serialize_inputMediaEmpty(MTPStringLogger &to, int32 stage, int32 lev, Typ
|
|||
}
|
||||
|
||||
void _serialize_inputMediaUploadedPhoto(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPDinputMediaUploadedPhoto::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -595,8 +597,10 @@ void _serialize_inputMediaUploadedPhoto(MTPStringLogger &to, int32 stage, int32
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" file: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" caption: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" file: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" caption: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" stickers: "); ++stages.back(); if (flag & MTPDinputMediaUploadedPhoto::Flag::f_stickers) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -644,6 +648,8 @@ void _serialize_inputMediaContact(MTPStringLogger &to, int32 stage, int32 lev, T
|
|||
}
|
||||
|
||||
void _serialize_inputMediaUploadedDocument(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPDinputMediaUploadedDocument::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -651,15 +657,19 @@ void _serialize_inputMediaUploadedDocument(MTPStringLogger &to, int32 stage, int
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" file: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" mime_type: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" attributes: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" caption: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" file: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" mime_type: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" attributes: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" caption: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 5: to.add(" stickers: "); ++stages.back(); if (flag & MTPDinputMediaUploadedDocument::Flag::f_stickers) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_inputMediaUploadedThumbDocument(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPDinputMediaUploadedThumbDocument::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -667,11 +677,13 @@ void _serialize_inputMediaUploadedThumbDocument(MTPStringLogger &to, int32 stage
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" file: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" thumb: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" mime_type: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" attributes: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" caption: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" file: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" thumb: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" mime_type: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" attributes: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 5: to.add(" caption: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 6: to.add(" stickers: "); ++stages.back(); if (flag & MTPDinputMediaUploadedThumbDocument::Flag::f_stickers) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -762,7 +774,6 @@ void _serialize_inputChatUploadedPhoto(MTPStringLogger &to, int32 stage, int32 l
|
|||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" file: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" crop: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -776,7 +787,6 @@ void _serialize_inputChatPhoto(MTPStringLogger &to, int32 stage, int32 lev, Type
|
|||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" crop: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -861,25 +871,6 @@ void _serialize_inputDocumentFileLocation(MTPStringLogger &to, int32 stage, int3
|
|||
}
|
||||
}
|
||||
|
||||
void _serialize_inputPhotoCropAuto(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
to.add("{ inputPhotoCropAuto }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
|
||||
}
|
||||
|
||||
void _serialize_inputPhotoCrop(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ inputPhotoCrop");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" crop_left: "); ++stages.back(); types.push_back(mtpc_double+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" crop_top: "); ++stages.back(); types.push_back(mtpc_double+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" crop_width: "); ++stages.back(); types.push_back(mtpc_double+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_inputAppEvent(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
|
@ -1672,6 +1663,20 @@ void _serialize_messageActionHistoryClear(MTPStringLogger &to, int32 stage, int3
|
|||
to.add("{ messageActionHistoryClear }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
|
||||
}
|
||||
|
||||
void _serialize_messageActionGameScore(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messageActionGameScore");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_dialog(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPDdialog::Flags flag(iflag);
|
||||
|
||||
|
@ -1709,6 +1714,8 @@ void _serialize_photoEmpty(MTPStringLogger &to, int32 stage, int32 lev, Types &t
|
|||
}
|
||||
|
||||
void _serialize_photo(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPDphoto::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -1716,10 +1723,12 @@ void _serialize_photo(MTPStringLogger &to, int32 stage, int32 lev, Types &types,
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" date: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" sizes: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" has_stickers: "); ++stages.back(); if (flag & MTPDphoto::Flag::f_has_stickers) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 2: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" date: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 5: to.add(" sizes: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -2880,6 +2889,8 @@ void _serialize_updateNewStickerSet(MTPStringLogger &to, int32 stage, int32 lev,
|
|||
}
|
||||
|
||||
void _serialize_updateStickerSetsOrder(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPDupdateStickerSetsOrder::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -2887,7 +2898,9 @@ void _serialize_updateStickerSetsOrder(MTPStringLogger &to, int32 stage, int32 l
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" order: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_long+0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" masks: "); ++stages.back(); if (flag & MTPDupdateStickerSetsOrder::Flag::f_masks) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 2: to.add(" order: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_long+0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -2970,6 +2983,8 @@ void _serialize_updateChannelPinnedMessage(MTPStringLogger &to, int32 stage, int
|
|||
}
|
||||
|
||||
void _serialize_updateBotCallbackQuery(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPDupdateBotCallbackQuery::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -2977,11 +2992,13 @@ void _serialize_updateBotCallbackQuery(MTPStringLogger &to, int32 stage, int32 l
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" query_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" msg_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" data: "); ++stages.back(); types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" query_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" msg_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 5: to.add(" data: "); ++stages.back(); if (flag & MTPDupdateBotCallbackQuery::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 6: to.add(" game_id: "); ++stages.back(); if (flag & MTPDupdateBotCallbackQuery::Flag::f_game_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -3002,6 +3019,8 @@ void _serialize_updateEditMessage(MTPStringLogger &to, int32 stage, int32 lev, T
|
|||
}
|
||||
|
||||
void _serialize_updateInlineBotCallbackQuery(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPDupdateInlineBotCallbackQuery::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -3009,10 +3028,12 @@ void _serialize_updateInlineBotCallbackQuery(MTPStringLogger &to, int32 stage, i
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" query_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" msg_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" data: "); ++stages.back(); types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" query_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" msg_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" data: "); ++stages.back(); if (flag & MTPDupdateInlineBotCallbackQuery::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 5: to.add(" game_id: "); ++stages.back(); if (flag & MTPDupdateInlineBotCallbackQuery::Flag::f_game_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -4008,6 +4029,8 @@ void _serialize_documentAttributeAnimated(MTPStringLogger &to, int32 stage, int3
|
|||
}
|
||||
|
||||
void _serialize_documentAttributeSticker(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPDdocumentAttributeSticker::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -4015,8 +4038,11 @@ void _serialize_documentAttributeSticker(MTPStringLogger &to, int32 stage, int32
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" alt: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" stickerset: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" mask: "); ++stages.back(); if (flag & MTPDdocumentAttributeSticker::Flag::f_mask) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
|
||||
case 2: to.add(" alt: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" stickerset: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" mask_coords: "); ++stages.back(); if (flag & MTPDdocumentAttributeSticker::Flag::f_mask_coords) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -4069,6 +4095,10 @@ void _serialize_documentAttributeFilename(MTPStringLogger &to, int32 stage, int3
|
|||
}
|
||||
}
|
||||
|
||||
void _serialize_documentAttributeHasStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
to.add("{ documentAttributeHasStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
|
||||
}
|
||||
|
||||
void _serialize_messages_stickersNotModified(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
to.add("{ messages_stickersNotModified }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
|
||||
}
|
||||
|
@ -4446,12 +4476,13 @@ void _serialize_stickerSet(MTPStringLogger &to, int32 stage, int32 lev, Types &t
|
|||
case 1: to.add(" installed: "); ++stages.back(); if (flag & MTPDstickerSet::Flag::f_installed) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 2: to.add(" archived: "); ++stages.back(); if (flag & MTPDstickerSet::Flag::f_archived) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
|
||||
case 3: to.add(" official: "); ++stages.back(); if (flag & MTPDstickerSet::Flag::f_official) { to.add("YES [ BY BIT 2 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
|
||||
case 4: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 5: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 6: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 7: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 8: to.add(" count: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 9: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" masks: "); ++stages.back(); if (flag & MTPDstickerSet::Flag::f_masks) { to.add("YES [ BY BIT 3 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
|
||||
case 5: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 6: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 7: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 8: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 9: to.add(" count: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 10: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -4585,6 +4616,22 @@ void _serialize_keyboardButtonSwitchInline(MTPStringLogger &to, int32 stage, int
|
|||
}
|
||||
}
|
||||
|
||||
void _serialize_keyboardButtonGame(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ keyboardButtonGame");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" text: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" game_title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" start_param: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_keyboardButtonRow(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
|
@ -5891,6 +5938,62 @@ void _serialize_stickerSetCovered(MTPStringLogger &to, int32 stage, int32 lev, T
|
|||
}
|
||||
}
|
||||
|
||||
void _serialize_stickerSetMultiCovered(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ stickerSetMultiCovered");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" set: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" covers: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_maskCoords(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ maskCoords");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" n: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" x: "); ++stages.back(); types.push_back(mtpc_double+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" y: "); ++stages.back(); types.push_back(mtpc_double+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" zoom: "); ++stages.back(); types.push_back(mtpc_double+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_inputStickeredMediaPhoto(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ inputStickeredMediaPhoto");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_inputStickeredMediaDocument(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ inputStickeredMediaDocument");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_req_pq(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
|
@ -6072,6 +6175,19 @@ void _serialize_auth_cancelCode(MTPStringLogger &to, int32 stage, int32 lev, Typ
|
|||
}
|
||||
}
|
||||
|
||||
void _serialize_auth_dropTempAuthKeys(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ auth_dropTempAuthKeys");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" except_auth_keys: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_long+0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_account_registerDevice(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
|
@ -6401,6 +6517,8 @@ void _serialize_messages_editChatAdmin(MTPStringLogger &to, int32 stage, int32 l
|
|||
}
|
||||
|
||||
void _serialize_messages_reorderStickerSets(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPmessages_reorderStickerSets::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -6408,7 +6526,9 @@ void _serialize_messages_reorderStickerSets(MTPStringLogger &to, int32 stage, in
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" order: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_long+0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" masks: "); ++stages.back(); if (flag & MTPmessages_reorderStickerSets::Flag::f_masks) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 2: to.add(" order: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_long+0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -6509,10 +6629,21 @@ void _serialize_messages_saveDraft(MTPStringLogger &to, int32 stage, int32 lev,
|
|||
}
|
||||
|
||||
void _serialize_messages_readFeaturedStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
to.add("{ messages_readFeaturedStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_readFeaturedStickers");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_long+0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_messages_saveRecentSticker(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPmessages_saveRecentSticker::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -6520,14 +6651,48 @@ void _serialize_messages_saveRecentSticker(MTPStringLogger &to, int32 stage, int
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" unsave: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" attached: "); ++stages.back(); if (flag & MTPmessages_saveRecentSticker::Flag::f_attached) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 2: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" unsave: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_messages_clearRecentStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
to.add("{ messages_clearRecentStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
|
||||
MTPmessages_clearRecentStickers::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_clearRecentStickers");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" attached: "); ++stages.back(); if (flag & MTPmessages_clearRecentStickers::Flag::f_attached) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_messages_setInlineGameScore(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPmessages_setInlineGameScore::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_setInlineGameScore");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" edit_message: "); ++stages.back(); if (flag & MTPmessages_setInlineGameScore::Flag::f_edit_message) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 2: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 5: to.add(" score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_upload_saveFilePart(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
|
@ -7447,10 +7612,11 @@ void _serialize_messages_forwardMessages(MTPStringLogger &to, int32 stage, int32
|
|||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" silent: "); ++stages.back(); if (flag & MTPmessages_forwardMessages::Flag::f_silent) { to.add("YES [ BY BIT 5 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 5 IN FIELD flags ]"); } break;
|
||||
case 2: to.add(" background: "); ++stages.back(); if (flag & MTPmessages_forwardMessages::Flag::f_background) { to.add("YES [ BY BIT 6 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break;
|
||||
case 3: to.add(" from_peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_int+0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 5: to.add(" random_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_long+0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 6: to.add(" to_peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" with_my_score: "); ++stages.back(); if (flag & MTPmessages_forwardMessages::Flag::f_with_my_score) { to.add("YES [ BY BIT 8 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 8 IN FIELD flags ]"); } break;
|
||||
case 4: to.add(" from_peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 5: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_int+0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 6: to.add(" random_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_long+0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 7: to.add(" to_peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -7645,6 +7811,27 @@ void _serialize_messages_getAllDrafts(MTPStringLogger &to, int32 stage, int32 le
|
|||
to.add("{ messages_getAllDrafts }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
|
||||
}
|
||||
|
||||
void _serialize_messages_setGameScore(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPmessages_setGameScore::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_setGameScore");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" edit_message: "); ++stages.back(); if (flag & MTPmessages_setGameScore::Flag::f_edit_message) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 2: to.add(" peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 4: to.add(" user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 5: to.add(" game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 6: to.add(" score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_channels_createChannel(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPchannels_createChannel::Flags flag(iflag);
|
||||
|
||||
|
@ -8006,20 +8193,6 @@ void _serialize_photos_deletePhotos(MTPStringLogger &to, int32 stage, int32 lev,
|
|||
}
|
||||
}
|
||||
|
||||
void _serialize_messages_getStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_getStickers");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" emoticon: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_messages_getAllStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
|
@ -8033,6 +8206,19 @@ void _serialize_messages_getAllStickers(MTPStringLogger &to, int32 stage, int32
|
|||
}
|
||||
}
|
||||
|
||||
void _serialize_messages_getMaskStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_getMaskStickers");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_messages_getWebPagePreview(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
|
@ -8189,6 +8375,8 @@ void _serialize_messages_getMessageEditData(MTPStringLogger &to, int32 stage, in
|
|||
}
|
||||
|
||||
void _serialize_messages_getBotCallbackAnswer(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPmessages_getBotCallbackAnswer::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -8196,9 +8384,11 @@ void _serialize_messages_getBotCallbackAnswer(MTPStringLogger &to, int32 stage,
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" msg_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" data: "); ++stages.back(); types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" msg_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" data: "); ++stages.back(); if (flag & MTPmessages_getBotCallbackAnswer::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 4: to.add(" game_id: "); ++stages.back(); if (flag & MTPmessages_getBotCallbackAnswer::Flag::f_game_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -8230,6 +8420,8 @@ void _serialize_messages_getFeaturedStickers(MTPStringLogger &to, int32 stage, i
|
|||
}
|
||||
|
||||
void _serialize_messages_getRecentStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
MTPmessages_getRecentStickers::Flags flag(iflag);
|
||||
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
|
@ -8237,20 +8429,9 @@ void _serialize_messages_getRecentStickers(MTPStringLogger &to, int32 stage, int
|
|||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_messages_getUnusedStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_getUnusedStickers");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" limit: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" attached: "); ++stages.back(); if (flag & MTPmessages_getRecentStickers::Flag::f_attached) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||
case 2: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -8269,6 +8450,19 @@ void _serialize_messages_getArchivedStickers(MTPStringLogger &to, int32 stage, i
|
|||
}
|
||||
}
|
||||
|
||||
void _serialize_messages_getAttachedStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_getAttachedStickers");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" media: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void _serialize_updates_getState(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
|
||||
to.add("{ updates_getState }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
|
||||
}
|
||||
|
@ -8313,7 +8507,6 @@ void _serialize_photos_updateProfilePhoto(MTPStringLogger &to, int32 stage, int3
|
|||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" crop: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -8327,9 +8520,6 @@ void _serialize_photos_uploadProfilePhoto(MTPStringLogger &to, int32 stage, int3
|
|||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" file: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" caption: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" geo_point: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" crop: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
}
|
||||
|
@ -8553,8 +8743,6 @@ namespace {
|
|||
_serializers.insert(mtpc_inputFileLocation, _serialize_inputFileLocation);
|
||||
_serializers.insert(mtpc_inputEncryptedFileLocation, _serialize_inputEncryptedFileLocation);
|
||||
_serializers.insert(mtpc_inputDocumentFileLocation, _serialize_inputDocumentFileLocation);
|
||||
_serializers.insert(mtpc_inputPhotoCropAuto, _serialize_inputPhotoCropAuto);
|
||||
_serializers.insert(mtpc_inputPhotoCrop, _serialize_inputPhotoCrop);
|
||||
_serializers.insert(mtpc_inputAppEvent, _serialize_inputAppEvent);
|
||||
_serializers.insert(mtpc_peerUser, _serialize_peerUser);
|
||||
_serializers.insert(mtpc_peerChat, _serialize_peerChat);
|
||||
|
@ -8619,6 +8807,7 @@ namespace {
|
|||
_serializers.insert(mtpc_messageActionChannelMigrateFrom, _serialize_messageActionChannelMigrateFrom);
|
||||
_serializers.insert(mtpc_messageActionPinMessage, _serialize_messageActionPinMessage);
|
||||
_serializers.insert(mtpc_messageActionHistoryClear, _serialize_messageActionHistoryClear);
|
||||
_serializers.insert(mtpc_messageActionGameScore, _serialize_messageActionGameScore);
|
||||
_serializers.insert(mtpc_dialog, _serialize_dialog);
|
||||
_serializers.insert(mtpc_photoEmpty, _serialize_photoEmpty);
|
||||
_serializers.insert(mtpc_photo, _serialize_photo);
|
||||
|
@ -8815,6 +9004,7 @@ namespace {
|
|||
_serializers.insert(mtpc_documentAttributeVideo, _serialize_documentAttributeVideo);
|
||||
_serializers.insert(mtpc_documentAttributeAudio, _serialize_documentAttributeAudio);
|
||||
_serializers.insert(mtpc_documentAttributeFilename, _serialize_documentAttributeFilename);
|
||||
_serializers.insert(mtpc_documentAttributeHasStickers, _serialize_documentAttributeHasStickers);
|
||||
_serializers.insert(mtpc_messages_stickersNotModified, _serialize_messages_stickersNotModified);
|
||||
_serializers.insert(mtpc_messages_stickers, _serialize_messages_stickers);
|
||||
_serializers.insert(mtpc_stickerPack, _serialize_stickerPack);
|
||||
|
@ -8854,6 +9044,7 @@ namespace {
|
|||
_serializers.insert(mtpc_keyboardButtonRequestPhone, _serialize_keyboardButtonRequestPhone);
|
||||
_serializers.insert(mtpc_keyboardButtonRequestGeoLocation, _serialize_keyboardButtonRequestGeoLocation);
|
||||
_serializers.insert(mtpc_keyboardButtonSwitchInline, _serialize_keyboardButtonSwitchInline);
|
||||
_serializers.insert(mtpc_keyboardButtonGame, _serialize_keyboardButtonGame);
|
||||
_serializers.insert(mtpc_keyboardButtonRow, _serialize_keyboardButtonRow);
|
||||
_serializers.insert(mtpc_replyKeyboardHide, _serialize_replyKeyboardHide);
|
||||
_serializers.insert(mtpc_replyKeyboardForceReply, _serialize_replyKeyboardForceReply);
|
||||
|
@ -8953,6 +9144,10 @@ namespace {
|
|||
_serializers.insert(mtpc_messages_stickerSetInstallResultSuccess, _serialize_messages_stickerSetInstallResultSuccess);
|
||||
_serializers.insert(mtpc_messages_stickerSetInstallResultArchive, _serialize_messages_stickerSetInstallResultArchive);
|
||||
_serializers.insert(mtpc_stickerSetCovered, _serialize_stickerSetCovered);
|
||||
_serializers.insert(mtpc_stickerSetMultiCovered, _serialize_stickerSetMultiCovered);
|
||||
_serializers.insert(mtpc_maskCoords, _serialize_maskCoords);
|
||||
_serializers.insert(mtpc_inputStickeredMediaPhoto, _serialize_inputStickeredMediaPhoto);
|
||||
_serializers.insert(mtpc_inputStickeredMediaDocument, _serialize_inputStickeredMediaDocument);
|
||||
|
||||
_serializers.insert(mtpc_req_pq, _serialize_req_pq);
|
||||
_serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params);
|
||||
|
@ -8968,6 +9163,7 @@ namespace {
|
|||
_serializers.insert(mtpc_auth_sendInvites, _serialize_auth_sendInvites);
|
||||
_serializers.insert(mtpc_auth_bindTempAuthKey, _serialize_auth_bindTempAuthKey);
|
||||
_serializers.insert(mtpc_auth_cancelCode, _serialize_auth_cancelCode);
|
||||
_serializers.insert(mtpc_auth_dropTempAuthKeys, _serialize_auth_dropTempAuthKeys);
|
||||
_serializers.insert(mtpc_account_registerDevice, _serialize_account_registerDevice);
|
||||
_serializers.insert(mtpc_account_unregisterDevice, _serialize_account_unregisterDevice);
|
||||
_serializers.insert(mtpc_account_updateNotifySettings, _serialize_account_updateNotifySettings);
|
||||
|
@ -9002,6 +9198,7 @@ namespace {
|
|||
_serializers.insert(mtpc_messages_readFeaturedStickers, _serialize_messages_readFeaturedStickers);
|
||||
_serializers.insert(mtpc_messages_saveRecentSticker, _serialize_messages_saveRecentSticker);
|
||||
_serializers.insert(mtpc_messages_clearRecentStickers, _serialize_messages_clearRecentStickers);
|
||||
_serializers.insert(mtpc_messages_setInlineGameScore, _serialize_messages_setInlineGameScore);
|
||||
_serializers.insert(mtpc_upload_saveFilePart, _serialize_upload_saveFilePart);
|
||||
_serializers.insert(mtpc_upload_saveBigFilePart, _serialize_upload_saveBigFilePart);
|
||||
_serializers.insert(mtpc_help_saveAppLog, _serialize_help_saveAppLog);
|
||||
|
@ -9081,6 +9278,7 @@ namespace {
|
|||
_serializers.insert(mtpc_messages_sendInlineBotResult, _serialize_messages_sendInlineBotResult);
|
||||
_serializers.insert(mtpc_messages_editMessage, _serialize_messages_editMessage);
|
||||
_serializers.insert(mtpc_messages_getAllDrafts, _serialize_messages_getAllDrafts);
|
||||
_serializers.insert(mtpc_messages_setGameScore, _serialize_messages_setGameScore);
|
||||
_serializers.insert(mtpc_channels_createChannel, _serialize_channels_createChannel);
|
||||
_serializers.insert(mtpc_channels_editAdmin, _serialize_channels_editAdmin);
|
||||
_serializers.insert(mtpc_channels_editTitle, _serialize_channels_editTitle);
|
||||
|
@ -9107,8 +9305,8 @@ namespace {
|
|||
_serializers.insert(mtpc_messages_sendEncryptedService, _serialize_messages_sendEncryptedService);
|
||||
_serializers.insert(mtpc_messages_receivedQueue, _serialize_messages_receivedQueue);
|
||||
_serializers.insert(mtpc_photos_deletePhotos, _serialize_photos_deletePhotos);
|
||||
_serializers.insert(mtpc_messages_getStickers, _serialize_messages_getStickers);
|
||||
_serializers.insert(mtpc_messages_getAllStickers, _serialize_messages_getAllStickers);
|
||||
_serializers.insert(mtpc_messages_getMaskStickers, _serialize_messages_getMaskStickers);
|
||||
_serializers.insert(mtpc_messages_getWebPagePreview, _serialize_messages_getWebPagePreview);
|
||||
_serializers.insert(mtpc_messages_exportChatInvite, _serialize_messages_exportChatInvite);
|
||||
_serializers.insert(mtpc_channels_exportInvite, _serialize_channels_exportInvite);
|
||||
|
@ -9124,8 +9322,8 @@ namespace {
|
|||
_serializers.insert(mtpc_messages_getPeerDialogs, _serialize_messages_getPeerDialogs);
|
||||
_serializers.insert(mtpc_messages_getFeaturedStickers, _serialize_messages_getFeaturedStickers);
|
||||
_serializers.insert(mtpc_messages_getRecentStickers, _serialize_messages_getRecentStickers);
|
||||
_serializers.insert(mtpc_messages_getUnusedStickers, _serialize_messages_getUnusedStickers);
|
||||
_serializers.insert(mtpc_messages_getArchivedStickers, _serialize_messages_getArchivedStickers);
|
||||
_serializers.insert(mtpc_messages_getAttachedStickers, _serialize_messages_getAttachedStickers);
|
||||
_serializers.insert(mtpc_updates_getState, _serialize_updates_getState);
|
||||
_serializers.insert(mtpc_updates_getDifference, _serialize_updates_getDifference);
|
||||
_serializers.insert(mtpc_updates_getChannelDifference, _serialize_updates_getChannelDifference);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -90,8 +90,9 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream &
|
|||
|
||||
thumb = readStorageImageLocation(stream);
|
||||
|
||||
MTPDdocumentAttributeSticker::Flags stickerFlags = 0;
|
||||
if (typeOfSet == StickerSetTypeEmpty) {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetEmpty()));
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_flags(stickerFlags), MTP_string(alt), MTP_inputStickerSetEmpty(), MTPMaskCoords()));
|
||||
} else if (info) {
|
||||
if (info->setId == Stickers::DefaultSetId || info->setId == Stickers::CloudRecentSetId || info->setId == Stickers::CustomSetId) {
|
||||
typeOfSet = StickerSetTypeEmpty;
|
||||
|
@ -99,14 +100,14 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream &
|
|||
|
||||
switch (typeOfSet) {
|
||||
case StickerSetTypeID: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetID(MTP_long(info->setId), MTP_long(info->accessHash))));
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_flags(stickerFlags), MTP_string(alt), MTP_inputStickerSetID(MTP_long(info->setId), MTP_long(info->accessHash)), MTPMaskCoords()));
|
||||
} break;
|
||||
case StickerSetTypeShortName: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetShortName(MTP_string(info->shortName))));
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_flags(stickerFlags), MTP_string(alt), MTP_inputStickerSetShortName(MTP_string(info->shortName)), MTPMaskCoords()));
|
||||
} break;
|
||||
case StickerSetTypeEmpty:
|
||||
default: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetEmpty()));
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_flags(stickerFlags), MTP_string(alt), MTP_inputStickerSetEmpty(), MTPMaskCoords()));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
|
3784
Telegram/SourceFiles/stickers/emoji_pan.cpp
Normal file
3784
Telegram/SourceFiles/stickers/emoji_pan.cpp
Normal file
File diff suppressed because it is too large
Load diff
664
Telegram/SourceFiles/stickers/emoji_pan.h
Normal file
664
Telegram/SourceFiles/stickers/emoji_pan.h
Normal file
|
@ -0,0 +1,664 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/twidget.h"
|
||||
#include "ui/boxshadow.h"
|
||||
|
||||
namespace InlineBots {
|
||||
namespace Layout {
|
||||
class ItemBase;
|
||||
} // namespace Layout
|
||||
class Result;
|
||||
} // namespace InlineBots
|
||||
|
||||
namespace internal {
|
||||
|
||||
constexpr int InlineItemsMaxPerRow = 5;
|
||||
constexpr int EmojiColorsCount = 5;
|
||||
|
||||
using InlineResult = InlineBots::Result;
|
||||
using InlineResults = QList<InlineBots::Result*>;
|
||||
using InlineItem = InlineBots::Layout::ItemBase;
|
||||
|
||||
struct InlineCacheEntry {
|
||||
~InlineCacheEntry() {
|
||||
clearResults();
|
||||
}
|
||||
QString nextOffset;
|
||||
QString switchPmText, switchPmStartToken;
|
||||
InlineResults results; // owns this results list
|
||||
void clearResults();
|
||||
};
|
||||
|
||||
class EmojiColorPicker : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
EmojiColorPicker();
|
||||
|
||||
void showEmoji(uint32 code);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
void showStart();
|
||||
|
||||
void clearSelection(bool fast = false);
|
||||
|
||||
public slots:
|
||||
|
||||
void hideStart(bool fast = false);
|
||||
|
||||
signals:
|
||||
|
||||
void emojiSelected(EmojiPtr emoji);
|
||||
void hidden();
|
||||
|
||||
private:
|
||||
|
||||
void drawVariant(Painter &p, int variant);
|
||||
|
||||
void updateSelected();
|
||||
|
||||
bool _ignoreShow = false;
|
||||
|
||||
EmojiPtr _variants[EmojiColorsCount + 1];
|
||||
|
||||
typedef QMap<int32, uint64> EmojiAnimations; // index - showing, -index - hiding
|
||||
EmojiAnimations _emojiAnimations;
|
||||
Animation _a_selected;
|
||||
|
||||
float64 _hovers[EmojiColorsCount + 1];
|
||||
|
||||
int _selected = -1;
|
||||
int _pressedSel = -1;
|
||||
QPoint _lastMousePos;
|
||||
|
||||
bool _hiding = false;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
Animation _a_appearance;
|
||||
|
||||
QTimer _hideTimer;
|
||||
|
||||
BoxShadow _shadow;
|
||||
|
||||
};
|
||||
|
||||
class EmojiPanel;
|
||||
class EmojiPanInner : public ScrolledWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EmojiPanInner();
|
||||
|
||||
void setMaxHeight(int32 h);
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
void hideFinish();
|
||||
|
||||
void showEmojiPack(DBIEmojiTab packIndex);
|
||||
|
||||
void clearSelection(bool fast = false);
|
||||
|
||||
DBIEmojiTab currentTab(int yOffset) const;
|
||||
|
||||
void refreshRecent();
|
||||
|
||||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
|
||||
void fillPanels(QVector<EmojiPanel*> &panels);
|
||||
void refreshPanels(QVector<EmojiPanel*> &panels);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
void leaveToChildEvent(QEvent *e, QWidget *child) override;
|
||||
void enterFromChildEvent(QEvent *e, QWidget *child) override;
|
||||
|
||||
public slots:
|
||||
void updateSelected();
|
||||
|
||||
void onShowPicker();
|
||||
void onPickerHidden();
|
||||
void onColorSelected(EmojiPtr emoji);
|
||||
|
||||
bool checkPickerHide();
|
||||
|
||||
signals:
|
||||
void selected(EmojiPtr emoji);
|
||||
|
||||
void switchToStickers();
|
||||
|
||||
void scrollToY(int y);
|
||||
void disableScroll(bool dis);
|
||||
|
||||
void needRefreshPanels();
|
||||
void saveConfigDelayed(int32 delay);
|
||||
|
||||
private:
|
||||
int32 _maxHeight;
|
||||
|
||||
int countHeight();
|
||||
void selectEmoji(EmojiPtr emoji);
|
||||
|
||||
QRect emojiRect(int tab, int sel);
|
||||
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _animations;
|
||||
Animation _a_selected;
|
||||
|
||||
int _visibleTop = 0;
|
||||
int _visibleBottom = 0;
|
||||
int _counts[emojiTabCount];
|
||||
|
||||
QVector<EmojiPtr> _emojis[emojiTabCount];
|
||||
QVector<float64> _hovers[emojiTabCount];
|
||||
|
||||
int32 _esize;
|
||||
|
||||
int _selected = -1;
|
||||
int _pressedSel = -1;
|
||||
int _pickerSel = -1;
|
||||
QPoint _lastMousePos;
|
||||
|
||||
EmojiColorPicker _picker;
|
||||
QTimer _showPickerTimer;
|
||||
};
|
||||
|
||||
struct StickerIcon {
|
||||
StickerIcon(uint64 setId) : setId(setId) {
|
||||
}
|
||||
StickerIcon(uint64 setId, DocumentData *sticker, int32 pixw, int32 pixh) : setId(setId), sticker(sticker), pixw(pixw), pixh(pixh) {
|
||||
}
|
||||
uint64 setId;
|
||||
DocumentData *sticker = nullptr;
|
||||
int pixw = 0;
|
||||
int pixh = 0;
|
||||
};
|
||||
|
||||
class StickerPanInner : public ScrolledWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
StickerPanInner();
|
||||
|
||||
void setMaxHeight(int32 h);
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
|
||||
void hideFinish(bool completely);
|
||||
void showFinish();
|
||||
void showStickerSet(uint64 setId);
|
||||
void updateShowingSavedGifs();
|
||||
|
||||
bool showSectionIcons() const;
|
||||
void clearSelection(bool fast = false);
|
||||
|
||||
void refreshStickers();
|
||||
void refreshRecentStickers(bool resize = true);
|
||||
void refreshSavedGifs();
|
||||
int refreshInlineRows(UserData *bot, const InlineCacheEntry *results, bool resultsDeleted);
|
||||
void refreshRecent();
|
||||
void inlineBotChanged();
|
||||
void hideInlineRowsPanel();
|
||||
void clearInlineRowsPanel();
|
||||
|
||||
void fillIcons(QList<StickerIcon> &icons);
|
||||
void fillPanels(QVector<EmojiPanel*> &panels);
|
||||
void refreshPanels(QVector<EmojiPanel*> &panels);
|
||||
|
||||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
void preloadImages();
|
||||
|
||||
uint64 currentSet(int yOffset) const;
|
||||
|
||||
void notify_inlineItemLayoutChanged(const InlineItem *layout);
|
||||
void ui_repaintInlineItem(const InlineItem *layout);
|
||||
bool ui_isInlineItemVisible(const InlineItem *layout);
|
||||
bool ui_isInlineItemBeingChosen();
|
||||
|
||||
bool inlineResultsShown() const {
|
||||
return (_section == Section::Inlines);
|
||||
}
|
||||
int countHeight(bool plain = false);
|
||||
|
||||
~StickerPanInner();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
void leaveToChildEvent(QEvent *e, QWidget *child) override;
|
||||
void enterFromChildEvent(QEvent *e, QWidget *child) override;
|
||||
|
||||
private slots:
|
||||
void updateSelected();
|
||||
void onSettings();
|
||||
void onPreview();
|
||||
void onUpdateInlineItems();
|
||||
void onSwitchPm();
|
||||
void onImageLoaded();
|
||||
|
||||
signals:
|
||||
void selected(DocumentData *sticker);
|
||||
void selected(PhotoData *photo);
|
||||
void selected(InlineBots::Result *result, UserData *bot);
|
||||
|
||||
void displaySet(quint64 setId);
|
||||
void installSet(quint64 setId);
|
||||
void removeSet(quint64 setId);
|
||||
|
||||
void refreshIcons();
|
||||
void emptyInlineRows();
|
||||
|
||||
void switchToEmoji();
|
||||
|
||||
void scrollToY(int y);
|
||||
void scrollUpdated();
|
||||
void disableScroll(bool dis);
|
||||
void needRefreshPanels();
|
||||
|
||||
void saveConfigDelayed(int32 delay);
|
||||
|
||||
private:
|
||||
struct Set {
|
||||
Set(uint64 id, MTPDstickerSet::Flags flags, const QString &title, int32 hoversSize, const StickerPack &pack = StickerPack()) : id(id), flags(flags), title(title), hovers(hoversSize, 0), pack(pack) {
|
||||
}
|
||||
uint64 id;
|
||||
MTPDstickerSet::Flags flags;
|
||||
QString title;
|
||||
QVector<float64> hovers;
|
||||
StickerPack pack;
|
||||
};
|
||||
using Sets = QList<Set>;
|
||||
Sets &shownSets() {
|
||||
return (_section == Section::Featured) ? _featuredSets : _mySets;
|
||||
}
|
||||
const Sets &shownSets() const {
|
||||
return const_cast<StickerPanInner*>(this)->shownSets();
|
||||
}
|
||||
int featuredRowHeight() const;
|
||||
void readVisibleSets();
|
||||
|
||||
bool showingInlineItems() const { // Gifs or Inline results
|
||||
return (_section == Section::Inlines) || (_section == Section::Gifs);
|
||||
}
|
||||
|
||||
void paintInlineItems(Painter &p, const QRect &r);
|
||||
void paintStickers(Painter &p, const QRect &r);
|
||||
void paintSticker(Painter &p, Set &set, int y, int index);
|
||||
bool featuredHasAddButton(int index) const;
|
||||
int featuredContentWidth() const;
|
||||
QRect featuredAddRect(int y) const;
|
||||
|
||||
void refreshSwitchPmButton(const InlineCacheEntry *entry);
|
||||
|
||||
enum class AppendSkip {
|
||||
Archived,
|
||||
Installed,
|
||||
};
|
||||
void appendSet(Sets &to, uint64 setId, AppendSkip skip);
|
||||
|
||||
void selectEmoji(EmojiPtr emoji);
|
||||
QRect stickerRect(int tab, int sel);
|
||||
|
||||
int32 _maxHeight;
|
||||
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _animations;
|
||||
Animation _a_selected;
|
||||
|
||||
int _visibleTop = 0;
|
||||
int _visibleBottom = 0;
|
||||
|
||||
Sets _mySets;
|
||||
Sets _featuredSets;
|
||||
QList<bool> _custom;
|
||||
|
||||
enum class Section {
|
||||
Inlines,
|
||||
Gifs,
|
||||
Featured,
|
||||
Stickers,
|
||||
};
|
||||
Section _section = Section::Stickers;
|
||||
bool _setGifCommand = false;
|
||||
UserData *_inlineBot;
|
||||
QString _inlineBotTitle;
|
||||
uint64 _lastScrolled = 0;
|
||||
QTimer _updateInlineItems;
|
||||
bool _inlineWithThumb = false;
|
||||
|
||||
std_::unique_ptr<BoxButton> _switchPmButton;
|
||||
QString _switchPmStartToken;
|
||||
|
||||
typedef QVector<InlineItem*> InlineItems;
|
||||
struct InlineRow {
|
||||
InlineRow() : height(0) {
|
||||
}
|
||||
int32 height;
|
||||
InlineItems items;
|
||||
};
|
||||
typedef QVector<InlineRow> InlineRows;
|
||||
InlineRows _inlineRows;
|
||||
void clearInlineRows(bool resultsDeleted);
|
||||
|
||||
using GifLayouts = QMap<DocumentData*, InlineItem*>;
|
||||
GifLayouts _gifLayouts;
|
||||
InlineItem *layoutPrepareSavedGif(DocumentData *doc, int32 position);
|
||||
|
||||
using InlineLayouts = QMap<InlineResult*, InlineItem*>;
|
||||
InlineLayouts _inlineLayouts;
|
||||
InlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
|
||||
|
||||
bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth);
|
||||
bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false);
|
||||
|
||||
InlineRow &layoutInlineRow(InlineRow &row, int32 sumWidth = 0);
|
||||
void deleteUnusedGifLayouts();
|
||||
|
||||
void deleteUnusedInlineLayouts();
|
||||
|
||||
int validateExistingInlineRows(const InlineResults &results);
|
||||
void selectInlineResult(int row, int column);
|
||||
void removeRecentSticker(int tab, int index);
|
||||
|
||||
int _selected = -1;
|
||||
int _pressed = -1;
|
||||
int _selectedFeaturedSet = -1;
|
||||
int _pressedFeaturedSet = -1;
|
||||
int _selectedFeaturedSetAdd = -1;
|
||||
int _pressedFeaturedSetAdd = -1;
|
||||
QPoint _lastMousePos;
|
||||
|
||||
QString _addText;
|
||||
int _addWidth;
|
||||
|
||||
LinkButton _settings;
|
||||
|
||||
QTimer _previewTimer;
|
||||
bool _previewShown = false;
|
||||
};
|
||||
|
||||
class EmojiPanel : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
EmojiPanel(QWidget *parent, const QString &text, uint64 setId, bool special, int32 wantedY); // Stickers::NoneSetId if in emoji
|
||||
void setText(const QString &text);
|
||||
void setDeleteVisible(bool isVisible);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
|
||||
int32 wantedY() const {
|
||||
return _wantedY;
|
||||
}
|
||||
void setWantedY(int32 y) {
|
||||
_wantedY = y;
|
||||
}
|
||||
|
||||
signals:
|
||||
|
||||
void deleteClicked(quint64 setId);
|
||||
void mousePressed();
|
||||
|
||||
public slots:
|
||||
|
||||
void onDelete();
|
||||
|
||||
private:
|
||||
|
||||
void updateText();
|
||||
|
||||
int32 _wantedY;
|
||||
QString _text, _fullText;
|
||||
uint64 _setId;
|
||||
bool _special, _deleteVisible;
|
||||
IconedButton *_delete;
|
||||
|
||||
};
|
||||
|
||||
class EmojiSwitchButton : public Button {
|
||||
public:
|
||||
|
||||
EmojiSwitchButton(QWidget *parent, bool toStickers); // otherwise toEmoji
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void updateText(const QString &inlineBotUsername = QString());
|
||||
|
||||
protected:
|
||||
|
||||
bool _toStickers;
|
||||
QString _text;
|
||||
int32 _textWidth;
|
||||
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
class EmojiPan : public TWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EmojiPan(QWidget *parent);
|
||||
|
||||
void setMaxHeight(int32 h);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
void moveBottom(int32 bottom, bool force = false);
|
||||
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void otherEnter();
|
||||
void otherLeave();
|
||||
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
|
||||
bool event(QEvent *e);
|
||||
|
||||
void fastHide();
|
||||
bool hiding() const {
|
||||
return _hiding || _hideTimer.isActive();
|
||||
}
|
||||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void step_slide(float64 ms, bool timer);
|
||||
void step_icons(uint64 ms, bool timer);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *e);
|
||||
void stickersInstalled(uint64 setId);
|
||||
|
||||
void queryInlineBot(UserData *bot, PeerData *peer, QString query);
|
||||
void clearInlineBot();
|
||||
|
||||
bool overlaps(const QRect &globalRect) {
|
||||
if (isHidden() || !_cache.isNull()) return false;
|
||||
|
||||
return QRect(st::dropdownDef.padding.left(),
|
||||
st::dropdownDef.padding.top(),
|
||||
_width - st::dropdownDef.padding.left() - st::dropdownDef.padding.right(),
|
||||
_height - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom()
|
||||
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||
}
|
||||
|
||||
void notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout);
|
||||
void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
|
||||
bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
|
||||
bool ui_isInlineItemBeingChosen();
|
||||
|
||||
bool inlineResultsShown() const {
|
||||
return s_inner.inlineResultsShown();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void refreshStickers();
|
||||
void refreshSavedGifs();
|
||||
|
||||
void hideStart();
|
||||
void hideFinish();
|
||||
|
||||
void showStart();
|
||||
void onWndActiveChanged();
|
||||
|
||||
void onTabChange();
|
||||
void onScrollEmoji();
|
||||
void onScrollStickers();
|
||||
void onSwitch();
|
||||
|
||||
void onDisplaySet(quint64 setId);
|
||||
void onInstallSet(quint64 setId);
|
||||
void onRemoveSet(quint64 setId);
|
||||
void onRemoveSetSure();
|
||||
void onDelayedHide();
|
||||
|
||||
void onRefreshIcons();
|
||||
void onRefreshPanels();
|
||||
|
||||
void onSaveConfig();
|
||||
void onSaveConfigDelayed(int32 delay);
|
||||
|
||||
void onInlineRequest();
|
||||
void onEmptyInlineRows();
|
||||
|
||||
signals:
|
||||
void emojiSelected(EmojiPtr emoji);
|
||||
void stickerSelected(DocumentData *sticker);
|
||||
void photoSelected(PhotoData *photo);
|
||||
void inlineResultSelected(InlineBots::Result *result, UserData *bot);
|
||||
|
||||
void updateStickers();
|
||||
|
||||
private:
|
||||
bool preventAutoHide() const;
|
||||
void installSetDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
bool installSetFail(uint64 setId, const RPCError &error);
|
||||
|
||||
void paintStickerSettingsIcon(Painter &p) const;
|
||||
void paintFeaturedStickerSetsBadge(Painter &p, int iconLeft) const;
|
||||
|
||||
void validateSelectedIcon(bool animated = false);
|
||||
void updateContentHeight();
|
||||
|
||||
void leaveToChildEvent(QEvent *e, QWidget *child);
|
||||
void hideAnimated();
|
||||
void prepareShowHideCache();
|
||||
|
||||
void updateSelected();
|
||||
void updateIcons();
|
||||
|
||||
void prepareTab(int32 &left, int32 top, int32 _width, FlatRadiobutton &tab);
|
||||
void updatePanelsPositions(const QVector<internal::EmojiPanel*> &panels, int32 st);
|
||||
|
||||
void showAll();
|
||||
void hideAll();
|
||||
|
||||
int32 _maxHeight, _contentMaxHeight, _contentHeight, _contentHeightEmoji, _contentHeightStickers;
|
||||
bool _horizontal = false;
|
||||
|
||||
bool _noTabUpdate = false;
|
||||
|
||||
int32 _width, _height, _bottom;
|
||||
bool _hiding = false;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity = { 0. };
|
||||
Animation _a_appearance;
|
||||
|
||||
QTimer _hideTimer;
|
||||
|
||||
BoxShadow _shadow;
|
||||
|
||||
FlatRadiobutton _recent, _people, _nature, _food, _activity, _travel, _objects, _symbols;
|
||||
QList<internal::StickerIcon> _icons;
|
||||
QVector<float64> _iconHovers;
|
||||
int _iconOver = -1;
|
||||
int _iconSel = 0;
|
||||
int _iconDown = -1;
|
||||
bool _iconsDragging = false;
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _iconAnimations;
|
||||
Animation _a_icons;
|
||||
QPoint _iconsMousePos, _iconsMouseDown;
|
||||
int _iconsLeft = 0;
|
||||
int _iconsTop = 0;
|
||||
int _iconsStartX = 0;
|
||||
int _iconsMax = 0;
|
||||
anim::ivalue _iconsX = { 0, 0 };
|
||||
anim::ivalue _iconSelX = { 0, 0 };
|
||||
uint64 _iconsStartAnim = 0;
|
||||
|
||||
bool _stickersShown = false;
|
||||
bool _shownFromInlineQuery = false;
|
||||
QPixmap _fromCache, _toCache;
|
||||
anim::ivalue a_fromCoord, a_toCoord;
|
||||
anim::fvalue a_fromAlpha, a_toAlpha;
|
||||
Animation _a_slide;
|
||||
|
||||
ScrollArea e_scroll;
|
||||
internal::EmojiPanInner e_inner;
|
||||
QVector<internal::EmojiPanel*> e_panels;
|
||||
internal::EmojiSwitchButton e_switch;
|
||||
ScrollArea s_scroll;
|
||||
internal::StickerPanInner s_inner;
|
||||
QVector<internal::EmojiPanel*> s_panels;
|
||||
internal::EmojiSwitchButton s_switch;
|
||||
|
||||
uint64 _displayingSetId = 0;
|
||||
uint64 _removingSetId = 0;
|
||||
|
||||
QTimer _saveConfigTimer;
|
||||
|
||||
// inline bots
|
||||
typedef QMap<QString, internal::InlineCacheEntry*> InlineCache;
|
||||
InlineCache _inlineCache;
|
||||
QTimer _inlineRequestTimer;
|
||||
|
||||
void inlineBotChanged();
|
||||
int32 showInlineRows(bool newResults);
|
||||
bool hideOnNoInlineResults();
|
||||
void recountContentMaxHeight();
|
||||
bool refreshInlineRows(int32 *added = 0);
|
||||
UserData *_inlineBot = nullptr;
|
||||
PeerData *_inlineQueryPeer = nullptr;
|
||||
QString _inlineQuery, _inlineNextQuery, _inlineNextOffset;
|
||||
mtpRequestId _inlineRequestId = 0;
|
||||
void inlineResultsDone(const MTPmessages_BotResults &result);
|
||||
bool inlineResultsFail(const RPCError &error);
|
||||
|
||||
};
|
207
Telegram/SourceFiles/stickers/stickers.cpp
Normal file
207
Telegram/SourceFiles/stickers/stickers.cpp
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "stickers.h"
|
||||
|
||||
#include "boxes/stickersetbox.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "lang.h"
|
||||
#include "apiwrap.h"
|
||||
#include "localstorage.h"
|
||||
#include "mainwidget.h"
|
||||
|
||||
namespace Stickers {
|
||||
namespace {
|
||||
|
||||
constexpr int kReadFeaturedSetsTimeoutMs = 1000;
|
||||
internal::FeaturedReader *FeaturedReaderInstance = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
|
||||
auto &v = d.vsets.c_vector().v;
|
||||
auto &order = Global::RefStickerSetsOrder();
|
||||
Stickers::Order archived;
|
||||
archived.reserve(v.size());
|
||||
QMap<uint64, uint64> setsToRequest;
|
||||
for_const (auto &stickerSet, v) {
|
||||
const MTPDstickerSet *setData = nullptr;
|
||||
switch (stickerSet.type()) {
|
||||
case mtpc_stickerSetCovered: {
|
||||
auto &d = stickerSet.c_stickerSetCovered();
|
||||
if (d.vset.type() == mtpc_stickerSet) {
|
||||
setData = &d.vset.c_stickerSet();
|
||||
}
|
||||
} break;
|
||||
case mtpc_stickerSetMultiCovered: {
|
||||
auto &d = stickerSet.c_stickerSetMultiCovered();
|
||||
if (d.vset.type() == mtpc_stickerSet) {
|
||||
setData = &d.vset.c_stickerSet();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
if (setData) {
|
||||
auto set = Stickers::feedSet(*setData);
|
||||
if (set->stickers.isEmpty()) {
|
||||
setsToRequest.insert(set->id, set->access);
|
||||
}
|
||||
auto index = order.indexOf(set->id);
|
||||
if (index >= 0) {
|
||||
order.removeAt(index);
|
||||
}
|
||||
archived.push_back(set->id);
|
||||
}
|
||||
}
|
||||
if (!setsToRequest.isEmpty()) {
|
||||
for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) {
|
||||
App::api()->scheduleStickerSetRequest(i.key(), i.value());
|
||||
}
|
||||
App::api()->requestStickerSets();
|
||||
}
|
||||
Local::writeInstalledStickers();
|
||||
Local::writeArchivedStickers();
|
||||
Ui::showLayer(new StickersBox(archived), KeepOtherLayers);
|
||||
|
||||
emit App::main()->stickersUpdated();
|
||||
}
|
||||
|
||||
void installLocally(uint64 setId) {
|
||||
auto &sets = Global::RefStickerSets();
|
||||
auto it = sets.find(setId);
|
||||
if (it == sets.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto flags = it->flags;
|
||||
it->flags &= ~(MTPDstickerSet::Flag::f_archived | MTPDstickerSet_ClientFlag::f_unread);
|
||||
it->flags |= MTPDstickerSet::Flag::f_installed;
|
||||
auto changedFlags = flags ^ it->flags;
|
||||
|
||||
auto &order = Global::RefStickerSetsOrder();
|
||||
int insertAtIndex = 0, currentIndex = order.indexOf(setId);
|
||||
if (currentIndex != insertAtIndex) {
|
||||
if (currentIndex > 0) {
|
||||
order.removeAt(currentIndex);
|
||||
}
|
||||
order.insert(insertAtIndex, setId);
|
||||
}
|
||||
|
||||
auto custom = sets.find(Stickers::CustomSetId);
|
||||
if (custom != sets.cend()) {
|
||||
for_const (auto sticker, it->stickers) {
|
||||
int removeIndex = custom->stickers.indexOf(sticker);
|
||||
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
|
||||
}
|
||||
if (custom->stickers.isEmpty()) {
|
||||
sets.erase(custom);
|
||||
}
|
||||
}
|
||||
Local::writeInstalledStickers();
|
||||
if (changedFlags & MTPDstickerSet_ClientFlag::f_unread) Local::writeFeaturedStickers();
|
||||
if (changedFlags & MTPDstickerSet::Flag::f_archived) {
|
||||
auto index = Global::RefArchivedStickerSetsOrder().indexOf(setId);
|
||||
if (index >= 0) {
|
||||
Global::RefArchivedStickerSetsOrder().removeAt(index);
|
||||
Local::writeArchivedStickers();
|
||||
}
|
||||
}
|
||||
emit App::main()->stickersUpdated();
|
||||
}
|
||||
|
||||
void undoInstallLocally(uint64 setId) {
|
||||
auto &sets = Global::RefStickerSets();
|
||||
auto it = sets.find(setId);
|
||||
if (it == sets.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
it->flags &= ~MTPDstickerSet::Flag::f_installed;
|
||||
|
||||
auto &order = Global::RefStickerSetsOrder();
|
||||
int currentIndex = order.indexOf(setId);
|
||||
if (currentIndex >= 0) {
|
||||
order.removeAt(currentIndex);
|
||||
}
|
||||
|
||||
Local::writeInstalledStickers();
|
||||
emit App::main()->stickersUpdated();
|
||||
|
||||
Ui::showLayer(new InformBox(lang(lng_stickers_not_found)), KeepOtherLayers);
|
||||
}
|
||||
|
||||
void markFeaturedAsRead(uint64 setId) {
|
||||
if (!FeaturedReaderInstance) {
|
||||
if (auto main = App::main()) {
|
||||
FeaturedReaderInstance = new internal::FeaturedReader(main);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
FeaturedReaderInstance->scheduleRead(setId);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
void readFeaturedDone() {
|
||||
Local::writeFeaturedStickers();
|
||||
if (App::main()) {
|
||||
emit App::main()->stickersUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
FeaturedReader::FeaturedReader(QObject *parent) : QObject(parent)
|
||||
, _timer(new QTimer(this)) {
|
||||
_timer->setSingleShot(true);
|
||||
connect(_timer, SIGNAL(timeout()), this, SLOT(onReadSets()));
|
||||
}
|
||||
|
||||
void FeaturedReader::scheduleRead(uint64 setId) {
|
||||
if (!_setIds.contains(setId)) {
|
||||
_setIds.insert(setId);
|
||||
_timer->start(kReadFeaturedSetsTimeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
void FeaturedReader::onReadSets() {
|
||||
auto &sets = Global::RefStickerSets();
|
||||
auto count = Global::FeaturedStickerSetsUnreadCount();
|
||||
QVector<MTPlong> wrappedIds;
|
||||
wrappedIds.reserve(_setIds.size());
|
||||
for_const (auto setId, _setIds) {
|
||||
auto it = sets.find(setId);
|
||||
if (it != sets.cend()) {
|
||||
it->flags &= ~MTPDstickerSet_ClientFlag::f_unread;
|
||||
wrappedIds.append(MTP_long(setId));
|
||||
if (count) {
|
||||
--count;
|
||||
}
|
||||
}
|
||||
}
|
||||
_setIds.clear();
|
||||
|
||||
if (!wrappedIds.empty()) {
|
||||
MTP::send(MTPmessages_ReadFeaturedStickers(MTP_vector<MTPlong>(wrappedIds)), rpcDone(&readFeaturedDone));
|
||||
Global::SetFeaturedStickerSetsUnreadCount(count);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Stickers
|
49
Telegram/SourceFiles/stickers/stickers.h
Normal file
49
Telegram/SourceFiles/stickers/stickers.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Stickers {
|
||||
|
||||
void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d);
|
||||
void installLocally(uint64 setId);
|
||||
void undoInstallLocally(uint64 setId);
|
||||
void markFeaturedAsRead(uint64 setId);
|
||||
|
||||
namespace internal {
|
||||
|
||||
class FeaturedReader : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FeaturedReader(QObject *parent);
|
||||
void scheduleRead(uint64 setId);
|
||||
|
||||
private slots:
|
||||
void onReadSets();
|
||||
|
||||
private:
|
||||
QTimer *_timer;
|
||||
OrderedSet<uint64> _setIds;
|
||||
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Stickers
|
60
Telegram/SourceFiles/stickers/stickers.style
Normal file
60
Telegram/SourceFiles/stickers/stickers.style
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
using "basic.style";
|
||||
|
||||
featuredStickersHeader: 45px;
|
||||
featuredStickersSkip: 15px;
|
||||
|
||||
featuredStickersHeaderFont: semiboldFont;
|
||||
featuredStickersHeaderFg: windowTextFg;
|
||||
featuredStickersHeaderTop: 0px;
|
||||
featuredStickersSubheaderFont: normalFont;
|
||||
featuredStickersSubheaderFg: #777;
|
||||
featuredStickersSubheaderTop: 20px;
|
||||
|
||||
featuredStickersAddTop: 3px;
|
||||
featuredStickersAdd: RoundButton(defaultActiveButton) {
|
||||
width: -17px;
|
||||
height: 26px;
|
||||
textTop: 4px;
|
||||
downTextTop: 5px;
|
||||
}
|
||||
|
||||
stickerEmojiSkip: 5px;
|
||||
|
||||
stickersAddIcon: icon {
|
||||
{ "stickers_add", #ffffff },
|
||||
};
|
||||
stickersAddSize: size(30px, 24px);
|
||||
|
||||
stickersFeaturedHeight: 32px;
|
||||
stickersFeaturedFont: contactsNameFont;
|
||||
stickersFeaturedPosition: point(16px, 6px);
|
||||
stickersFeaturedBadgeFont: semiboldFont;
|
||||
stickersFeaturedBadgeSize: 21px;
|
||||
stickersFeaturedPen: contactsNewItemFg;
|
||||
stickersFeaturedUnreadBg: msgFileInBg;
|
||||
stickersFeaturedUnreadSize: 5px;
|
||||
stickersFeaturedUnreadSkip: 5px;
|
||||
stickersFeaturedUnreadTop: 7px;
|
||||
stickersFeaturedInstalled: icon {
|
||||
{ "mediaview_save_check", #40ace3 }
|
||||
};
|
|
@ -1140,7 +1140,7 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
|
|||
for (int32 i = 0, l = attributes.size(); i < l; ++i) {
|
||||
switch (attributes[i].type()) {
|
||||
case mtpc_documentAttributeImageSize: {
|
||||
const auto &d(attributes[i].c_documentAttributeImageSize());
|
||||
auto &d = attributes[i].c_documentAttributeImageSize();
|
||||
dimensions = QSize(d.vw.v, d.vh.v);
|
||||
} break;
|
||||
case mtpc_documentAttributeAnimated: if (type == FileDocument || type == StickerDocument || type == VideoDocument) {
|
||||
|
@ -1148,14 +1148,16 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
|
|||
_additional = nullptr;
|
||||
} break;
|
||||
case mtpc_documentAttributeSticker: {
|
||||
const auto &d(attributes[i].c_documentAttributeSticker());
|
||||
auto &d = attributes[i].c_documentAttributeSticker();
|
||||
if (type == FileDocument) {
|
||||
type = StickerDocument;
|
||||
_additional = std_::make_unique<StickerData>();
|
||||
}
|
||||
if (sticker()) {
|
||||
sticker()->alt = qs(d.valt);
|
||||
sticker()->set = d.vstickerset;
|
||||
if (sticker()->set.type() != mtpc_inputStickerSetID || d.vstickerset.type() == mtpc_inputStickerSetID) {
|
||||
sticker()->set = d.vstickerset;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case mtpc_documentAttributeVideo: {
|
||||
|
|
|
@ -1029,12 +1029,10 @@ struct DocumentAdditionalData {
|
|||
};
|
||||
|
||||
struct StickerData : public DocumentAdditionalData {
|
||||
StickerData() : set(MTP_inputStickerSetEmpty()) {
|
||||
}
|
||||
ImagePtr img;
|
||||
QString alt;
|
||||
|
||||
MTPInputStickerSet set;
|
||||
MTPInputStickerSet set = MTP_inputStickerSetEmpty();
|
||||
bool setInstalled() const;
|
||||
|
||||
StorageImageLocation loc; // doc thumb location
|
||||
|
|
|
@ -438,7 +438,7 @@ CountrySelectBox::CountrySelectBox() : ItemListBox(st::countriesScroll, st::boxW
|
|||
connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
|
||||
connect(&_filter, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||
connect(&_filterCancel, SIGNAL(clicked()), this, SLOT(onFilterCancel()));
|
||||
connect(&_inner, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int)));
|
||||
connect(&_inner, SIGNAL(mustScrollTo(int, int)), scrollArea(), SLOT(scrollToY(int, int)));
|
||||
connect(&_inner, SIGNAL(countryChosen(const QString&)), this, SIGNAL(countryChosen(const QString&)));
|
||||
|
||||
_filterCancel.setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
@ -456,9 +456,9 @@ void CountrySelectBox::keyPressEvent(QKeyEvent *e) {
|
|||
} else if (e->key() == Qt::Key_Up) {
|
||||
_inner.selectSkip(-1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner.selectSkipPage(_scroll.height(), 1);
|
||||
_inner.selectSkipPage(scrollArea()->height(), 1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner.selectSkipPage(_scroll.height(), -1);
|
||||
_inner.selectSkipPage(scrollArea()->height(), -1);
|
||||
} else {
|
||||
ItemListBox::keyPressEvent(e);
|
||||
}
|
||||
|
@ -496,7 +496,7 @@ void CountrySelectBox::onFilterCancel() {
|
|||
}
|
||||
|
||||
void CountrySelectBox::onFilterUpdate() {
|
||||
_scroll.scrollToY(0);
|
||||
scrollArea()->scrollToY(0);
|
||||
if (_filter.getLastText().isEmpty()) {
|
||||
_filterCancel.hide();
|
||||
} else {
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
'<(src_loc)/overview/overview.style',
|
||||
'<(src_loc)/profile/profile.style',
|
||||
'<(src_loc)/settings/settings.style',
|
||||
'<(src_loc)/stickers/stickers.style',
|
||||
'<(src_loc)/ui/widgets/widgets.style',
|
||||
],
|
||||
'langpacks': [
|
||||
|
@ -185,6 +186,8 @@
|
|||
'<(src_loc)/boxes/report_box.h',
|
||||
'<(src_loc)/boxes/sessionsbox.cpp',
|
||||
'<(src_loc)/boxes/sessionsbox.h',
|
||||
'<(src_loc)/boxes/sharebox.cpp',
|
||||
'<(src_loc)/boxes/sharebox.h',
|
||||
'<(src_loc)/boxes/stickersetbox.cpp',
|
||||
'<(src_loc)/boxes/stickersetbox.h',
|
||||
'<(src_loc)/boxes/usernamebox.cpp',
|
||||
|
@ -390,6 +393,10 @@
|
|||
'<(src_loc)/settings/settings_scale_widget.h',
|
||||
'<(src_loc)/settings/settings_widget.cpp',
|
||||
'<(src_loc)/settings/settings_widget.h',
|
||||
'<(src_loc)/stickers/emoji_pan.cpp',
|
||||
'<(src_loc)/stickers/emoji_pan.h',
|
||||
'<(src_loc)/stickers/stickers.cpp',
|
||||
'<(src_loc)/stickers/stickers.h',
|
||||
'<(src_loc)/ui/buttons/history_down_button.cpp',
|
||||
'<(src_loc)/ui/buttons/history_down_button.h',
|
||||
'<(src_loc)/ui/buttons/icon_button.cpp',
|
||||
|
|
Loading…
Add table
Reference in a new issue