Use emoji/stickers/gifs slider in EmojiPan.

Also rename EmojiTabs to EmojiSections.
This commit is contained in:
John Preston 2017-03-28 15:30:38 +03:00
parent 3d846fcd49
commit 1540f6f528
23 changed files with 1466 additions and 1424 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -776,6 +776,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_switch_stickers" = "Stickers";
"lng_switch_stickers_gifs" = "GIFs & Stickers";
"lng_switch_emoji" = "Emoji";
"lng_switch_gifs" = "GIFs";
"lng_stickers_featured_add" = "Add";
"lng_saved_gifs" = "Saved GIFs";

View File

@ -24,11 +24,60 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "storage/file_download.h"
#include "window/notifications_manager.h"
QByteArray AuthSessionData::serialize() const {
auto size = sizeof(qint32) * 2;
auto result = QByteArray();
result.reserve(size);
{
QBuffer buffer(&result);
if (!buffer.open(QIODevice::WriteOnly)) {
Unexpected("Can't open data for AuthSessionData::serialize()");
}
QDataStream stream(&buffer);
stream.setVersion(QDataStream::Qt_5_1);
stream << static_cast<qint32>(_variables.emojiPanTab);
stream << qint32(_variables.lastSeenWarningSeen ? 1 : 0);
}
return result;
}
void AuthSessionData::constructFromSerialized(const QByteArray &serialized) {
if (serialized.isEmpty()) {
return;
}
auto readonly = serialized;
QBuffer buffer(&readonly);
if (!buffer.open(QIODevice::ReadOnly)) {
Unexpected("Can't open data for DcOptions::constructFromSerialized()");
}
QDataStream stream(&buffer);
stream.setVersion(QDataStream::Qt_5_1);
qint32 emojiPanTab = static_cast<qint32>(EmojiPanTabType::Emoji);
qint32 lastSeenWarningSeen = 0;
stream >> emojiPanTab;
stream >> lastSeenWarningSeen;
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: Bad data for AuthSessionData::constructFromSerialized()"));
return;
}
auto uncheckedTab = static_cast<EmojiPanTabType>(emojiPanTab);
switch (uncheckedTab) {
case EmojiPanTabType::Emoji:
case EmojiPanTabType::Stickers:
case EmojiPanTabType::Gifs: _variables.emojiPanTab = uncheckedTab; break;
}
_variables.lastSeenWarningSeen = (lastSeenWarningSeen == 1);
}
AuthSession::AuthSession(UserId userId)
: _userId(userId)
, _downloader(std::make_unique<Storage::Downloader>())
, _notifications(std::make_unique<Window::Notifications::System>(this)) {
t_assert(_userId != 0);
Expects(_userId != 0);
}
bool AuthSession::Exists() {

View File

@ -30,6 +30,56 @@ class System;
} // namespace Notifications
} // namespace Window
enum class EmojiPanTabType {
Emoji,
Stickers,
Gifs,
};
class AuthSessionData final {
public:
base::Variable<bool> &contactsLoaded() {
return _contactsLoaded;
}
base::Variable<bool> &allChatsLoaded() {
return _allChatsLoaded;
}
base::Observable<void> &moreChatsLoaded() {
return _moreChatsLoaded;
}
void copyFrom(const AuthSessionData &other) {
_variables = other._variables;
}
QByteArray serialize() const;
void constructFromSerialized(const QByteArray &serialized);
bool lastSeenWarningSeen() const {
return _variables.lastSeenWarningSeen;
}
void setLastSeenWarningSeen(bool lastSeenWarningSeen) {
_variables.lastSeenWarningSeen = lastSeenWarningSeen;
}
EmojiPanTabType emojiPanTab() const {
return _variables.emojiPanTab;
}
void setEmojiPanTab(EmojiPanTabType tab) {
_variables.emojiPanTab = tab;
}
private:
struct Variables {
bool lastSeenWarningSeen = false;
EmojiPanTabType emojiPanTab = EmojiPanTabType::Emoji;
};
base::Variable<bool> _contactsLoaded = { false };
base::Variable<bool> _allChatsLoaded = { false };
base::Observable<void> _moreChatsLoaded;
Variables _variables;
};
class AuthSession final {
public:
AuthSession(UserId userId);
@ -63,33 +113,7 @@ public:
return *_notifications;
}
class Data {
public:
base::Variable<bool> &contactsLoaded() {
return _contactsLoaded;
}
base::Variable<bool> &allChatsLoaded() {
return _allChatsLoaded;
}
base::Observable<void> &moreChatsLoaded() {
return _moreChatsLoaded;
}
bool lastSeenWarningSeen() const {
return _lastSeenWarningSeen;
}
void setLastSeenWarningSeen(bool lastSeenWarningSeen) {
_lastSeenWarningSeen = lastSeenWarningSeen;
}
private:
base::Variable<bool> _contactsLoaded = { false } ;
base::Variable<bool> _allChatsLoaded = { false };
base::Observable<void> _moreChatsLoaded;
bool _lastSeenWarningSeen = false;
};
Data &data() {
AuthSessionData &data() {
return _data;
}
@ -97,7 +121,7 @@ public:
private:
UserId _userId = 0;
Data _data;
AuthSessionData _data;
const std::unique_ptr<Storage::Downloader> _downloader;
const std::unique_ptr<Window::Notifications::System> _notifications;

View File

@ -386,38 +386,40 @@ void StickersBox::switchTab() {
newTab = &_archived;
requestArchivedSets();
}
if (_tab != newTab) {
if (_tab == &_installed) {
_localOrder = _tab->widget()->getFullOrder();
_localRemoved = _tab->widget()->getRemovedSets();
}
auto wasCache = grabContentCache();
auto wasIndex = _tab->index();
_tab->saveScrollTop();
auto widget = takeInnerWidget<Inner>();
widget->setParent(this);
widget->hide();
_tab->returnWidget(std::move(widget));
_tab = newTab;
_section = newSection;
setInnerWidget(_tab->takeWidget(), getTopSkip());
_tabs->raise();
_unreadBadge->raise();
_tab->widget()->show();
rebuildList();
onScrollToY(_tab->getScrollTop());
auto nowCache = grabContentCache();
auto nowIndex = _tab->index();
_slideAnimation = std::make_unique<Ui::SlideAnimation>();
_slideAnimation->setSnapshots(std::move(wasCache), std::move(nowCache));
auto slideLeft = wasIndex > nowIndex;
_slideAnimation->start(slideLeft, [this] { update(); }, st::slideDuration);
setInnerVisible(false);
setFocus();
update();
if (_tab == newTab) {
return;
}
if (_tab == &_installed) {
_localOrder = _tab->widget()->getFullOrder();
_localRemoved = _tab->widget()->getRemovedSets();
}
auto wasCache = grabContentCache();
auto wasIndex = _tab->index();
_tab->saveScrollTop();
auto widget = takeInnerWidget<Inner>();
widget->setParent(this);
widget->hide();
_tab->returnWidget(std::move(widget));
_tab = newTab;
_section = newSection;
setInnerWidget(_tab->takeWidget(), getTopSkip());
_tabs->raise();
_unreadBadge->raise();
_tab->widget()->show();
rebuildList();
onScrollToY(_tab->getScrollTop());
auto nowCache = grabContentCache();
auto nowIndex = _tab->index();
_slideAnimation = std::make_unique<Ui::SlideAnimation>();
_slideAnimation->setSnapshots(std::move(wasCache), std::move(nowCache));
auto slideLeft = wasIndex > nowIndex;
_slideAnimation->start(slideLeft, [this] { update(); }, st::slideDuration);
setInnerVisible(false);
setFocus();
update();
}
QPixmap StickersBox::grabContentCache() {

View File

@ -35,6 +35,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "auth_session.h"
#include "messenger.h"
namespace {
constexpr auto kStickerPanPerRow = Stickers::kPanPerRow;
} // namespace
StickerSetBox::StickerSetBox(QWidget*, const MTPInputStickerSet &set)
: _set(set) {
}
@ -181,8 +187,8 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
if (_pack.isEmpty()) {
Ui::show(Box<InformBox>(lang(lng_stickers_not_found)));
} else {
int32 rows = _pack.size() / StickerPanPerRow + ((_pack.size() % StickerPanPerRow) ? 1 : 0);
resize(st::stickersPadding.left() + StickerPanPerRow * st::stickersSize.width(), st::stickersPadding.top() + rows * st::stickersSize.height() + st::stickersPadding.bottom());
int32 rows = _pack.size() / kStickerPanPerRow + ((_pack.size() % kStickerPanPerRow) ? 1 : 0);
resize(st::stickersPadding.left() + kStickerPanPerRow * st::stickersSize.width(), st::stickersPadding.top() + rows * st::stickersSize.height() + st::stickersPadding.bottom());
}
_loaded = true;
@ -319,8 +325,8 @@ void StickerSetBox::Inner::setSelected(int selected) {
void StickerSetBox::Inner::startOverAnimation(int index, float64 from, float64 to) {
if (index >= 0 && index < _packOvers.size()) {
_packOvers[index].start([this, index] {
int row = index / StickerPanPerRow;
int column = index % StickerPanPerRow;
int row = index / kStickerPanPerRow;
int column = index % kStickerPanPerRow;
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());
@ -341,8 +347,8 @@ int32 StickerSetBox::Inner::stickerFromGlobalPos(const QPoint &p) const {
if (rtl()) l.setX(width() - l.x());
int32 row = (l.y() >= st::stickersPadding.top()) ? qFloor((l.y() - st::stickersPadding.top()) / st::stickersSize.height()) : -1;
int32 col = (l.x() >= st::stickersPadding.left()) ? qFloor((l.x() - st::stickersPadding.left()) / st::stickersSize.width()) : -1;
if (row >= 0 && col >= 0 && col < StickerPanPerRow) {
int32 result = row * StickerPanPerRow + col;
if (row >= 0 && col >= 0 && col < kStickerPanPerRow) {
int32 result = row * kStickerPanPerRow + col;
return (result < _pack.size()) ? result : -1;
}
return -1;
@ -355,12 +361,12 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) {
if (_pack.isEmpty()) return;
auto ms = getms();
int32 rows = _pack.size() / StickerPanPerRow + ((_pack.size() % StickerPanPerRow) ? 1 : 0);
int32 rows = _pack.size() / kStickerPanPerRow + ((_pack.size() % kStickerPanPerRow) ? 1 : 0);
int32 from = qFloor(e->rect().top() / st::stickersSize.height()), to = qFloor(e->rect().bottom() / st::stickersSize.height()) + 1;
for (int32 i = from; i < to; ++i) {
for (int32 j = 0; j < StickerPanPerRow; ++j) {
int32 index = i * StickerPanPerRow + j;
for (int32 j = 0; j < kStickerPanPerRow; ++j) {
int32 index = i * kStickerPanPerRow + j;
if (index >= _pack.size()) break;
t_assert(index < _packOvers.size());

View File

@ -393,18 +393,18 @@ void Init() {\n\
bool Generator::writePacks() {
constexpr const char *packNames[] = {
"dbietPeople",
"dbietNature",
"dbietFood",
"dbietActivity",
"dbietTravel",
"dbietObjects",
"dbietSymbols",
"dbiesPeople",
"dbiesNature",
"dbiesFood",
"dbiesActivity",
"dbiesTravel",
"dbiesObjects",
"dbiesSymbols",
};
source_->stream() << "\
\n\
int GetPackCount(DBIEmojiTab tab) {\n\
switch (tab) {\n";
int GetPackCount(DBIEmojiSection section) {\n\
switch (section) {\n";
auto countIndex = 0;
for (auto name : packNames) {
if (countIndex >= int(data_.categories.size())) {
@ -415,13 +415,13 @@ int GetPackCount(DBIEmojiTab tab) {\n\
case " << name << ": return " << data_.categories[countIndex++].size() << ";\n";
}
source_->stream() << "\
case dbietRecent: return cGetRecentEmoji().size();\n\
case dbiesRecent: return GetRecent().size();\n\
}\n\
return 0;\n\
}\n\
\n\
EmojiPack GetPack(DBIEmojiTab tab) {\n\
switch (tab) {\n";
EmojiPack GetPack(DBIEmojiSection section) {\n\
switch (section) {\n";
auto index = 0;
for (auto name : packNames) {
if (index >= int(data_.categories.size())) {
@ -444,10 +444,10 @@ EmojiPack GetPack(DBIEmojiTab tab) {\n\
} break;\n\n";
}
source_->stream() << "\
case dbietRecent: {\n\
case dbiesRecent: {\n\
auto result = EmojiPack();\n\
result.reserve(cGetRecentEmoji().size());\n\
for (auto &item : cGetRecentEmoji()) {\n\
result.reserve(GetRecent().size());\n\
for (auto &item : GetRecent()) {\n\
result.push_back(item.first);\n\
}\n\
return result;\n\

View File

@ -110,11 +110,6 @@ enum {
ShortcutsCountLimit = 256, // how many shortcuts can be in json file
PreloadHeightsCount = 3, // when 3 screens to scroll left make a preload request
EmojiPanPerRow = 7,
EmojiPanRowsPerPage = 6,
StickerPanPerRow = 5,
StickerPanRowsPerPage = 4,
StickersUpdateTimeout = 3600000, // update not more than once in an hour
SearchPeopleLimit = 5,
MinUsernameLength = 5,

View File

@ -223,6 +223,12 @@ inline QFlags<Enum> qFlags(Enum v) {
return QFlags<Enum>(v);
}
template <typename Lambda>
inline void InvokeQueued(QObject *context, Lambda &&lambda) {
QObject proxy;
QObject::connect(&proxy, &QObject::destroyed, context, std::forward<Lambda>(lambda), Qt::QueuedConnection);
}
static const int32 ScrollMax = INT_MAX;
extern uint64 _SharedMemoryLocation[];
@ -521,21 +527,17 @@ enum DBIScale {
static const int MatrixRowShift = 40000;
enum DBIEmojiTab {
dbietRecent = -1,
dbietPeople = 0,
dbietNature = 1,
dbietFood = 2,
dbietActivity = 3,
dbietTravel = 4,
dbietObjects = 5,
dbietSymbols = 6,
dbietStickers = 666,
enum DBIEmojiSection {
dbiesRecent = -1,
dbiesPeople = 0,
dbiesNature = 1,
dbiesFood = 2,
dbiesActivity = 3,
dbiesTravel = 4,
dbiesObjects = 5,
dbiesSymbols = 6,
dbiesStickers = 666,
};
static const int emojiTabCount = 8;
inline DBIEmojiTab emojiTabAtIndex(int index) {
return (index < 0 || index >= emojiTabCount) ? dbietRecent : DBIEmojiTab(index - 1);
}
enum DBIPlatform {
dbipWindows = 0,

View File

@ -67,6 +67,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace {
constexpr auto kStickersUpdateTimeout = 3600000; // update not more than once in an hour
QString mimeTagFromTag(const QString &tagId) {
if (tagId.startsWith(qstr("mention://"))) {
return tagId + ':' + QString::number(AuthSession::CurrentUserId());
@ -3718,22 +3720,22 @@ void HistoryWidget::onRecordUpdate(quint16 level, qint32 samples) {
void HistoryWidget::updateStickers() {
auto now = getms(true);
if (!Global::LastStickersUpdate() || now >= Global::LastStickersUpdate() + StickersUpdateTimeout) {
if (!Global::LastStickersUpdate() || now >= Global::LastStickersUpdate() + kStickersUpdateTimeout) {
if (!_stickersUpdateRequest) {
_stickersUpdateRequest = MTP::send(MTPmessages_GetAllStickers(MTP_int(Local::countStickersHash(true))), rpcDone(&HistoryWidget::stickersGot), rpcFail(&HistoryWidget::stickersFailed));
}
}
if (!Global::LastRecentStickersUpdate() || now >= Global::LastRecentStickersUpdate() + StickersUpdateTimeout) {
if (!Global::LastRecentStickersUpdate() || now >= Global::LastRecentStickersUpdate() + kStickersUpdateTimeout) {
if (!_recentStickersUpdateRequest) {
_recentStickersUpdateRequest = MTP::send(MTPmessages_GetRecentStickers(MTP_flags(0), MTP_int(Local::countRecentStickersHash())), rpcDone(&HistoryWidget::recentStickersGot), rpcFail(&HistoryWidget::recentStickersFailed));
}
}
if (!Global::LastFeaturedStickersUpdate() || now >= Global::LastFeaturedStickersUpdate() + StickersUpdateTimeout) {
if (!Global::LastFeaturedStickersUpdate() || now >= Global::LastFeaturedStickersUpdate() + kStickersUpdateTimeout) {
if (!_featuredStickersUpdateRequest) {
_featuredStickersUpdateRequest = MTP::send(MTPmessages_GetFeaturedStickers(MTP_int(Local::countFeaturedStickersHash())), rpcDone(&HistoryWidget::featuredStickersGot), rpcFail(&HistoryWidget::featuredStickersFailed));
}
}
if (!cLastSavedGifsUpdate() || now >= cLastSavedGifsUpdate() + StickersUpdateTimeout) {
if (!cLastSavedGifsUpdate() || now >= cLastSavedGifsUpdate() + kStickersUpdateTimeout) {
if (!_savedGifsUpdateRequest) {
_savedGifsUpdateRequest = MTP::send(MTPmessages_GetSavedGifs(MTP_int(Local::countSavedGifsHash())), rpcDone(&HistoryWidget::savedGifsGot), rpcFail(&HistoryWidget::savedGifsFailed));
}

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "settings.h"
#include "platform/platform_specific.h"
#include "stickers/emoji_pan.h"
#include "lang.h"
bool gRtl = false;
@ -82,7 +83,6 @@ RecentStickerPack gRecentStickers;
SavedGifs gSavedGifs;
TimeMs gLastSavedGifsUpdate = 0;
bool gShowingSavedGifs = false;
RecentHashtagPack gRecentWriteHashtags, gRecentSearchHashtags;
@ -212,79 +212,6 @@ void settingsParseArgs(int argc, char *argv[]) {
}
}
RecentEmojiPack &cGetRecentEmoji() {
if (cRecentEmoji().isEmpty()) {
RecentEmojiPack result;
auto haveAlready = [&result](EmojiPtr emoji) {
for (auto &row : result) {
if (row.first->id() == emoji->id()) {
return true;
}
}
return false;
};
if (!cRecentEmojiPreload().isEmpty()) {
auto preload = cRecentEmojiPreload();
cSetRecentEmojiPreload(RecentEmojiPreload());
result.reserve(preload.size());
for (auto i = preload.cbegin(), e = preload.cend(); i != e; ++i) {
if (auto emoji = Ui::Emoji::Find(i->first)) {
if (!haveAlready(emoji)) {
result.push_back(qMakePair(emoji, i->second));
}
}
}
}
uint64 defaultRecent[] = {
0xD83DDE02LLU,
0xD83DDE18LLU,
0x2764LLU,
0xD83DDE0DLLU,
0xD83DDE0ALLU,
0xD83DDE01LLU,
0xD83DDC4DLLU,
0x263ALLU,
0xD83DDE14LLU,
0xD83DDE04LLU,
0xD83DDE2DLLU,
0xD83DDC8BLLU,
0xD83DDE12LLU,
0xD83DDE33LLU,
0xD83DDE1CLLU,
0xD83DDE48LLU,
0xD83DDE09LLU,
0xD83DDE03LLU,
0xD83DDE22LLU,
0xD83DDE1DLLU,
0xD83DDE31LLU,
0xD83DDE21LLU,
0xD83DDE0FLLU,
0xD83DDE1ELLU,
0xD83DDE05LLU,
0xD83DDE1ALLU,
0xD83DDE4ALLU,
0xD83DDE0CLLU,
0xD83DDE00LLU,
0xD83DDE0BLLU,
0xD83DDE06LLU,
0xD83DDC4CLLU,
0xD83DDE10LLU,
0xD83DDE15LLU,
};
for (auto oldKey : defaultRecent) {
if (result.size() >= EmojiPanPerRow * EmojiPanRowsPerPage) break;
if (auto emoji = Ui::Emoji::FromOldKey(oldKey)) {
if (!haveAlready(emoji)) {
result.push_back(qMakePair(emoji, 1));
}
}
}
cSetRecentEmoji(result);
}
return cRefRecentEmoji();
}
RecentStickerPack &cGetRecentStickers() {
if (cRecentStickers().isEmpty() && !cRecentStickersPreload().isEmpty()) {
RecentStickerPreload p(cRecentStickersPreload());

View File

@ -156,8 +156,6 @@ DeclareRefSetting(RecentEmojiPack, RecentEmoji);
DeclareSetting(RecentEmojiPreload, RecentEmojiPreload);
DeclareRefSetting(EmojiColorVariants, EmojiVariants);
RecentEmojiPack &cGetRecentEmoji();
class DocumentData;
typedef QVector<DocumentData*> StickerPack;
@ -174,7 +172,6 @@ typedef QMap<EmojiPtr, StickerPack> StickersByEmojiMap;
typedef QVector<DocumentData*> SavedGifs;
DeclareRefSetting(SavedGifs, SavedGifs);
DeclareSetting(TimeMs, LastSavedGifsUpdate);
DeclareSetting(bool, ShowingSavedGifs);
typedef QList<QPair<QString, ushort> > RecentHashtagPack;
DeclareRefSetting(RecentHashtagPack, RecentWriteHashtags);

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/effects/panel_animation.h"
#include "mtproto/sender.h"
#include "inline_bots/inline_bot_layout_item.h"
#include "auth_session.h"
namespace InlineBots {
namespace Layout {
@ -34,16 +35,23 @@ class Result;
} // namespace InlineBots
namespace Ui {
class PlainShadow;
class ScrollArea;
class IconButton;
class LinkButton;
class RoundButton;
class RippleAnimation;
class SettingsSlider;
} // namesapce Ui
namespace internal {
constexpr int kInlineItemsMaxPerRow = 5;
constexpr auto kInlineItemsMaxPerRow = 5;
constexpr auto kEmojiSectionCount = 8;
inline DBIEmojiSection EmojiSectionAtIndex(int index) {
return (index < 0 || index >= kEmojiSectionCount) ? dbiesRecent : DBIEmojiSection(index - 1);
}
using InlineResult = InlineBots::Result;
using InlineResults = std::vector<std::unique_ptr<InlineResult>>;
@ -109,38 +117,56 @@ private:
};
class EmojiPanel;
class EmojiPanInner : public TWidget {
class BasicPanInner : public TWidget {
Q_OBJECT
public:
BasicPanInner(QWidget *parent);
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
int getVisibleTop() const {
return _visibleTop;
}
int getVisibleBottom() const {
return _visibleBottom;
}
virtual void refreshRecent() = 0;
virtual void preloadImages() {
}
virtual void hideFinish(bool completely) = 0;
virtual void clearSelection() = 0;
virtual object_ptr<TWidget> createController() = 0;
signals:
void scrollToY(int y);
void disableScroll(bool disabled);
void saveConfigDelayed(int delay);
protected:
virtual int countHeight() = 0;
private:
int _visibleTop = 0;
int _visibleBottom = 0;
};
class EmojiPanInner : public BasicPanInner {
Q_OBJECT
public:
EmojiPanInner(QWidget *parent);
void setMaxHeight(int maxHeight);
void refreshRecent() override;
void hideFinish(bool completely) override;
void clearSelection() override;
object_ptr<TWidget> createController() override;
void hideFinish();
void showEmojiPack(DBIEmojiTab packIndex);
void clearSelection();
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 paintEvent(QPaintEvent *e) override;
void leaveEventHook(QEvent *e) override;
void leaveToChildEvent(QEvent *e, QWidget *child) override;
void enterFromChildEvent(QEvent *e, QWidget *child) override;
void showEmojiSection(DBIEmojiSection section);
DBIEmojiSection currentSection(int yOffset) const;
public slots:
void onShowPicker();
@ -151,31 +177,46 @@ public slots:
signals:
void selected(EmojiPtr emoji);
void switchToStickers();
void scrollToY(int y);
void disableScroll(bool dis);
void needRefreshPanels();
void saveConfigDelayed(int32 delay);
protected:
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void leaveEventHook(QEvent *e) override;
void leaveToChildEvent(QEvent *e, QWidget *child) override;
void enterFromChildEvent(QEvent *e, QWidget *child) override;
bool event(QEvent *e) override;
int countHeight() override;
private:
class Controller;
struct SectionInfo {
int section = 0;
int count = 0;
int top = 0;
int rowsCount = 0;
int rowsTop = 0;
int rowsBottom = 0;
};
template <typename Callback>
bool enumerateSections(Callback callback) const;
SectionInfo sectionInfo(int section) const;
SectionInfo sectionInfoByOffset(int yOffset) const;
void ensureLoaded(int section);
int countSectionTop(int section) const;
void updateSelected();
void setSelected(int newSelected);
int32 _maxHeight;
int countHeight();
void selectEmoji(EmojiPtr emoji);
QRect emojiRect(int tab, int sel);
QRect emojiRect(int section, int sel);
int _visibleTop = 0;
int _visibleBottom = 0;
int _counts[emojiTabCount];
QVector<EmojiPtr> _emojis[emojiTabCount];
int _counts[kEmojiSectionCount];
QVector<EmojiPtr> _emoji[kEmojiSectionCount];
int32 _esize;
@ -194,54 +235,44 @@ struct StickerIcon {
}
StickerIcon(uint64 setId, DocumentData *sticker, int32 pixw, int32 pixh) : setId(setId), sticker(sticker), pixw(pixw), pixh(pixh) {
}
uint64 setId;
uint64 setId = 0;
DocumentData *sticker = nullptr;
int pixw = 0;
int pixh = 0;
};
class StickerPanInner : public TWidget, public InlineBots::Layout::Context, private base::Subscriber {
class StickerPanInner : public BasicPanInner, public InlineBots::Layout::Context, private base::Subscriber {
Q_OBJECT
public:
StickerPanInner(QWidget *parent);
StickerPanInner(QWidget *parent, bool gifs);
void setMaxHeight(int maxHeight);
void refreshRecent() override;
void preloadImages() override;
void hideFinish(bool completely) override;
void clearSelection() override;
object_ptr<TWidget> createController() override;
void hideFinish(bool completely);
void showStickerSet(uint64 setId);
void updateShowingSavedGifs();
bool showSectionIcons() const;
void clearSelection();
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 inlineItemLayoutChanged(const InlineItem *layout) override;
void inlineItemRepaint(const InlineItem *layout) override;
bool inlineItemVisible(const InlineItem *layout) override;
bool ui_isInlineItemBeingChosen();
bool inlineResultsShown() const {
return (_section == Section::Inlines);
}
int countHeight(bool plain = false);
void installedLocally(uint64 setId);
void notInstalledLocally(uint64 setId);
@ -253,10 +284,12 @@ protected:
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void leaveEventHook(QEvent *e) override;
void leaveToChildEvent(QEvent *e, QWidget *child) override;
void enterFromChildEvent(QEvent *e, QWidget *child) override;
int countHeight() override;
private slots:
void onSettings();
@ -275,19 +308,32 @@ signals:
void refreshIcons(bool scrollAnimation);
void emptyInlineRows();
void switchToEmoji();
void scrollToY(int y);
void scrollUpdated();
void disableScroll(bool dis);
void needRefreshPanels();
void saveConfigDelayed(int32 delay);
private:
static constexpr bool kRefreshIconsScrollAnimation = true;
static constexpr bool kRefreshIconsNoAnimation = false;
enum class Section {
Inlines,
Gifs,
Featured,
Stickers,
};
class Controller;
static constexpr auto kRefreshIconsScrollAnimation = true;
static constexpr auto kRefreshIconsNoAnimation = false;
struct SectionInfo {
int section = 0;
int count = 0;
int top = 0;
int rowsCount = 0;
int rowsTop = 0;
int rowsBottom = 0;
};
template <typename Callback>
bool enumerateSections(Callback callback) const;
SectionInfo sectionInfo(int section) const;
SectionInfo sectionInfoByOffset(int yOffset) const;
void updateSelected();
void setSelected(int newSelected, int newSelectedFeaturedSet, int newSelectedFeaturedSetAdd);
@ -317,8 +363,9 @@ private:
return (_section == Section::Inlines) || (_section == Section::Gifs);
}
void paintInlineItems(Painter &p, const QRect &r);
void paintStickers(Painter &p, const QRect &r);
void paintInlineItems(Painter &p, QRect clip);
void paintFeaturedStickers(Painter &p, QRect clip);
void paintStickers(Painter &p, QRect clip);
void paintSticker(Painter &p, Set &set, int y, int index, bool selected, bool deleteSelected);
bool featuredHasAddButton(int index) const;
int featuredContentWidth() const;
@ -334,24 +381,13 @@ private:
void selectEmoji(EmojiPtr emoji);
int stickersLeft() const;
QRect stickerRect(int tab, int sel);
int32 _maxHeight;
int _visibleTop = 0;
int _visibleBottom = 0;
QRect stickerRect(int section, int sel);
Sets _mySets;
Sets _featuredSets;
OrderedSet<uint64> _installedLocallySets;
QList<bool> _custom;
enum class Section {
Inlines,
Gifs,
Featured,
Stickers,
};
Section _section = Section::Stickers;
UserData *_inlineBot;
QString _inlineBotTitle;
@ -387,7 +423,7 @@ private:
int validateExistingInlineRows(const InlineResults &results);
void selectInlineResult(int row, int column);
void removeRecentSticker(int tab, int index);
void removeRecentSticker(int section, int index);
int _selected = -1;
int _pressed = -1;
@ -404,57 +440,6 @@ private:
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);
int wantedY() const {
return _wantedY;
}
void setWantedY(int32 y) {
_wantedY = y;
}
signals:
void deleteClicked(quint64 setId);
void mousePressed();
public slots:
void onDelete();
protected:
void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
private:
void updateText();
int32 _wantedY;
QString _text, _fullText;
uint64 _setId;
bool _special, _deleteVisible;
Ui::IconButton *_delete = nullptr;
};
class EmojiSwitchButton : public Ui::AbstractButton {
public:
EmojiSwitchButton(QWidget *parent, bool toStickers); // otherwise toEmoji
void updateText(const QString &inlineBotUsername = QString());
protected:
void paintEvent(QPaintEvent *e) override;
private:
bool _toStickers = false;
QString _text;
int _textWidth = 0;
};
@ -515,10 +500,7 @@ private slots:
void refreshSavedGifs();
void onWndActiveChanged();
void onScrollEmoji();
void onScrollStickers();
void onSwitch();
void onScroll();
void onDisplaySet(quint64 setId);
void onInstallSet(quint64 setId);
@ -526,10 +508,9 @@ private slots:
void onDelayedHide();
void onRefreshIcons(bool scrollAnimation);
void onRefreshPanels();
void onSaveConfig();
void onSaveConfigDelayed(int32 delay);
void onSaveConfigDelayed(int delay);
void onInlineRequest();
void onEmptyInlineRows();
@ -543,11 +524,45 @@ signals:
void updateStickers();
private:
bool inlineResultsShown() const;
using TabType = EmojiPanTabType;
class Tab {
public:
static constexpr auto kCount = 3;
Tab(TabType type, object_ptr<internal::BasicPanInner> widget);
object_ptr<internal::BasicPanInner> takeWidget();
void returnWidget(object_ptr<internal::BasicPanInner> widget);
TabType type() const {
return _type;
}
gsl::not_null<internal::BasicPanInner*> widget() const {
return _weak;
}
void saveScrollTop();
void saveScrollTop(int scrollTop) {
_scrollTop = scrollTop;
}
int getScrollTop() const {
return _scrollTop;
}
private:
TabType _type = TabType::Emoji;
object_ptr<internal::BasicPanInner> _widget = { nullptr };
QPointer<internal::BasicPanInner> _weak;
int _scrollTop = 0;
};
int marginTop() const;
int marginBottom() const;
int countBottom() const;
void moveByBottom();
void paintSlideFrame(Painter &p, TimeMs ms);
void paintContent(Painter &p);
void performSwitch();
style::margins innerPadding() const;
@ -562,20 +577,23 @@ private:
// This one is allowed to be not rounded.
QRect verticalRect() const;
QImage grabForPanelAnimation();
enum class GrabType {
Panel,
Slide,
};
QImage grabForComplexAnimation(GrabType type);
void startShowAnimation();
void startOpacityAnimation(bool hiding);
void prepareCache();
class Container;
void opacityAnimationCallback();
void hideFinished();
void showStarted();
bool preventAutoHide() const;
void setActiveTab(DBIEmojiTab tab);
void setCurrentTabIcon(DBIEmojiTab tab);
void setActiveSection(DBIEmojiSection section);
void setCurrentSectionIcon(DBIEmojiSection section);
void paintStickerSettingsIcon(Painter &p) const;
void paintFeaturedStickerSetsBadge(Painter &p, int iconLeft) const;
@ -591,18 +609,40 @@ private:
void updateSelected();
void updateIcons();
void prepareTab(int &left, int top, int _width, Ui::IconButton *tab, DBIEmojiTab value);
void updatePanelsPositions(const QVector<internal::EmojiPanel*> &panels, int st);
void prepareSection(int &left, int top, int _width, Ui::IconButton *sectionIcon, DBIEmojiSection section);
void showAll();
void hideAll();
void hideForSliding();
void setWidgetToScrollArea();
void createTabsSlider();
void switchTab();
gsl::not_null<Tab*> getTab(TabType type) {
return &_tabs[static_cast<int>(type)];
}
gsl::not_null<const Tab*> getTab(TabType type) const {
return &_tabs[static_cast<int>(type)];
}
gsl::not_null<Tab*> currentTab() {
return getTab(_currentTabType);
}
gsl::not_null<const Tab*> currentTab() const {
return getTab(_currentTabType);
}
gsl::not_null<internal::EmojiPanInner*> emoji() const {
return static_cast<internal::EmojiPanInner*>(getTab(TabType::Emoji)->widget().get());
}
gsl::not_null<internal::StickerPanInner*> stickers() const {
return static_cast<internal::StickerPanInner*>(getTab(TabType::Stickers)->widget().get());
}
gsl::not_null<internal::StickerPanInner*> gifs() const {
return static_cast<internal::StickerPanInner*>(getTab(TabType::Gifs)->widget().get());
}
int _minTop = 0;
int _minBottom = 0;
int _contentMaxHeight = 0;
int _contentHeight = 0;
int _contentHeightEmoji = 0;
int _contentHeightStickers = 0;
bool _horizontal = false;
int _width = 0;
@ -613,10 +653,11 @@ private:
Animation _a_show;
bool _hiding = false;
bool _hideAfterSlide = false;
QPixmap _cache;
Animation _a_opacity;
QTimer _hideTimer;
bool _inPanelGrab = false;
bool _inComplrexGrab = false;
class SlideAnimation;
std::unique_ptr<SlideAnimation> _slideAnimation;
@ -646,17 +687,12 @@ private:
anim::value _iconSelX;
TimeMs _iconsStartAnim = 0;
bool _emojiShown = true;
bool _shownFromInlineQuery = false;
object_ptr<Ui::ScrollArea> e_scroll;
QPointer<internal::EmojiPanInner> e_inner;
QVector<internal::EmojiPanel*> e_panels;
object_ptr<internal::EmojiSwitchButton> e_switch;
object_ptr<Ui::ScrollArea> s_scroll;
QPointer<internal::StickerPanInner> s_inner;
QVector<internal::EmojiPanel*> s_panels;
object_ptr<internal::EmojiSwitchButton> s_switch;
object_ptr<Ui::SettingsSlider> _tabsSlider = { nullptr };
object_ptr<Ui::PlainShadow> _topShadow;
object_ptr<Ui::PlainShadow> _bottomShadow;
object_ptr<Ui::ScrollArea> _scroll;
std::array<Tab, Tab::kCount> _tabs;
TabType _currentTabType = TabType::Emoji;
uint64 _displayingSetId = 0;
uint64 _removingSetId = 0;
@ -669,7 +705,6 @@ private:
void inlineBotChanged();
int32 showInlineRows(bool newResults);
void recountContentMaxHeight();
bool refreshInlineRows(int32 *added = 0);
UserData *_inlineBot = nullptr;
PeerData *_inlineQueryPeer = nullptr;

View File

@ -24,6 +24,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace Stickers {
constexpr auto kPanPerRow = 5;
void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d);
bool applyArchivedResultFake(); // For testing.
void installLocally(uint64 setId);

View File

@ -109,9 +109,11 @@ stickersSettingsUnreadPosition: point(4px, 5px);
emojiPanMargins: margins(10px, 10px, 10px, 10px);
emojiScroll: ScrollArea(defaultSolidScroll) {
deltat: 48px;
emojiTabs: SettingsSlider(defaultTabsSlider) {
rippleRoundRadius: buttonRadius;
}
emojiScroll: defaultSolidScroll;
emojiRecent: icon {{ "emoji_recent", emojiIconFg }};
emojiRecentActive: icon {{ "emoji_recent", emojiIconFgActive }};
emojiPeople: icon {{ "emoji_people", emojiIconFg }};
@ -128,8 +130,6 @@ emojiObjects: icon {{ "emoji_objects", emojiIconFg }};
emojiObjectsActive: icon {{ "emoji_objects", emojiIconFgActive }};
emojiSymbols: icon {{ "emoji_symbols", emojiIconFg }};
emojiSymbolsActive: icon {{ "emoji_symbols", emojiIconFgActive }};
emojiSavedGifs: icon {{ "emoji_gif", emojiIconFg }};
emojiSavedGifsActive: icon {{ "emoji_gif", emojiIconFgActive }};
emojiCategory: IconButton {
width: 42px;
@ -152,12 +152,11 @@ emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
emojiPanPadding: 12px;
emojiPanSize: size(45px, 41px);
emojiPanWidth: 345px;
emojiPanMinHeight: 206px;
emojiPanMaxHeight: 366px;
emojiPanShowDuration: 200;
emojiPanDuration: 200;
emojiPanShowDuration: 2000;
emojiPanDuration: 2000;
emojiPanHover: windowBgOver;
emojiPanSlideDuration: 200;
emojiPanSlideDuration: 2000;
emojiPanHeader: 42px;
emojiPanHeaderFont: semiboldFont;

View File

@ -48,8 +48,6 @@ using FileKey = quint64;
constexpr char tdfMagic[] = { 'T', 'D', 'F', '$' };
constexpr int tdfMagicLen = sizeof(tdfMagic);
bool _cacheLastSeenWarningSeen = false;
QString toFilePart(FileKey val) {
QString result;
result.reserve(0x10);
@ -556,7 +554,7 @@ enum {
dbiDownloadPath = 0x33,
dbiAutoDownload = 0x34,
dbiSavedGifsLimit = 0x35,
dbiShowingSavedGifs = 0x36,
dbiShowingSavedGifsOld = 0x36,
dbiAutoPlay = 0x37,
dbiAdaptiveForWide = 0x38,
dbiHiddenPinnedMessages = 0x39,
@ -574,7 +572,8 @@ enum {
dbiUseExternalVideoPlayer = 0x49,
dbiDcOptions = 0x4a,
dbiMtpAuthorization = 0x4b,
dbiLastSeenWarningSeen = 0x4c,
dbiLastSeenWarningSeenOld = 0x4c,
dbiAuthSessionData = 0x4d,
dbiEncryptedWithSalt = 333,
dbiEncrypted = 444,
@ -633,17 +632,25 @@ int32 _storageImagesSize = 0, _storageStickersSize = 0, _storageAudiosSize = 0;
bool _mapChanged = false;
int32 _oldMapVersion = 0, _oldSettingsVersion = 0;
enum WriteMapWhen {
WriteMapNow,
WriteMapFast,
WriteMapSoon,
enum class WriteMapWhen {
Now,
Fast,
Soon,
};
void _writeMap(WriteMapWhen when = WriteMapSoon);
std::unique_ptr<AuthSessionData> AuthSessionDataCache;
AuthSessionData &GetAuthSessionDataCache() {
if (!AuthSessionDataCache) {
AuthSessionDataCache = std::make_unique<AuthSessionData>();
}
return *AuthSessionDataCache;
}
void _writeLocations(WriteMapWhen when = WriteMapSoon) {
if (when != WriteMapNow) {
_manager->writeLocations(when == WriteMapFast);
void _writeMap(WriteMapWhen when = WriteMapWhen::Soon);
void _writeLocations(WriteMapWhen when = WriteMapWhen::Soon) {
if (when != WriteMapWhen::Now) {
_manager->writeLocations(when == WriteMapWhen::Fast);
return;
}
if (!_working()) return;
@ -660,7 +667,7 @@ void _writeLocations(WriteMapWhen when = WriteMapSoon) {
if (!_locationsKey) {
_locationsKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
quint32 size = 0;
for (FileLocations::const_iterator i = _fileLocations.cbegin(), e = _fileLocations.cend(); i != e; ++i) {
@ -798,7 +805,7 @@ void _writeReportSpamStatuses() {
if (!_reportSpamStatusesKey) {
_reportSpamStatusesKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
const ReportSpamStatuses &statuses(cReportSpamStatuses());
@ -920,7 +927,6 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
Messenger::Instance().setMtpMainDcId(dcId);
if (userId) {
Messenger::Instance().authSessionCreate(UserId(userId));
AuthSession::Current().data().setLastSeenWarningSeen(_cacheLastSeenWarningSeen);
}
} break;
@ -940,9 +946,6 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
if (!_checkStreamStatus(stream)) return false;
Messenger::Instance().setMtpAuthorization(serialized);
if (AuthSession::Exists()) {
AuthSession::Current().data().setLastSeenWarningSeen(_cacheLastSeenWarningSeen);
}
} break;
case dbiAutoStart: {
@ -1035,12 +1038,10 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
Global::SetIncludeMuted(v == 1);
} break;
case dbiShowingSavedGifs: {
case dbiShowingSavedGifsOld: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
cSetShowingSavedGifs(v == 1);
} break;
case dbiDesktopNotify: {
@ -1090,16 +1091,20 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
Global::SetDialogsWidthRatio(v / 1000000.);
} break;
case dbiLastSeenWarningSeen: {
case dbiLastSeenWarningSeenOld: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
if (AuthSession::Exists()) {
AuthSession::Current().data().setLastSeenWarningSeen(v == 1);
} else {
_cacheLastSeenWarningSeen = (v == 1);
}
GetAuthSessionDataCache().setLastSeenWarningSeen(v == 1);
} break;
case dbiAuthSessionData: {
QByteArray v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
GetAuthSessionDataCache().constructFromSerialized(v);
} break;
case dbiWorkMode: {
@ -1694,16 +1699,18 @@ void _writeUserSettings() {
if (!_userSettingsKey) {
_userSettingsKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
auto recentEmojiPreloadData = cRecentEmojiPreload();
if (recentEmojiPreloadData.isEmpty()) {
recentEmojiPreloadData.reserve(cGetRecentEmoji().size());
for (auto &item : cGetRecentEmoji()) {
recentEmojiPreloadData.reserve(Ui::Emoji::GetRecent().size());
for (auto &item : Ui::Emoji::GetRecent()) {
recentEmojiPreloadData.push_back(qMakePair(item.first->id(), item.second));
}
}
auto userDataInstance = AuthSessionDataCache ? AuthSessionDataCache.get() : AuthSession::Exists() ? &AuthSession::Current().data() : nullptr;
auto userData = userDataInstance ? userDataInstance->serialize() : QByteArray();
uint32 size = 21 * (sizeof(quint32) + sizeof(qint32));
size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark());
@ -1721,6 +1728,9 @@ void _writeUserSettings() {
if (!Global::HiddenPinnedMessages().isEmpty()) {
size += sizeof(quint32) + sizeof(qint32) + Global::HiddenPinnedMessages().size() * (sizeof(PeerId) + sizeof(MsgId));
}
if (!userData.isEmpty()) {
size += sizeof(quint32) + Serialize::bytearraySize(userData);
}
EncryptedDescriptor data(size);
data.stream << quint32(dbiSendKey) << qint32(cCtrlEnter() ? dbiskCtrlEnter : dbiskEnter);
@ -1730,7 +1740,6 @@ void _writeUserSettings() {
data.stream << quint32(dbiReplaceEmojis) << qint32(cReplaceEmojis() ? 1 : 0);
data.stream << quint32(dbiSoundNotify) << qint32(Global::SoundNotify());
data.stream << quint32(dbiIncludeMuted) << qint32(Global::IncludeMuted());
data.stream << quint32(dbiShowingSavedGifs) << qint32(cShowingSavedGifs());
data.stream << quint32(dbiDesktopNotify) << qint32(Global::DesktopNotify());
data.stream << quint32(dbiNotifyView) << qint32(Global::NotifyView());
data.stream << quint32(dbiNativeNotifications) << qint32(Global::NativeNotifications());
@ -1747,9 +1756,10 @@ void _writeUserSettings() {
data.stream << quint32(dbiModerateMode) << qint32(Global::ModerateModeEnabled() ? 1 : 0);
data.stream << quint32(dbiAutoPlay) << qint32(cAutoPlayGif() ? 1 : 0);
data.stream << quint32(dbiDialogsWidthRatio) << qint32(snap(qRound(Global::DialogsWidthRatio() * 1000000), 0, 1000000));
auto lastSeenWarningSeen = (AuthSession::Exists() ? AuthSession::Current().data().lastSeenWarningSeen() : _cacheLastSeenWarningSeen);
data.stream << quint32(dbiLastSeenWarningSeen) << qint32(lastSeenWarningSeen ? 1 : 0);
data.stream << quint32(dbiUseExternalVideoPlayer) << qint32(cUseExternalVideoPlayer());
if (!userData.isEmpty()) {
data.stream << quint32(dbiAuthSessionData) << userData;
}
{
data.stream << quint32(dbiRecentEmoji) << recentEmojiPreloadData;
@ -2055,6 +2065,13 @@ ReadMapState _readMap(const QByteArray &pass) {
_readUserSettings();
_readMtpData();
if (AuthSessionDataCache) {
if (AuthSession::Exists()) {
AuthSession::Current().data().copyFrom(*AuthSessionDataCache);
}
AuthSessionDataCache.reset();
}
LOG(("Map read time: %1").arg(getms() - ms));
if (_oldSettingsVersion < AppVersion) {
writeSettings();
@ -2063,8 +2080,8 @@ ReadMapState _readMap(const QByteArray &pass) {
}
void _writeMap(WriteMapWhen when) {
if (when != WriteMapNow) {
_manager->writeMap(when == WriteMapFast);
if (when != WriteMapWhen::Now) {
_manager->writeMap(when == WriteMapWhen::Fast);
return;
}
_manager->writingMap();
@ -2183,7 +2200,7 @@ void _writeMap(WriteMapWhen when) {
void finish() {
if (_manager) {
_writeMap(WriteMapNow);
_writeMap(WriteMapWhen::Now);
_manager->finish();
_manager->deleteLater();
_manager = 0;
@ -2350,9 +2367,9 @@ void reset() {
_savedGifsKey = 0;
_backgroundKey = _userSettingsKey = _recentHashtagsAndBotsKey = _savedPeersKey = 0;
_oldMapVersion = _oldSettingsVersion = 0;
_cacheLastSeenWarningSeen = false;
AuthSessionDataCache.reset();
_mapChanged = true;
_writeMap(WriteMapNow);
_writeMap(WriteMapWhen::Now);
_writeMtpData();
}
@ -2371,7 +2388,7 @@ void setPasscode(const QByteArray &passcode) {
_passKeyEncrypted = FileWriteDescriptor::prepareEncrypted(passKeyData, PassKey);
_mapChanged = true;
_writeMap(WriteMapNow);
_writeMap(WriteMapWhen::Now);
Global::SetLocalPasscode(!passcode.isEmpty());
Global::RefLocalPasscodeChanged().notify();
@ -2381,7 +2398,7 @@ ReadMapState readMap(const QByteArray &pass) {
ReadMapState result = _readMap(pass);
if (result == ReadMapFailed) {
_mapChanged = true;
_writeMap(WriteMapNow);
_writeMap(WriteMapWhen::Now);
}
return result;
}
@ -2412,7 +2429,7 @@ void writeDrafts(const PeerId &peer, const MessageDraft &localDraft, const Messa
if (i == _draftsMap.cend()) {
i = _draftsMap.insert(peer, genKey());
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
auto msgTags = Ui::FlatTextarea::serializeTagsList(localDraft.textWithTags.tags);
@ -2552,7 +2569,7 @@ void writeDraftCursors(const PeerId &peer, const MessageCursor &msgCursor, const
if (i == _draftCursorsMap.cend()) {
i = _draftCursorsMap.insert(peer, genKey());
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
EncryptedDescriptor data(sizeof(quint64) + sizeof(qint32) * 3);
@ -2585,7 +2602,7 @@ void writeFileLocation(MediaKey location, const FileLocation &local) {
if (i.value().second == local) {
if (i.value().first != location) {
_fileLocationAliases.insert(location, i.value().first);
_writeLocations(WriteMapFast);
_writeLocations(WriteMapWhen::Fast);
}
return;
}
@ -2601,7 +2618,7 @@ void writeFileLocation(MediaKey location, const FileLocation &local) {
}
_fileLocations.insert(location, local);
_fileLocationPairs.insert(local.fname, FileLocationPair(location, local));
_writeLocations(WriteMapFast);
_writeLocations(WriteMapWhen::Fast);
}
FileLocation readFileLocation(MediaKey location, bool check) {
@ -3192,7 +3209,7 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
if (!stickersKey) {
stickersKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
EncryptedDescriptor data(size);
data.stream << quint32(setsCount) << hashToWrite;
@ -3610,7 +3627,7 @@ void writeSavedGifs() {
if (!_savedGifsKey) {
_savedGifsKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
EncryptedDescriptor data(size);
data.stream << quint32(saved.size());
@ -3667,7 +3684,7 @@ void writeBackground(int32 id, const QImage &img) {
if (!_backgroundKey) {
_backgroundKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
quint32 size = sizeof(qint32) + sizeof(quint32) + (bmp.isEmpty() ? 0 : (sizeof(quint32) + bmp.size()));
EncryptedDescriptor data(size);
@ -4028,7 +4045,7 @@ void writeRecentHashtagsAndBots() {
if (!_recentHashtagsAndBotsKey) {
_recentHashtagsAndBotsKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
quint32 size = sizeof(quint32) * 3, writeCnt = 0, searchCnt = 0, botsCnt = cRecentInlineBots().size();
for (RecentHashtagPack::const_iterator i = write.cbegin(), e = write.cend(); i != e; ++i) {
@ -4133,7 +4150,7 @@ void writeSavedPeers() {
if (!_savedPeersKey) {
_savedPeersKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
quint32 size = sizeof(quint32);
for (SavedPeers::const_iterator i = saved.cbegin(); i != saved.cend(); ++i) {
@ -4234,7 +4251,7 @@ void writeTrustedBots() {
if (!_trustedBotsKey) {
_trustedBotsKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
_writeMap(WriteMapWhen::Fast);
}
quint32 size = sizeof(qint32) + _trustedBots.size() * sizeof(quint64);
EncryptedDescriptor data(size);
@ -4586,11 +4603,11 @@ void Manager::writingLocations() {
}
void Manager::mapWriteTimeout() {
_writeMap(WriteMapNow);
_writeMap(WriteMapWhen::Now);
}
void Manager::locationsWriteTimeout() {
_writeLocations(WriteMapNow);
_writeLocations(WriteMapWhen::Now);
}
void Manager::finish() {

View File

@ -15239,23 +15239,23 @@ void Init() {
Items.emplace_back(internal::ComputeId(0xd83c, 0xddff, 0xd83c, 0xddfc), 6, 54, false, false, nullptr, tag);
}
int GetPackCount(DBIEmojiTab tab) {
int GetPackCount(DBIEmojiSection tab) {
switch (tab) {
case dbietPeople: return 291;
case dbietNature: return 159;
case dbietFood: return 86;
case dbietActivity: return 80;
case dbietTravel: return 119;
case dbietObjects: return 173;
case dbietSymbols: return 524;
case dbietRecent: return cGetRecentEmoji().size();
case dbiesPeople: return 291;
case dbiesNature: return 159;
case dbiesFood: return 86;
case dbiesActivity: return 80;
case dbiesTravel: return 119;
case dbiesObjects: return 173;
case dbiesSymbols: return 524;
case dbiesRecent: return GetRecent().size();
}
return 0;
}
EmojiPack GetPack(DBIEmojiTab tab) {
EmojiPack GetPack(DBIEmojiSection tab) {
switch (tab) {
case dbietPeople: {
case dbiesPeople: {
static auto result = EmojiPack();
if (result.isEmpty()) {
result.reserve(291);
@ -15554,7 +15554,7 @@ EmojiPack GetPack(DBIEmojiTab tab) {
return result;
} break;
case dbietNature: {
case dbiesNature: {
static auto result = EmojiPack();
if (result.isEmpty()) {
result.reserve(159);
@ -15721,7 +15721,7 @@ EmojiPack GetPack(DBIEmojiTab tab) {
return result;
} break;
case dbietFood: {
case dbiesFood: {
static auto result = EmojiPack();
if (result.isEmpty()) {
result.reserve(86);
@ -15815,7 +15815,7 @@ EmojiPack GetPack(DBIEmojiTab tab) {
return result;
} break;
case dbietActivity: {
case dbiesActivity: {
static auto result = EmojiPack();
if (result.isEmpty()) {
result.reserve(80);
@ -15903,7 +15903,7 @@ EmojiPack GetPack(DBIEmojiTab tab) {
return result;
} break;
case dbietTravel: {
case dbiesTravel: {
static auto result = EmojiPack();
if (result.isEmpty()) {
result.reserve(119);
@ -16030,7 +16030,7 @@ EmojiPack GetPack(DBIEmojiTab tab) {
return result;
} break;
case dbietObjects: {
case dbiesObjects: {
static auto result = EmojiPack();
if (result.isEmpty()) {
result.reserve(173);
@ -16211,7 +16211,7 @@ EmojiPack GetPack(DBIEmojiTab tab) {
return result;
} break;
case dbietSymbols: {
case dbiesSymbols: {
static auto result = EmojiPack();
if (result.isEmpty()) {
result.reserve(524);
@ -16743,10 +16743,10 @@ EmojiPack GetPack(DBIEmojiTab tab) {
return result;
} break;
case dbietRecent: {
case dbiesRecent: {
auto result = EmojiPack();
result.reserve(cGetRecentEmoji().size());
for (auto &item : cGetRecentEmoji()) {
result.reserve(GetRecent().size());
for (auto &item : GetRecent()) {
result.push_back(item.first);
}
return result;

View File

@ -51,6 +51,8 @@ EmojiPtr FindReplace(const QChar *ch, const QChar *end, int *outLength = nullptr
void Init();
constexpr auto kPostfix = static_cast<ushort>(0xFE0F);
constexpr auto kPanPerRow = 7;
constexpr auto kPanRowsPerPage = 6;
class One {
struct CreationTag {
@ -219,8 +221,8 @@ inline QString Filename(int index = Index()) {
return QString::fromLatin1(EmojiNames[index]);
}
int GetPackCount(DBIEmojiTab tab);
EmojiPack GetPack(DBIEmojiTab tab);
int GetPackCount(DBIEmojiSection tab);
EmojiPack GetPack(DBIEmojiSection tab);
inline void appendPartToResult(QString &result, const QChar *start, const QChar *from, const QChar *to, EntitiesInText *inOutEntities) {
if (to > from) {
@ -289,5 +291,78 @@ inline QString ReplaceInText(const QString &text, EntitiesInText *inOutEntities)
return result;
}
inline RecentEmojiPack &GetRecent() {
if (cRecentEmoji().isEmpty()) {
RecentEmojiPack result;
auto haveAlready = [&result](EmojiPtr emoji) {
for (auto &row : result) {
if (row.first->id() == emoji->id()) {
return true;
}
}
return false;
};
if (!cRecentEmojiPreload().isEmpty()) {
auto preload = cRecentEmojiPreload();
cSetRecentEmojiPreload(RecentEmojiPreload());
result.reserve(preload.size());
for (auto i = preload.cbegin(), e = preload.cend(); i != e; ++i) {
if (auto emoji = Ui::Emoji::Find(i->first)) {
if (!haveAlready(emoji)) {
result.push_back(qMakePair(emoji, i->second));
}
}
}
}
uint64 defaultRecent[] = {
0xD83DDE02LLU,
0xD83DDE18LLU,
0x2764LLU,
0xD83DDE0DLLU,
0xD83DDE0ALLU,
0xD83DDE01LLU,
0xD83DDC4DLLU,
0x263ALLU,
0xD83DDE14LLU,
0xD83DDE04LLU,
0xD83DDE2DLLU,
0xD83DDC8BLLU,
0xD83DDE12LLU,
0xD83DDE33LLU,
0xD83DDE1CLLU,
0xD83DDE48LLU,
0xD83DDE09LLU,
0xD83DDE03LLU,
0xD83DDE22LLU,
0xD83DDE1DLLU,
0xD83DDE31LLU,
0xD83DDE21LLU,
0xD83DDE0FLLU,
0xD83DDE1ELLU,
0xD83DDE05LLU,
0xD83DDE1ALLU,
0xD83DDE4ALLU,
0xD83DDE0CLLU,
0xD83DDE00LLU,
0xD83DDE0BLLU,
0xD83DDE06LLU,
0xD83DDC4CLLU,
0xD83DDE10LLU,
0xD83DDE15LLU,
};
for (auto oldKey : defaultRecent) {
if (result.size() >= kPanPerRow * kPanRowsPerPage) break;
if (auto emoji = Ui::Emoji::FromOldKey(oldKey)) {
if (!haveAlready(emoji)) {
result.push_back(qMakePair(emoji, 1));
}
}
}
cSetRecentEmoji(result);
}
return cRefRecentEmoji();
}
} // namespace Emoji
} // namespace Ui

View File

@ -236,11 +236,12 @@ QImage SettingsSlider::prepareRippleMask(int sectionIndex, const Section &sectio
void SettingsSlider::paintEvent(QPaintEvent *e) {
Painter p(this);
auto clip = e->rect();
auto ms = getms();
auto activeLeft = getCurrentActiveLeft(ms);
p.setFont(_st.labelFont);
enumerateSections([this, &p, activeLeft, ms](Section &section) {
enumerateSections([this, &p, activeLeft, ms, clip](Section &section) {
auto active = 1. - snap(qAbs(activeLeft - section.left) / float64(section.width), 0., 1.);
if (section.ripple) {
auto color = anim::color(_st.rippleBg, _st.rippleBgActive, active);
@ -266,8 +267,10 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
if (tofill) {
p.fillRect(myrtlrect(from, _st.barTop, tofill, _st.barStroke), _st.barFg);
}
p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active));
p.drawTextLeft(section.left + (section.width - section.labelWidth) / 2, _st.labelTop, width(), section.label, section.labelWidth);
if (myrtlrect(section.left, _st.labelTop, section.width, _st.labelFont->height).intersects(clip)) {
p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active));
p.drawTextLeft(section.left + (section.width - section.labelWidth) / 2, _st.labelTop, width(), section.label, section.labelWidth);
}
return true;
});
}

View File

@ -10,6 +10,10 @@ if "%Command%" == "header" (
) else if "%Command%" == "source" (
call :write_source %2
exit /b %errorlevel%
) else if "%Command%" == "" (
echo This is an utility for fast blank module creation.
echo Please provide module path.
exit /b
)
call :write_module %Command%

View File

@ -74,6 +74,7 @@
],
'dependencies': [
'codegen.gyp:codegen_emoji',
'codegen.gyp:codegen_style',
'codegen.gyp:codegen_numbers',
'codegen.gyp:MetaLang',