Merge branch 'master' into player

Conflicts:
	Telegram/SourceFiles/core/observer.h
	Telegram/SourceFiles/mainwindow.h
	Telegram/SourceFiles/media/view/media_clip_playback.cpp
	Telegram/SourceFiles/media/view/media_clip_playback.h
This commit is contained in:
John Preston 2016-09-29 00:16:02 +03:00
commit 0562024444
114 changed files with 743 additions and 1196 deletions

View file

@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,8,0 FILEVERSION 0,10,8,1
PRODUCTVERSION 0,10,8,0 PRODUCTVERSION 0,10,8,1
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.10.8.0" VALUE "FileVersion", "0.10.8.1"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.8.0" VALUE "ProductVersion", "0.10.8.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,8,0 FILEVERSION 0,10,8,1
PRODUCTVERSION 0,10,8,0 PRODUCTVERSION 0,10,8,1
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -43,10 +43,10 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Updater" VALUE "FileDescription", "Telegram Updater"
VALUE "FileVersion", "0.10.8.0" VALUE "FileVersion", "0.10.8.1"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.8.0" VALUE "ProductVersion", "0.10.8.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -42,11 +42,10 @@ ApiWrap::ApiWrap(QObject *parent) : QObject(parent)
void ApiWrap::init() { void ApiWrap::init() {
} }
void ApiWrap::requestMessageData(ChannelData *channel, MsgId msgId, std_::unique_ptr<RequestMessageDataCallback> callback) { void ApiWrap::requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback &&callback) {
MessageDataRequest &req(channel ? _channelMessageDataRequests[channel][msgId] : _messageDataRequests[msgId]); MessageDataRequest &req(channel ? _channelMessageDataRequests[channel][msgId] : _messageDataRequests[msgId]);
if (callback) { if (callback) {
MessageDataRequest::CallbackPtr pcallback(callback.release()); req.callbacks.append(std_::move(callback));
req.callbacks.append(pcallback);
} }
if (!req.req) _messageDataResolveDelayed->call(); if (!req.req) _messageDataResolveDelayed->call();
} }
@ -138,7 +137,7 @@ void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &
for (auto i = requests->begin(); i != requests->cend();) { for (auto i = requests->begin(); i != requests->cend();) {
if (i.value().req == req) { if (i.value().req == req) {
for_const (auto &callback, i.value().callbacks) { for_const (auto &callback, i.value().callbacks) {
callback->call(channel, i.key()); callback(channel, i.key());
} }
i = requests->erase(i); i = requests->erase(i);
} else { } else {

View file

@ -28,8 +28,8 @@ public:
ApiWrap(QObject *parent); ApiWrap(QObject *parent);
void init(); void init();
using RequestMessageDataCallback = SharedCallback<void, ChannelData*, MsgId>; using RequestMessageDataCallback = base::lambda_wrap<void(ChannelData*, MsgId)>;
void requestMessageData(ChannelData *channel, MsgId msgId, std_::unique_ptr<RequestMessageDataCallback> callback); void requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback &&callback);
void requestFullPeer(PeerData *peer); void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer); void requestPeer(PeerData *peer);
@ -82,11 +82,8 @@ private:
void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req);
struct MessageDataRequest { struct MessageDataRequest {
MessageDataRequest() : req(0) { using Callbacks = QList<RequestMessageDataCallback>;
} mtpRequestId req = 0;
typedef SharedCallback<void, ChannelData*, MsgId>::Ptr CallbackPtr;
typedef QList<CallbackPtr> Callbacks;
mtpRequestId req;
Callbacks callbacks; Callbacks callbacks;
}; };
typedef QMap<MsgId, MessageDataRequest> MessageDataRequests; typedef QMap<MsgId, MessageDataRequest> MessageDataRequests;

View file

@ -1874,7 +1874,7 @@ namespace {
} }
History *history(const PeerId &peer) { History *history(const PeerId &peer) {
return ::histories.findOrInsert(peer, 0, 0, 0); return ::histories.findOrInsert(peer);
} }
History *historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead, int32 maxOutboxRead) { History *historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead, int32 maxOutboxRead) {

View file

@ -218,7 +218,6 @@ void Application::singleInstanceChecked() {
Logs::multipleInstances(); Logs::multipleInstances();
} }
Notify::startObservers();
Sandbox::start(); Sandbox::start();
if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) { if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) {
@ -357,8 +356,6 @@ void Application::closeApplication() {
} }
_updateThread = 0; _updateThread = 0;
#endif #endif
Notify::finishObservers();
} }
#ifndef TDESKTOP_DISABLE_AUTOUPDATE #ifndef TDESKTOP_DISABLE_AUTOUPDATE

View file

@ -47,7 +47,7 @@ private:
}; };
class AbstractBox : public LayerWidget { class AbstractBox : public LayerWidget, protected base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -1362,8 +1362,8 @@ RevokePublicLinkBox::RevokePublicLinkBox(base::lambda_unique<void()> &&revokeCal
updateMaxHeight(); updateMaxHeight();
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose())); connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
prepare(); prepare();
} }
@ -1410,10 +1410,16 @@ void RevokePublicLinkBox::mouseReleaseEvent(QMouseEvent *e) {
auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : lng_channels_too_much_public_revoke_confirm_channel; auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : lng_channels_too_much_public_revoke_confirm_channel;
auto text = text_method(lt_link, qsl("telegram.me/") + pressed->userName(), lt_group, pressed->name); auto text = text_method(lt_link, qsl("telegram.me/") + pressed->userName(), lt_group, pressed->name);
weakRevokeConfirmBox = new ConfirmBox(text, lang(lng_channels_too_much_public_revoke)); weakRevokeConfirmBox = new ConfirmBox(text, lang(lng_channels_too_much_public_revoke));
weakRevokeConfirmBox->setConfirmedCallback([this, weak_this = weakThis(), pressed]() { struct Data {
if (!weak_this) return; Data(QPointer<TWidget> &&weakThis, PeerData *pressed) : weakThis(std_::move(weakThis)), pressed(pressed) {
}
QPointer<TWidget> weakThis;
PeerData *pressed;
};
weakRevokeConfirmBox->setConfirmedCallback([this, data = std_::make_unique<Data>(weakThis(), pressed)]() {
if (!data->weakThis) return;
if (_revokeRequestId) return; if (_revokeRequestId) return;
_revokeRequestId = MTP::send(MTPchannels_UpdateUsername(pressed->asChannel()->inputChannel, MTP_string("")), rpcDone(&RevokePublicLinkBox::revokeLinkDone), rpcFail(&RevokePublicLinkBox::revokeLinkFail)); _revokeRequestId = MTP::send(MTPchannels_UpdateUsername(data->pressed->asChannel()->inputChannel, MTP_string("")), rpcDone(&RevokePublicLinkBox::revokeLinkDone), rpcFail(&RevokePublicLinkBox::revokeLinkFail));
}); });
Ui::showLayer(weakRevokeConfirmBox, KeepOtherLayers); Ui::showLayer(weakRevokeConfirmBox, KeepOtherLayers);
} }

View file

@ -29,13 +29,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
BackgroundInner::BackgroundInner() : BackgroundInner::BackgroundInner() :
_bgCount(0), _rows(0), _over(-1), _overDown(-1) { _bgCount(0), _rows(0), _over(-1), _overDown(-1) {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
if (App::cServerBackgrounds().isEmpty()) { if (App::cServerBackgrounds().isEmpty()) {
resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
MTP::send(MTPaccount_GetWallPapers(), rpcDone(&BackgroundInner::gotWallpapers)); MTP::send(MTPaccount_GetWallPapers(), rpcDone(&BackgroundInner::gotWallpapers));
} else { } else {
updateWallpapers(); updateWallpapers();
} }
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
setMouseTracking(true); setMouseTracking(true);
} }

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "abstractbox.h" #include "abstractbox.h"
#include "core/lambda_wrap.h" #include "core/lambda_wrap.h"
class BackgroundInner : public QWidget, public RPCSender { class BackgroundInner : public TWidget, public RPCSender, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -546,7 +546,7 @@ ConfirmInviteBox::ConfirmInviteBox(const QString &title, const MTPChatPhoto &pho
if (!location.isNull()) { if (!location.isNull()) {
_photo = ImagePtr(location); _photo = ImagePtr(location);
if (!_photo->loaded()) { if (!_photo->loaded()) {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); subscribe(FileDownload::ImageLoaded(), [this] { update(); });
_photo->load(); _photo->load();
} }
} }

View file

@ -34,7 +34,7 @@ public:
void updateLink(); void updateLink();
// You can use this instead of connecting to "confirmed()" signal. // You can use this instead of connecting to "confirmed()" signal.
void setConfirmedCallback(base::lambda_wrap<void()> &&callback) { void setConfirmedCallback(base::lambda_unique<void()> &&callback) {
_confirmedCallback = std_::move(callback); _confirmedCallback = std_::move(callback);
} }

View file

@ -106,7 +106,7 @@ ContactsInner::ContactsInner(UserData *bot) : TWidget()
} }
void ContactsInner::init() { void ContactsInner::init() {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); subscribe(FileDownload::ImageLoaded(), [this] { update(); });
connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact())); connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact()));
connect(&_allAdmins, SIGNAL(changed()), this, SLOT(onAllAdminsChanged())); connect(&_allAdmins, SIGNAL(changed()), this, SLOT(onAllAdminsChanged()));
@ -1750,7 +1750,8 @@ MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right()) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right())
, _about(_aboutWidth) , _about(_aboutWidth)
, _aboutHeight(0) { , _aboutHeight(0) {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); subscribe(FileDownload::ImageLoaded(), [this] { update(); });
connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&))); connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)));
connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*))); connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*)));

View file

@ -36,7 +36,7 @@ using MembersAlreadyIn = OrderedSet<UserData*>;
QString cantInviteError(); QString cantInviteError();
class ConfirmBox; class ConfirmBox;
class ContactsInner : public TWidget, public RPCSender { class ContactsInner : public TWidget, public RPCSender, private base::Subscriber {
Q_OBJECT Q_OBJECT
private: private:
@ -269,7 +269,7 @@ private:
}; };
class MembersInner : public TWidget, public RPCSender { class MembersInner : public TWidget, public RPCSender, private base::Subscriber {
Q_OBJECT Q_OBJECT
private: private:

View file

@ -33,10 +33,11 @@ LocalStorageBox::LocalStorageBox() : AbstractBox()
connect(_clear, SIGNAL(clicked()), this, SLOT(onClear())); connect(_clear, SIGNAL(clicked()), this, SLOT(onClear()));
connect(_close, SIGNAL(clicked()), this, SLOT(onClose())); connect(_close, SIGNAL(clicked()), this, SLOT(onClose()));
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int))); connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int)));
connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int))); connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int)));
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
checkLocalStoredCounts(); checkLocalStoredCounts();
prepare(); prepare();
} }

View file

@ -227,9 +227,9 @@ void ShareBox::onMustScrollTo(int top, int bottom) {
to = bottom - (scrollBottom - scrollTop); to = bottom - (scrollBottom - scrollTop);
} }
if (from != to) { if (from != to) {
START_ANIMATION(_scrollAnimation, func([this]() { _scrollAnimation.start([this]() {
scrollArea()->scrollToY(_scrollAnimation.current(scrollArea()->scrollTop())); scrollArea()->scrollToY(_scrollAnimation.current(scrollArea()->scrollTop()));
}), from, to, st::shareScrollDuration, anim::sineInOut); }, from, to, st::shareScrollDuration, anim::sineInOut);
} }
} }
@ -243,8 +243,6 @@ namespace internal {
ShareInner::ShareInner(QWidget *parent) : ScrolledWidget(parent) ShareInner::ShareInner(QWidget *parent) : ScrolledWidget(parent)
, _chatsIndexed(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Add)) { , _chatsIndexed(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Add)) {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
_rowsTop = st::shareRowsTop; _rowsTop = st::shareRowsTop;
_rowHeight = st::shareRowHeight; _rowHeight = st::shareRowHeight;
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
@ -264,7 +262,10 @@ ShareInner::ShareInner(QWidget *parent) : ScrolledWidget(parent)
using UpdateFlag = Notify::PeerUpdate::Flag; using UpdateFlag = Notify::PeerUpdate::Flag;
auto observeEvents = UpdateFlag::NameChanged | UpdateFlag::PhotoChanged; auto observeEvents = UpdateFlag::NameChanged | UpdateFlag::PhotoChanged;
Notify::registerPeerObserver(observeEvents, this, &ShareInner::notifyPeerUpdated); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
} }
void ShareInner::setVisibleTopBottom(int visibleTop, int visibleBottom) { void ShareInner::setVisibleTopBottom(int visibleTop, int visibleBottom) {
@ -437,9 +438,9 @@ void ShareInner::setActive(int active) {
if (active != _active) { if (active != _active) {
auto changeNameFg = [this](int index, style::color from, style::color to) { auto changeNameFg = [this](int index, style::color from, style::color to) {
if (auto chat = getChatAtIndex(index)) { if (auto chat = getChatAtIndex(index)) {
START_ANIMATION(chat->nameFg, func([this, chat] { chat->nameFg.start([this, chat] {
repaintChat(chat->peer); repaintChat(chat->peer);
}), from->c, to->c, st::shareActivateDuration, anim::linear); }, from->c, to->c, st::shareActivateDuration);
} }
}; };
changeNameFg(_active, st::shareNameActiveFg, st::shareNameFg); changeNameFg(_active, st::shareNameActiveFg, st::shareNameFg);
@ -459,16 +460,7 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
auto w = width(); auto w = width();
auto photoLeft = (_rowWidth - (st::sharePhotoRadius * 2)) / 2; auto photoLeft = (_rowWidth - (st::sharePhotoRadius * 2)) / 2;
auto photoTop = st::sharePhotoTop; auto photoTop = st::sharePhotoTop;
if (chat->selection.isNull()) { if (chat->selection.animating()) {
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); p.setRenderHint(QPainter::SmoothPixmapTransform, true);
auto userpicRadius = qRound(WideCacheScale * (st::sharePhotoRadius + (st::sharePhotoSmallRadius - st::sharePhotoRadius) * selectionLevel)); auto userpicRadius = qRound(WideCacheScale * (st::sharePhotoRadius + (st::sharePhotoSmallRadius - st::sharePhotoRadius) * selectionLevel));
auto userpicShift = WideCacheScale * st::sharePhotoRadius - userpicRadius; auto userpicShift = WideCacheScale * st::sharePhotoRadius - userpicRadius;
@ -478,6 +470,15 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
auto from = QRect(QPoint(0, 0), chat->wideUserpicCache.size()); auto from = QRect(QPoint(0, 0), chat->wideUserpicCache.size());
p.drawPixmapLeft(to, w, chat->wideUserpicCache, from); p.drawPixmapLeft(to, w, chat->wideUserpicCache, from);
p.setRenderHint(QPainter::SmoothPixmapTransform, false); p.setRenderHint(QPainter::SmoothPixmapTransform, false);
} else {
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);
} }
if (selectionLevel > 0) { if (selectionLevel > 0) {
@ -516,11 +517,12 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
p.setRenderHint(QPainter::SmoothPixmapTransform, false); p.setRenderHint(QPainter::SmoothPixmapTransform, false);
p.setOpacity(1.); p.setOpacity(1.);
if (chat->nameFg.isNull()) { if (chat->nameFg.animating()) {
p.setPen((index == _active) ? st::shareNameActiveFg : st::shareNameFg);
} else {
p.setPen(chat->nameFg.current()); p.setPen(chat->nameFg.current());
} else {
p.setPen((index == _active) ? st::shareNameActiveFg : st::shareNameFg);
} }
auto nameWidth = (_rowWidth - st::shareColumnSkip); auto nameWidth = (_rowWidth - st::shareColumnSkip);
auto nameLeft = st::shareColumnSkip / 2; auto nameLeft = st::shareColumnSkip / 2;
auto nameTop = photoTop + st::sharePhotoRadius * 2 + st::shareNameTop; auto nameTop = photoTop + st::sharePhotoRadius * 2 + st::shareNameTop;
@ -670,21 +672,21 @@ void ShareInner::changeCheckState(Chat *chat) {
if (chat->selected) { if (chat->selected) {
_selected.insert(chat->peer); _selected.insert(chat->peer);
chat->icons.push_back(Chat::Icon()); chat->icons.push_back(Chat::Icon());
START_ANIMATION(chat->icons.back().fadeIn, func([this, chat] { chat->icons.back().fadeIn.start([this, chat] {
repaintChat(chat->peer); repaintChat(chat->peer);
}), 0, 1, st::shareSelectDuration, anim::linear); }, 0, 1, st::shareSelectDuration);
} else { } else {
_selected.remove(chat->peer); _selected.remove(chat->peer);
prepareWideCheckIconCache(&chat->icons.back()); prepareWideCheckIconCache(&chat->icons.back());
START_ANIMATION(chat->icons.back().fadeOut, func([this, chat] { chat->icons.back().fadeOut.start([this, chat] {
removeFadeOutedIcons(chat);
repaintChat(chat->peer); repaintChat(chat->peer);
}), 1, 0, st::shareSelectDuration, anim::linear); removeFadeOutedIcons(chat); // this call can destroy current lambda
}, 1, 0, st::shareSelectDuration);
} }
prepareWideUserpicCache(chat); prepareWideUserpicCache(chat);
START_ANIMATION(chat->selection, func([this, chat] { chat->selection.start([this, chat] {
repaintChat(chat->peer); repaintChat(chat->peer);
}), chat->selected ? 0 : 1, chat->selected ? 1 : 0, st::shareSelectDuration, anim_bumpy); }, chat->selected ? 0 : 1, chat->selected ? 1 : 0, st::shareSelectDuration, anim_bumpy);
if (chat->selected) { if (chat->selected) {
setActive(chatIndex(chat->peer)); setActive(chatIndex(chat->peer));
} }
@ -692,9 +694,9 @@ void ShareInner::changeCheckState(Chat *chat) {
} }
void ShareInner::removeFadeOutedIcons(Chat *chat) { void ShareInner::removeFadeOutedIcons(Chat *chat) {
while (!chat->icons.empty() && chat->icons.front().fadeIn.isNull() && chat->icons.front().fadeOut.isNull()) { while (!chat->icons.empty() && !chat->icons.front().fadeIn.animating() && !chat->icons.front().fadeOut.animating()) {
if (chat->icons.size() > 1 || !chat->selected) { if (chat->icons.size() > 1 || !chat->selected) {
chat->icons.pop_front(); chat->icons.erase(chat->icons.begin());
} else { } else {
break; break;
} }
@ -1016,18 +1018,6 @@ void shareGameScoreFromItem(HistoryItem *item) {
Ui::showLayer(new ShareBox(std_::move(copyCallback), std_::move(submitCallback))); Ui::showLayer(new ShareBox(std_::move(copyCallback), std_::move(submitCallback)));
} }
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 } // namespace
void shareGameScoreByHash(const QString &hash) { void shareGameScoreByHash(const QString &hash) {
@ -1062,7 +1052,13 @@ void shareGameScoreByHash(const QString &hash) {
} else if (App::api()) { } else if (App::api()) {
auto channel = channelId ? App::channelLoaded(channelId) : nullptr; auto channel = channelId ? App::channelLoaded(channelId) : nullptr;
if (channel || !channelId) { if (channel || !channelId) {
App::api()->requestMessageData(channel, msgId, std_::make_unique<GameMessageResolvedCallback>()); App::api()->requestMessageData(channel, msgId, [](ChannelData *channel, MsgId msgId) {
if (auto item = App::histItemById(channel, msgId)) {
shareGameScoreFromItem(item);
} else {
Ui::showLayer(new InformBox(lang(lng_edit_deleted)));
}
});
} }
} }
} }

View file

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "abstractbox.h" #include "abstractbox.h"
#include "core/lambda_wrap.h" #include "core/lambda_wrap.h"
#include "core/observer.h" #include "core/observer.h"
#include "core/vector_of_moveable.h"
namespace Dialogs { namespace Dialogs {
class Row; class Row;
@ -107,7 +108,7 @@ private:
namespace internal { namespace internal {
class ShareInner : public ScrolledWidget, public RPCSender, public Notify::Observer { class ShareInner : public ScrolledWidget, public RPCSender, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:
@ -163,7 +164,7 @@ private:
FloatAnimation fadeOut; FloatAnimation fadeOut;
QPixmap wideCheckCache; QPixmap wideCheckCache;
}; };
QList<Icon> icons; std_::vector_of_moveable<Icon> icons;
}; };
void paintChat(Painter &p, Chat *chat, int index); void paintChat(Painter &p, Chat *chat, int index);
void updateChat(PeerData *peer); void updateChat(PeerData *peer);

View file

@ -41,7 +41,6 @@ constexpr int kArchivedLimitPerPage = 30;
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : ScrolledWidget() StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : ScrolledWidget()
, _input(set) { , _input(set) {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
switch (set.type()) { switch (set.type()) {
case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break; case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break;
case mtpc_inputStickerSetShortName: _setShortName = qs(set.c_inputStickerSetShortName().vshort_name); break; case mtpc_inputStickerSetShortName: _setShortName = qs(set.c_inputStickerSetShortName().vshort_name); break;
@ -49,6 +48,8 @@ StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : ScrolledWidget
MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&StickerSetInner::gotSet), rpcFail(&StickerSetInner::failedSet)); MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&StickerSetInner::gotSet), rpcFail(&StickerSetInner::failedSet));
App::main()->updateStickers(); App::main()->updateStickers();
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
setMouseTracking(true); setMouseTracking(true);
_previewTimer.setSingleShot(true); _previewTimer.setSingleShot(true);
@ -62,8 +63,8 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_selected = -1; _selected = -1;
setCursor(style::cur_default); setCursor(style::cur_default);
if (set.type() == mtpc_messages_stickerSet) { if (set.type() == mtpc_messages_stickerSet) {
auto &d(set.c_messages_stickerSet()); auto &d = set.c_messages_stickerSet();
auto &v(d.vdocuments.c_vector().v); auto &v = d.vdocuments.c_vector().v;
_pack.reserve(v.size()); _pack.reserve(v.size());
_packOvers.reserve(v.size()); _packOvers.reserve(v.size());
for (int i = 0, l = v.size(); i < l; ++i) { for (int i = 0, l = v.size(); i < l; ++i) {
@ -247,13 +248,13 @@ void StickerSetInner::updateSelected() {
void StickerSetInner::startOverAnimation(int index, float64 from, float64 to) { void StickerSetInner::startOverAnimation(int index, float64 from, float64 to) {
if (index >= 0 && index < _packOvers.size()) { if (index >= 0 && index < _packOvers.size()) {
START_ANIMATION(_packOvers[index], func([this, index]() { _packOvers[index].start([this, index] {
int row = index / StickerPanPerRow; int row = index / StickerPanPerRow;
int column = index % StickerPanPerRow; int column = index % StickerPanPerRow;
int left = st::stickersPadding.left() + column * st::stickersSize.width(); int left = st::stickersPadding.left() + column * st::stickersSize.width();
int top = st::stickersPadding.top() + row * st::stickersSize.height(); int top = st::stickersPadding.top() + row * st::stickersSize.height();
rtlupdate(left, top, st::stickersSize.width(), st::stickersSize.height()); rtlupdate(left, top, st::stickersSize.width(), st::stickersSize.height());
}), from, to, st::emojiPanDuration, anim::linear); }, from, to, st::emojiPanDuration);
} }
} }
@ -515,7 +516,7 @@ StickersInner::StickersInner(const Stickers::Order &archivedIds) : ScrolledWidge
} }
void StickersInner::setup() { void StickersInner::setup() {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(onImageLoaded())); subscribe(FileDownload::ImageLoaded(), [this] { update(); });
setMouseTracking(true); setMouseTracking(true);
} }

View file

@ -21,10 +21,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "abstractbox.h" #include "abstractbox.h"
#include "core/vector_of_moveable.h"
class ConfirmBox; class ConfirmBox;
class StickerSetInner : public ScrolledWidget, public RPCSender { class StickerSetInner : public ScrolledWidget, public RPCSender, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:
@ -69,7 +70,7 @@ private:
return (_setFlags & MTPDstickerSet::Flag::f_masks); return (_setFlags & MTPDstickerSet::Flag::f_masks);
} }
QVector<FloatAnimation> _packOvers; std_::vector_of_moveable<FloatAnimation> _packOvers;
StickerPack _pack; StickerPack _pack;
StickersByEmojiMap _emoji; StickersByEmojiMap _emoji;
bool _loaded = false; bool _loaded = false;
@ -206,7 +207,7 @@ int32 stickerPacksCount(bool includeDisabledOfficial = false);
namespace internal { namespace internal {
class StickersInner : public ScrolledWidget, public RPCSender { class StickersInner : public ScrolledWidget, public RPCSender, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -20,6 +20,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include <string>
#include <exception>
#include <QtCore/QReadWriteLock>
#include <ctime>
#ifndef OS_MAC_OLD
#include <memory>
#endif // OS_MAC_OLD
template <typename T> template <typename T>
void deleteAndMark(T *&link) { void deleteAndMark(T *&link) {
delete link; delete link;
@ -259,13 +270,6 @@ typedef float float32;
typedef double float64; typedef double float64;
#endif #endif
#include <string>
#include <exception>
#include <QtCore/QReadWriteLock>
#include <ctime>
using std::string; using std::string;
using std::exception; using std::exception;
#ifdef OS_MAC_OLD #ifdef OS_MAC_OLD
@ -1035,13 +1039,15 @@ struct ComponentWrapStruct {
// global scope, so it will be filled by zeros from the start // global scope, so it will be filled by zeros from the start
ComponentWrapStruct() { ComponentWrapStruct() {
} }
ComponentWrapStruct(int size, ComponentConstruct construct, ComponentDestruct destruct, ComponentMove move) ComponentWrapStruct(std::size_t size, std::size_t align, ComponentConstruct construct, ComponentDestruct destruct, ComponentMove move)
: Size(size) : Size(size)
, Align(align)
, Construct(construct) , Construct(construct)
, Destruct(destruct) , Destruct(destruct)
, Move(move) { , Move(move) {
} }
int Size; std::size_t Size;
std::size_t Align;
ComponentConstruct Construct; ComponentConstruct Construct;
ComponentDestruct Destruct; ComponentDestruct Destruct;
ComponentMove Move; ComponentMove Move;
@ -1058,6 +1064,7 @@ extern QAtomicInt ComponentIndexLast;
template <typename Type> template <typename Type>
struct BaseComponent { struct BaseComponent {
BaseComponent() { BaseComponent() {
static_assert(alignof(Type) <= alignof(SmallestSizeType), "Components should align to a pointer!");
} }
BaseComponent(const BaseComponent &other) = delete; BaseComponent(const BaseComponent &other) = delete;
BaseComponent &operator=(const BaseComponent &other) = delete; BaseComponent &operator=(const BaseComponent &other) = delete;
@ -1075,8 +1082,11 @@ struct BaseComponent {
t_assert(last < 64); t_assert(last < 64);
if (_index.testAndSetOrdered(0, last + 1)) { if (_index.testAndSetOrdered(0, last + 1)) {
ComponentWraps[last] = ComponentWrapStruct( ComponentWraps[last] = ComponentWrapStruct(
CeilDivideMinimumOne<sizeof(Type), sizeof(uint64)>::Result * sizeof(uint64), CeilDivideMinimumOne<sizeof(Type), sizeof(SmallestSizeType)>::Result * sizeof(SmallestSizeType),
Type::ComponentConstruct, Type::ComponentDestruct, Type::ComponentMove); alignof(Type),
Type::ComponentConstruct,
Type::ComponentDestruct,
Type::ComponentMove);
} }
break; break;
} }
@ -1088,6 +1098,8 @@ struct BaseComponent {
} }
protected: protected:
using SmallestSizeType = void*;
static void ComponentConstruct(void *location, Composer *composer) { static void ComponentConstruct(void *location, Composer *composer) {
new (location) Type(); new (location) Type();
} }
@ -1102,7 +1114,6 @@ protected:
class ComposerMetadata { class ComposerMetadata {
public: public:
ComposerMetadata(uint64 mask) : size(0), last(64), _mask(mask) { ComposerMetadata(uint64 mask) : size(0), last(64), _mask(mask) {
for (int i = 0; i < 64; ++i) { for (int i = 0; i < 64; ++i) {
uint64 m = (1ULL << i); uint64 m = (1ULL << i);
@ -1147,15 +1158,13 @@ const ComposerMetadata *GetComposerMetadata(uint64 mask);
class Composer { class Composer {
public: public:
Composer(uint64 mask = 0) : _data(zerodata()) { Composer(uint64 mask = 0) : _data(zerodata()) {
if (mask) { if (mask) {
const ComposerMetadata *meta = GetComposerMetadata(mask); const ComposerMetadata *meta = GetComposerMetadata(mask);
int size = sizeof(meta) + meta->size; int size = sizeof(meta) + meta->size;
void *data = operator new(size);
if (!data) { // terminate if we can't allocate memory auto data = operator new(size);
throw "Can't allocate memory!"; t_assert(data != nullptr);
}
_data = data; _data = data;
_meta() = meta; _meta() = meta;
@ -1163,7 +1172,13 @@ public:
int offset = meta->offsets[i]; int offset = meta->offsets[i];
if (offset >= 0) { if (offset >= 0) {
try { try {
ComponentWraps[i].Construct(_dataptrunsafe(offset), this); auto constructAt = _dataptrunsafe(offset);
#ifndef OS_MAC_OLD
auto space = ComponentWraps[i].Size;
auto alignedAt = std::align(ComponentWraps[i].Align, space, constructAt, space);
t_assert(alignedAt == constructAt);
#endif // OS_MAC_OLD
ComponentWraps[i].Construct(constructAt, this);
} catch (...) { } catch (...) {
while (i > 0) { while (i > 0) {
--i; --i;
@ -1182,7 +1197,7 @@ public:
Composer &operator=(const Composer &other) = delete; Composer &operator=(const Composer &other) = delete;
~Composer() { ~Composer() {
if (_data != zerodata()) { if (_data != zerodata()) {
const ComposerMetadata *meta = _meta(); auto meta = _meta();
for (int i = 0; i < meta->last; ++i) { for (int i = 0; i < meta->last; ++i) {
int offset = meta->offsets[i]; int offset = meta->offsets[i];
if (offset >= 0) { if (offset >= 0) {
@ -1213,7 +1228,7 @@ protected:
Composer tmp(mask); Composer tmp(mask);
tmp.swap(*this); tmp.swap(*this);
if (_data != zerodata() && tmp._data != zerodata()) { if (_data != zerodata() && tmp._data != zerodata()) {
const ComposerMetadata *meta = _meta(), *wasmeta = tmp._meta(); auto meta = _meta(), wasmeta = tmp._meta();
for (int i = 0; i < meta->last; ++i) { for (int i = 0; i < meta->last; ++i) {
int offset = meta->offsets[i], wasoffset = wasmeta->offsets[i]; int offset = meta->offsets[i], wasoffset = wasmeta->offsets[i];
if (offset >= 0 && wasoffset >= 0) { if (offset >= 0 && wasoffset >= 0) {
@ -1252,103 +1267,3 @@ private:
} }
}; };
template <typename R, typename... Args>
class SharedCallback {
public:
virtual R call(Args... args) const = 0;
virtual ~SharedCallback() {
}
using Ptr = QSharedPointer<SharedCallback<R, Args...>>;
};
template <typename R, typename... Args>
class FunctionImplementation {
public:
virtual R call(Args... args) = 0;
virtual void destroy() { delete this; }
virtual ~FunctionImplementation() {}
};
template <typename R, typename... Args>
class NullFunctionImplementation : public FunctionImplementation<R, Args...> {
public:
R call(Args... args) override { return R(); }
void destroy() override {}
static NullFunctionImplementation<R, Args...> SharedInstance;
};
template <typename R, typename... Args>
NullFunctionImplementation<R, Args...> NullFunctionImplementation<R, Args...>::SharedInstance;
template <typename R, typename... Args>
class Function {
public:
Function() : _implementation(nullImpl()) {}
Function(FunctionImplementation<R, Args...> *implementation) : _implementation(implementation) {}
Function(const Function<R, Args...> &other) = delete;
Function<R, Args...> &operator=(const Function<R, Args...> &other) = delete;
Function(Function<R, Args...> &&other) : _implementation(other._implementation) {
other._implementation = nullImpl();
}
Function<R, Args...> &operator=(Function<R, Args...> &&other) {
std::swap(_implementation, other._implementation);
return *this;
}
bool isNull() const {
return (_implementation == nullImpl());
}
R call(Args... args) { return _implementation->call(args...); }
~Function() {
if (_implementation) {
_implementation->destroy();
_implementation = nullptr;
}
deleteAndMark(_implementation);
}
private:
static FunctionImplementation<R, Args...> *nullImpl() {
return &NullFunctionImplementation<R, Args...>::SharedInstance;
}
FunctionImplementation<R, Args...> *_implementation;
};
template <typename R, typename... Args>
class WrappedFunction : public FunctionImplementation<R, Args...> {
public:
using Method = R(*)(Args... args);
WrappedFunction(Method method) : _method(method) {}
R call(Args... args) override { return (*_method)(args...); }
private:
Method _method;
};
template <typename R, typename... Args>
inline Function<R, Args...> func(R(*method)(Args... args)) {
return Function<R, Args...>(new WrappedFunction<R, Args...>(method));
}
template <typename O, typename I, typename R, typename... Args>
class ObjectFunction : public FunctionImplementation<R, Args...> {
public:
using Method = R(I::*)(Args... args);
ObjectFunction(O *obj, Method method) : _obj(obj), _method(method) {}
R call(Args... args) override { return (_obj->*_method)(args...); }
private:
O *_obj;
Method _method;
};
template <typename O, typename I, typename R, typename... Args>
inline Function<R, Args...> func(O *obj, R(I::*method)(Args...)) {
return Function<R, Args...>(new ObjectFunction<O, I, R, Args...>(obj, method));
}

View file

@ -20,6 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#ifndef OS_MAC_OLD
#include <memory>
#endif // OS_MAC_OLD
namespace base { namespace base {
namespace internal { namespace internal {
@ -50,7 +54,7 @@ struct lambda_wrap_helper_base {
const call_type call; const call_type call;
const destruct_type destruct; const destruct_type destruct;
static constexpr size_t kFullStorageSize = 40U; static constexpr size_t kFullStorageSize = sizeof(void*) + 24U;
static constexpr size_t kStorageSize = kFullStorageSize - sizeof(void*); static constexpr size_t kStorageSize = kFullStorageSize - sizeof(void*);
template <typename Lambda> template <typename Lambda>
@ -90,43 +94,47 @@ const lambda_wrap_empty<Return, Args...> lambda_wrap_empty<Return, Args...>::ins
template <typename Lambda, typename IsLarge, typename Return, typename ...Args> struct lambda_wrap_helper_move_impl; template <typename Lambda, typename IsLarge, typename Return, typename ...Args> struct lambda_wrap_helper_move_impl;
template <typename Lambda, typename Return, typename ...Args> //
struct lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> { // Disable large lambda support.
using JustLambda = std_::decay_simple_t<Lambda>; // If you really need it, just store data in some std_::unique_ptr<struct>.
using LambdaPtr = std_::unique_ptr<JustLambda>; //
using Parent = lambda_wrap_helper_base<Return, Args...>; //template <typename Lambda, typename Return, typename ...Args>
static void construct_move_other_method(void *lambda, void *source) { //struct lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> {
auto source_lambda = static_cast<LambdaPtr*>(source); // using JustLambda = std_::decay_simple_t<Lambda>;
new (lambda) LambdaPtr(std_::move(*source_lambda)); // using LambdaPtr = std_::unique_ptr<JustLambda>;
} // using Parent = lambda_wrap_helper_base<Return, Args...>;
static void construct_move_lambda_method(void *lambda, void *source) { // static void construct_move_other_method(void *lambda, void *source) {
auto source_lambda = static_cast<JustLambda*>(source); // auto source_lambda = static_cast<LambdaPtr*>(source);
new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<JustLambda&&>(*source_lambda))); // new (lambda) LambdaPtr(std_::move(*source_lambda));
} // }
static Return call_method(const void *lambda, Args... args) { // static void construct_move_lambda_method(void *lambda, void *source) {
return (**static_cast<const LambdaPtr*>(lambda))(std_::forward<Args>(args)...); // auto source_lambda = static_cast<JustLambda*>(source);
} // new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<JustLambda&&>(*source_lambda)));
static void destruct_method(const void *lambda) { // }
static_cast<const LambdaPtr*>(lambda)->~LambdaPtr(); // static Return call_method(const void *lambda, Args... args) {
} // return (**static_cast<const LambdaPtr*>(lambda))(std_::forward<Args>(args)...);
lambda_wrap_helper_move_impl() : Parent( // }
&Parent::bad_construct_copy, // static void destruct_method(const void *lambda) {
&lambda_wrap_helper_move_impl::construct_move_other_method, // static_cast<const LambdaPtr*>(lambda)->~LambdaPtr();
&lambda_wrap_helper_move_impl::call_method, // }
&lambda_wrap_helper_move_impl::destruct_method) { // lambda_wrap_helper_move_impl() : Parent(
} // &Parent::bad_construct_copy,
// &lambda_wrap_helper_move_impl::construct_move_other_method,
protected: // &lambda_wrap_helper_move_impl::call_method,
lambda_wrap_helper_move_impl( // &lambda_wrap_helper_move_impl::destruct_method) {
typename Parent::construct_copy_other_type construct_copy_other // }
) : Parent( //
construct_copy_other, //protected:
&lambda_wrap_helper_move_impl::construct_move_other_method, // lambda_wrap_helper_move_impl(
&lambda_wrap_helper_move_impl::call_method, // typename Parent::construct_copy_other_type construct_copy_other
&lambda_wrap_helper_move_impl::destruct_method) { // ) : Parent(
} // construct_copy_other,
// &lambda_wrap_helper_move_impl::construct_move_other_method,
}; // &lambda_wrap_helper_move_impl::call_method,
// &lambda_wrap_helper_move_impl::destruct_method) {
// }
//
//};
template <typename Lambda, typename Return, typename ...Args> template <typename Lambda, typename Return, typename ...Args>
struct lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> { struct lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> {
@ -137,6 +145,12 @@ struct lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> :
new (lambda) JustLambda(static_cast<JustLambda&&>(*source_lambda)); new (lambda) JustLambda(static_cast<JustLambda&&>(*source_lambda));
} }
static void construct_move_lambda_method(void *lambda, void *source) { static void construct_move_lambda_method(void *lambda, void *source) {
static_assert(alignof(JustLambda) <= alignof(void*), "Bad lambda alignment.");
#ifndef OS_MAC_OLD
auto space = sizeof(JustLambda);
auto aligned = std::align(alignof(JustLambda), space, lambda, space);
t_assert(aligned == lambda);
#endif // OS_MAC_OLD
auto source_lambda = static_cast<JustLambda*>(source); auto source_lambda = static_cast<JustLambda*>(source);
new (lambda) JustLambda(static_cast<JustLambda&&>(*source_lambda)); new (lambda) JustLambda(static_cast<JustLambda&&>(*source_lambda));
} }
@ -177,23 +191,27 @@ const lambda_wrap_helper_move<Lambda, Return, Args...> lambda_wrap_helper_move<L
template <typename Lambda, typename IsLarge, typename Return, typename ...Args> struct lambda_wrap_helper_copy_impl; template <typename Lambda, typename IsLarge, typename Return, typename ...Args> struct lambda_wrap_helper_copy_impl;
template <typename Lambda, typename Return, typename ...Args> //
struct lambda_wrap_helper_copy_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> { // Disable large lambda support.
using JustLambda = std_::decay_simple_t<Lambda>; // If you really need it, just store data in some QSharedPointer<struct>.
using LambdaPtr = std_::unique_ptr<JustLambda>; //
using Parent = lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...>; //template <typename Lambda, typename Return, typename ...Args>
static void construct_copy_other_method(void *lambda, const void *source) { //struct lambda_wrap_helper_copy_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> {
auto source_lambda = static_cast<const LambdaPtr*>(source); // using JustLambda = std_::decay_simple_t<Lambda>;
new (lambda) LambdaPtr(std_::make_unique<JustLambda>(*source_lambda->get())); // using LambdaPtr = std_::unique_ptr<JustLambda>;
} // using Parent = lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...>;
static void construct_copy_lambda_method(void *lambda, const void *source) { // static void construct_copy_other_method(void *lambda, const void *source) {
auto source_lambda = static_cast<const JustLambda*>(source); // auto source_lambda = static_cast<const LambdaPtr*>(source);
new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<const JustLambda &>(*source_lambda))); // new (lambda) LambdaPtr(std_::make_unique<JustLambda>(*source_lambda->get()));
} // }
lambda_wrap_helper_copy_impl() : Parent(&lambda_wrap_helper_copy_impl::construct_copy_other_method) { // static void construct_copy_lambda_method(void *lambda, const void *source) {
} // auto source_lambda = static_cast<const JustLambda*>(source);
// new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<const JustLambda &>(*source_lambda)));
}; // }
// lambda_wrap_helper_copy_impl() : Parent(&lambda_wrap_helper_copy_impl::construct_copy_other_method) {
// }
//
//};
template <typename Lambda, typename Return, typename ...Args> template <typename Lambda, typename Return, typename ...Args>
struct lambda_wrap_helper_copy_impl<Lambda, std_::false_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> { struct lambda_wrap_helper_copy_impl<Lambda, std_::false_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> {
@ -204,6 +222,12 @@ struct lambda_wrap_helper_copy_impl<Lambda, std_::false_type, Return, Args...> :
new (lambda) JustLambda(static_cast<const JustLambda &>(*source_lambda)); new (lambda) JustLambda(static_cast<const JustLambda &>(*source_lambda));
} }
static void construct_copy_lambda_method(void *lambda, const void *source) { static void construct_copy_lambda_method(void *lambda, const void *source) {
static_assert(alignof(JustLambda) <= alignof(void*), "Bad lambda alignment.");
#ifndef OS_MAC_OLD
auto space = sizeof(JustLambda);
auto aligned = std::align(alignof(JustLambda), space, lambda, space);
t_assert(aligned == lambda);
#endif // OS_MAC_OLD
auto source_lambda = static_cast<const JustLambda*>(source); auto source_lambda = static_cast<const JustLambda*>(source);
new (lambda) JustLambda(static_cast<const JustLambda &>(*source_lambda)); new (lambda) JustLambda(static_cast<const JustLambda &>(*source_lambda));
} }
@ -356,7 +380,7 @@ public:
auto temp = other; auto temp = other;
this->helper_->destruct(this->storage_); this->helper_->destruct(this->storage_);
this->helper_ = &internal::lambda_wrap_helper_copy<Lambda, Return, Args...>::instance; this->helper_ = &internal::lambda_wrap_helper_copy<Lambda, Return, Args...>::instance;
internal::lambda_wrap_helper_copy<Lambda, Return, Args...>::construct_move_lambda_method(this->storage_, &other); internal::lambda_wrap_helper_copy<Lambda, Return, Args...>::construct_copy_lambda_method(this->storage_, &other);
return *this; return *this;
} }
@ -373,48 +397,20 @@ public:
} // namespace base } // namespace base
// While we still use Function<> // While we still use rpcDone() and rpcFail()
#include "mtproto/rpc_sender.h"
template <typename FunctionType> template <typename FunctionType>
struct LambdaFunctionHelper; struct LambdaUniqueHelper;
template <typename Lambda, typename R, typename ...Args> template <typename Lambda, typename R, typename ...Args>
struct LambdaFunctionHelper<R(Lambda::*)(Args...) const> { struct LambdaUniqueHelper<R(Lambda::*)(Args...) const> {
using FunctionType = Function<R, Args...>;
using UniqueType = base::lambda_unique<R(Args...)>; using UniqueType = base::lambda_unique<R(Args...)>;
}; };
template <typename FunctionType> template <typename FunctionType>
using LambdaGetFunction = typename LambdaFunctionHelper<FunctionType>::FunctionType; using LambdaGetUnique = typename LambdaUniqueHelper<FunctionType>::UniqueType;
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...> func_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 func_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}
// While we still use rpcDone() and rpcFail()
#include "mtproto/rpc_sender.h"
template <typename Base, typename FunctionType> template <typename Base, typename FunctionType>
class RPCHandlerImplementation : public Base { class RPCHandlerImplementation : public Base {

View file

@ -21,99 +21,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h" #include "stdafx.h"
#include "core/observer.h" #include "core/observer.h"
namespace Notify {
namespace internal {
namespace {
struct StartCallbackData {
void *that;
StartCallback call;
};
struct FinishCallbackData {
void *that;
FinishCallback call;
};
struct UnregisterCallbackData {
void *that;
UnregisterCallback call;
};
using StartCallbacksList = QVector<StartCallbackData>;
using FinishCallbacksList = QVector<FinishCallbackData>;
NeverFreedPointer<StartCallbacksList> StartCallbacks;
NeverFreedPointer<FinishCallbacksList> FinishCallbacks;
UnregisterCallbackData UnregisterCallbacks[256]/* = { nullptr }*/;
ObservedEvent LastRegisteredEvent/* = 0*/;
} // namespace
} // namespace internal
void startObservers() {
if (!internal::StartCallbacks) return;
for (auto &callback : *internal::StartCallbacks) {
callback.call(callback.that);
}
}
void finishObservers() {
if (!internal::FinishCallbacks) return;
for (auto &callback : *internal::FinishCallbacks) {
callback.call(callback.that);
}
internal::StartCallbacks.clear();
internal::FinishCallbacks.clear();
}
namespace internal {
BaseObservedEventRegistrator::BaseObservedEventRegistrator(void *that
, StartCallback startCallback
, FinishCallback finishCallback
, UnregisterCallback unregisterCallback) {
_event = LastRegisteredEvent++;
StartCallbacks.makeIfNull();
StartCallbacks->push_back({ that, startCallback });
FinishCallbacks.makeIfNull();
FinishCallbacks->push_back({ that, finishCallback });
UnregisterCallbacks[_event] = { that, unregisterCallback };
}
} // namespace internal
// Observer base interface.
Observer::~Observer() {
for_const (auto connection, _connections) {
unregisterObserver(connection);
}
}
void Observer::observerRegistered(ConnectionId connection) {
_connections.push_back(connection);
}
void unregisterObserver(ConnectionId connection) {
auto event = static_cast<internal::ObservedEvent>(connection >> 24);
auto connectionIndex = int(connection & 0x00FFFFFFU) - 1;
auto &callback = internal::UnregisterCallbacks[event];
if (connectionIndex >= 0 && callback.call && callback.that) {
callback.call(callback.that, connectionIndex);
}
}
namespace internal {
void observerRegisteredDefault(Observer *observer, ConnectionId connection) {
observer->observerRegistered(connection);
}
} // namespace internal
} // namespace Notify
namespace base { namespace base {
namespace internal { namespace internal {
namespace { namespace {

View file

@ -22,230 +22,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/vector_of_moveable.h" #include "core/vector_of_moveable.h"
namespace Notify {
using ConnectionId = uint32;
// startObservers() must be called after main() started (not in a global variable constructor).
// finishObservers() must be called before main() finished (not in a global variable destructor).
void startObservers();
void finishObservers();
using StartObservedEventCallback = void(*)();
using FinishObservedEventCallback = void(*)();
namespace internal {
using ObservedEvent = uchar;
using StartCallback = void(*)(void*);
using FinishCallback = void(*)(void*);
using UnregisterCallback = void(*)(void*,int connectionIndex);
class BaseObservedEventRegistrator {
public:
BaseObservedEventRegistrator(void *that
, StartCallback startCallback
, FinishCallback finishCallback
, UnregisterCallback unregisterCallback);
protected:
inline ObservedEvent event() const {
return _event;
}
private:
ObservedEvent _event;
};
// Handler is one of Function<> instantiations.
template <typename Flags, typename Handler>
struct ObserversList {
struct Entry {
Flags flags;
Handler handler;
};
std_::vector_of_moveable<Entry> entries;
QVector<int> freeIndices;
};
// If no filtering by flags is done, you can use Flags=int and this value.
constexpr int UniversalFlag = 0x01;
} // namespace internal
// Objects of this class should be constructed in global scope.
// startCallback will be called from Notify::startObservers().
// finishCallback will be called from Notify::finishObservers().
template <typename Flags, typename Handler>
class ObservedEventRegistrator : public internal::BaseObservedEventRegistrator {
public:
ObservedEventRegistrator(StartObservedEventCallback startCallback,
FinishObservedEventCallback finishCallback) : internal::BaseObservedEventRegistrator(static_cast<void*>(this),
ObservedEventRegistrator<Flags, Handler>::start,
ObservedEventRegistrator<Flags, Handler>::finish,
ObservedEventRegistrator<Flags, Handler>::unregister)
, _startCallback(startCallback), _finishCallback(finishCallback) {
}
bool started() const {
return _list != nullptr;
}
ConnectionId registerObserver(Flags flags, Handler &&handler) {
t_assert(started());
int connectionIndex = doRegisterObserver(flags, std_::forward<Handler>(handler));
return (static_cast<uint32>(event()) << 24) | static_cast<uint32>(connectionIndex + 1);
}
template <typename... Args>
void notify(Flags flags, Args&&... args) {
t_assert(started());
auto &entries = _list->entries;
// This way of iterating (i < entries.size() should be used
// because some entries can be removed from the end of the
// entries list while the loop is still running.
for (int i = 0; i < entries.size(); ++i) {
auto &entry = entries[i];
if (!entry.handler.isNull() && (flags & entry.flags)) {
entry.handler.call(std_::forward<Args>(args)...);
}
}
}
private:
using Self = ObservedEventRegistrator<Flags, Handler>;
static void start(void *vthat) {
Self *that = static_cast<Self*>(vthat);
t_assert(!that->started());
if (that->_startCallback) that->_startCallback();
that->_list = new internal::ObserversList<Flags, Handler>();
}
static void finish(void *vthat) {
Self *that = static_cast<Self*>(vthat);
if (that->_finishCallback) that->_finishCallback();
delete that->_list;
that->_list = nullptr;
}
static void unregister(void *vthat, int connectionIndex) {
Self *that = static_cast<Self*>(vthat);
t_assert(that->started());
auto &entries = that->_list->entries;
if (entries.size() <= connectionIndex) return;
if (entries.size() == connectionIndex + 1) {
for (entries.pop_back(); !entries.isEmpty() && entries.back().handler.isNull();) {
entries.pop_back();
}
} else {
entries[connectionIndex].handler = Handler();
that->_list->freeIndices.push_back(connectionIndex);
}
}
int doRegisterObserver(Flags flags, Handler &&handler) {
while (!_list->freeIndices.isEmpty()) {
auto freeIndex = _list->freeIndices.back();
_list->freeIndices.pop_back();
if (freeIndex < _list->entries.size()) {
_list->entries[freeIndex] = { flags, std_::move(handler) };
return freeIndex;
}
}
_list->entries.push_back({ flags, std_::move(handler) });
return _list->entries.size() - 1;
}
StartObservedEventCallback _startCallback;
FinishObservedEventCallback _finishCallback;
internal::ObserversList<Flags, Handler> *_list = nullptr;
};
// If no filtering of notifications by Flags is intended use this class.
template <typename Handler>
class SimpleObservedEventRegistrator {
public:
SimpleObservedEventRegistrator(StartObservedEventCallback startCallback,
FinishObservedEventCallback finishCallback) : _implementation(startCallback, finishCallback) {
}
bool started() const {
return _implementation.started();
}
ConnectionId registerObserver(Handler &&handler) {
return _implementation.registerObserver(internal::UniversalFlag, std_::forward<Handler>(handler));
}
template <typename... Args>
void notify(Args&&... args) {
return _implementation.notify(internal::UniversalFlag, std_::forward<Args>(args)...);
}
private:
ObservedEventRegistrator<int, Handler> _implementation;
};
// Each observer type should have observerRegistered(Notify::ConnectionId connection) method.
// Usually it is done by deriving the type from the Notify::Observer base class.
// In destructor it should call Notify::unregisterObserver(connection) for all the connections.
class Observer;
namespace internal {
void observerRegisteredDefault(Observer *observer, ConnectionId connection);
} // namespace internal
void unregisterObserver(ConnectionId connection);
class Observer {
public:
virtual ~Observer() = 0;
private:
void observerRegistered(ConnectionId connection);
friend void internal::observerRegisteredDefault(Observer *observer, ConnectionId connection);
QVector<ConnectionId> _connections;
};
namespace internal {
template <typename ObserverType, int>
struct ObserverRegisteredGeneric {
static inline void call(ObserverType *observer, ConnectionId connection) {
observer->observerRegistered(connection);
}
};
template <typename ObserverType>
struct ObserverRegisteredGeneric<ObserverType, true> {
static inline void call(ObserverType *observer, ConnectionId connection) {
observerRegisteredDefault(observer, connection);
}
};
} // namespace internal
template <typename ObserverType>
inline void observerRegistered(ObserverType *observer, ConnectionId connection) {
// For derivatives of the Observer class we call special friend function observerRegistered().
// For all other classes we call just a member function observerRegistered().
using ObserverRegistered = internal::ObserverRegisteredGeneric<ObserverType, std_::is_base_of<Observer, ObserverType>::value>;
ObserverRegistered::call(observer, connection);
}
} // namespace Notify
namespace base { namespace base {
namespace internal { namespace internal {
@ -271,10 +47,10 @@ using SubscriptionHandler = typename SubscriptionHandlerHelper<EventType>::type;
class BaseObservableData { class BaseObservableData {
}; };
template <typename EventType> template <typename EventType, typename Handler>
class CommonObservableData; class CommonObservableData;
template <typename EventType> template <typename EventType, typename Handler>
class ObservableData; class ObservableData;
} // namespace internal } // namespace internal
@ -317,43 +93,41 @@ private:
Node *_node = nullptr; Node *_node = nullptr;
RemoveMethod _removeMethod; RemoveMethod _removeMethod;
template <typename EventType> template <typename EventType, typename Handler>
friend class internal::CommonObservableData; friend class internal::CommonObservableData;
template <typename EventType> template <typename EventType, typename Handler>
friend class internal::ObservableData; friend class internal::ObservableData;
}; };
template <typename EventType> template <typename EventType, typename Handler>
class Observable; class Observable;
namespace internal { namespace internal {
template <typename EventType> template <typename EventType, typename Handler>
class CommonObservable { class CommonObservable {
public: public:
using Handler = typename CommonObservableData<EventType>::Handler;
Subscription add_subscription(Handler &&handler) { Subscription add_subscription(Handler &&handler) {
if (!_data) { if (!_data) {
_data = MakeShared<ObservableData<EventType>>(this); _data = MakeShared<ObservableData<EventType, Handler>>(this);
} }
return _data->append(std_::forward<Handler>(handler)); return _data->append(std_::forward<Handler>(handler));
} }
private: private:
QSharedPointer<ObservableData<EventType>> _data; QSharedPointer<ObservableData<EventType, Handler>> _data;
friend class CommonObservableData<EventType>; friend class CommonObservableData<EventType, Handler>;
friend class Observable<EventType>; friend class Observable<EventType, Handler>;
}; };
} // namespace internal } // namespace internal
template <typename EventType> template <typename EventType, typename Handler = internal::SubscriptionHandler<EventType>>
class Observable : public internal::CommonObservable<EventType> { class Observable : public internal::CommonObservable<EventType, Handler> {
public: public:
void notify(EventType &&event, bool sync = false) { void notify(EventType &&event, bool sync = false) {
if (this->_data) { if (this->_data) {
@ -368,12 +142,10 @@ public:
namespace internal { namespace internal {
template <typename EventType> template <typename EventType, typename Handler>
class CommonObservableData : public BaseObservableData { class CommonObservableData : public BaseObservableData {
public: public:
using Handler = SubscriptionHandler<EventType>; CommonObservableData(CommonObservable<EventType, Handler> *observable) : _observable(observable) {
CommonObservableData(CommonObservable<EventType> *observable) : _observable(observable) {
} }
Subscription append(Handler &&handler) { Subscription append(Handler &&handler) {
@ -444,20 +216,20 @@ private:
} }
} }
CommonObservable<EventType> *_observable = nullptr; CommonObservable<EventType, Handler> *_observable = nullptr;
Node *_begin = nullptr; Node *_begin = nullptr;
Node *_current = nullptr; Node *_current = nullptr;
Node *_end = nullptr; Node *_end = nullptr;
ObservableCallHandlers _callHandlers; ObservableCallHandlers _callHandlers;
friend class ObservableData<EventType>; friend class ObservableData<EventType, Handler>;
}; };
template <typename EventType> template <typename EventType, typename Handler>
class ObservableData : public CommonObservableData<EventType> { class ObservableData : public CommonObservableData<EventType, Handler> {
public: public:
using CommonObservableData<EventType>::CommonObservableData; using CommonObservableData<EventType, Handler>::CommonObservableData;
void notify(EventType &&event, bool sync) { void notify(EventType &&event, bool sync) {
if (_handling) { if (_handling) {
@ -501,10 +273,10 @@ private:
}; };
template <> template <class Handler>
class ObservableData<void> : public CommonObservableData<void> { class ObservableData<void, Handler> : public CommonObservableData<void, Handler> {
public: public:
using CommonObservableData<void>::CommonObservableData; using CommonObservableData<void, Handler>::CommonObservableData;
void notify(bool sync) { void notify(bool sync) {
if (_handling) { if (_handling) {
@ -514,20 +286,20 @@ public:
++_eventsCount; ++_eventsCount;
callHandlers(); callHandlers();
} else { } else {
if (!_callHandlers) { if (!this->_callHandlers) {
_callHandlers = [this]() { this->_callHandlers = [this]() {
callHandlers(); callHandlers();
}; };
} }
if (!_eventsCount) { if (!_eventsCount) {
RegisterPendingObservable(&_callHandlers); RegisterPendingObservable(&this->_callHandlers);
} }
++_eventsCount; ++_eventsCount;
} }
} }
~ObservableData() { ~ObservableData() {
UnregisterObservable(&_callHandlers); UnregisterObservable(&this->_callHandlers);
} }
private: private:
@ -535,12 +307,12 @@ private:
_handling = true; _handling = true;
auto eventsCount = createAndSwap(_eventsCount); auto eventsCount = createAndSwap(_eventsCount);
for (int i = 0; i != eventsCount; ++i) { for (int i = 0; i != eventsCount; ++i) {
notifyEnumerate([this]() { this->notifyEnumerate([this]() {
_current->handler(); this->_current->handler();
}); });
} }
_handling = false; _handling = false;
UnregisterActiveObservable(&_callHandlers); UnregisterActiveObservable(&this->_callHandlers);
} }
int _eventsCount = 0; int _eventsCount = 0;
@ -550,12 +322,12 @@ private:
} // namespace internal } // namespace internal
template <> template <typename Handler>
class Observable<void> : public internal::CommonObservable<void> { class Observable<void, Handler> : public internal::CommonObservable<void, Handler> {
public: public:
void notify(bool sync = false) { void notify(bool sync = false) {
if (_data) { if (this->_data) {
_data->notify(sync); this->_data->notify(sync);
} }
} }
@ -563,14 +335,14 @@ public:
class Subscriber { class Subscriber {
protected: protected:
template <typename EventType, typename Lambda> template <typename EventType, typename Handler, typename Lambda>
int subscribe(base::Observable<EventType> &observable, Lambda &&handler) { int subscribe(base::Observable<EventType, Handler> &observable, Lambda &&handler) {
_subscriptions.push_back(observable.add_subscription(std_::forward<Lambda>(handler))); _subscriptions.push_back(observable.add_subscription(std_::forward<Lambda>(handler)));
return _subscriptions.size() - 1; return _subscriptions.size() - 1;
} }
template <typename EventType, typename Lambda> template <typename EventType, typename Handler, typename Lambda>
int subscribe(base::Observable<EventType> *observable, Lambda &&handler) { int subscribe(base::Observable<EventType, Handler> *observable, Lambda &&handler) {
return subscribe(*observable, std_::forward<Lambda>(handler)); return subscribe(*observable, std_::forward<Lambda>(handler));
} }

View file

@ -93,6 +93,7 @@ public:
*prev = std_::move(*next); *prev = std_::move(*next);
} }
--_size; --_size;
end()->~T();
return it; return it;
} }
@ -143,15 +144,21 @@ public:
} }
inline const T &at(int index) const { inline const T &at(int index) const {
if (index < 0 || index >= _size) { if (index < 0 || index >= _size) {
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) #ifndef OS_MAC_OLD
throw std::exception();
#else // QT_VERSION < 5.5.0
throw std::out_of_range(""); throw std::out_of_range("");
#endif // QT_VERSION < 5.5.0 #else // OS_MAC_OLD
throw std::exception();
#endif // OS_MAC_OLD
} }
return data()[index]; return data()[index];
} }
void reserve(int newCapacity) {
if (newCapacity > _capacity) {
reallocate(newCapacity);
}
}
inline ~vector_of_moveable() { inline ~vector_of_moveable() {
clear(); clear();
} }

View file

@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/basic_types.h" #include "core/basic_types.h"
#define BETA_VERSION_MACRO (0ULL) #define BETA_VERSION_MACRO (10008001ULL)
constexpr int AppVersion = 10008; constexpr int AppVersion = 10008;
constexpr str_const AppVersionStr = "0.10.8"; constexpr str_const AppVersionStr = "0.10.8";

View file

@ -46,13 +46,15 @@ DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(p
if (Global::DialogsModeEnabled()) { if (Global::DialogsModeEnabled()) {
importantDialogs = std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Date); importantDialogs = std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Date);
} }
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
connect(main, SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&))); connect(main, SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)));
connect(main, SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(onPeerPhotoChanged(PeerData*))); connect(main, SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(onPeerPhotoChanged(PeerData*)));
connect(main, SIGNAL(dialogRowReplaced(Dialogs::Row*,Dialogs::Row*)), this, SLOT(onDialogRowReplaced(Dialogs::Row*,Dialogs::Row*))); connect(main, SIGNAL(dialogRowReplaced(Dialogs::Row*,Dialogs::Row*)), this, SLOT(onDialogRowReplaced(Dialogs::Row*,Dialogs::Row*)));
connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact())); connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact()));
connect(&_cancelSearchInPeer, SIGNAL(clicked()), this, SIGNAL(cancelSearchInPeer())); connect(&_cancelSearchInPeer, SIGNAL(clicked()), this, SIGNAL(cancelSearchInPeer()));
_cancelSearchInPeer.hide(); _cancelSearchInPeer.hide();
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
refresh(); refresh();
} }

View file

@ -42,7 +42,7 @@ enum DialogsSearchRequestType {
DialogsSearchMigratedFromOffset, DialogsSearchMigratedFromOffset,
}; };
class DialogsInner : public SplittedWidget, public RPCSender { class DialogsInner : public SplittedWidget, public RPCSender, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
class LayerWidget; class LayerWidget;
namespace base { namespace base {
template <typename Type> template <typename Type, typename>
class Observable; class Observable;
} // namespace base } // namespace base
namespace InlineBots { namespace InlineBots {

View file

@ -574,6 +574,15 @@ History *Histories::find(const PeerId &peerId) {
return (i == map.cend()) ? 0 : i.value(); return (i == map.cend()) ? 0 : i.value();
} }
History *Histories::findOrInsert(const PeerId &peerId) {
auto i = map.constFind(peerId);
if (i == map.cend()) {
auto history = peerIsChannel(peerId) ? static_cast<History*>(new ChannelHistory(peerId)) : (new History(peerId));
i = map.insert(peerId, history);
}
return i.value();
}
History *Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead) { History *Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead) {
auto i = map.constFind(peerId); auto i = map.constFind(peerId);
if (i == map.cend()) { if (i == map.cend()) {
@ -584,10 +593,10 @@ History *Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32
history->outboxReadBefore = maxOutboxRead + 1; history->outboxReadBefore = maxOutboxRead + 1;
} else { } else {
auto history = i.value(); auto history = i.value();
if (unreadCount >= history->unreadCount()) { if (unreadCount > history->unreadCount()) {
history->setUnreadCount(unreadCount); history->setUnreadCount(unreadCount);
history->inboxReadBefore = maxInboxRead + 1;
} }
accumulate_max(history->inboxReadBefore, maxInboxRead + 1);
accumulate_max(history->outboxReadBefore, maxOutboxRead + 1); accumulate_max(history->outboxReadBefore, maxOutboxRead + 1);
} }
return i.value(); return i.value();
@ -1442,8 +1451,8 @@ MsgId History::inboxRead(MsgId upTo) {
updateChatListEntry(); updateChatListEntry();
if (peer->migrateTo()) { if (peer->migrateTo()) {
if (History *h = App::historyLoaded(peer->migrateTo()->id)) { if (auto migrateTo = App::historyLoaded(peer->migrateTo()->id)) {
h->updateChatListEntry(); migrateTo->updateChatListEntry();
} }
} }
@ -2635,10 +2644,12 @@ void HistoryMessageReplyMarkup::create(const MTPReplyMarkup &markup) {
} }
} }
void HistoryDependentItemCallback::call(ChannelData *channel, MsgId msgId) const { ApiWrap::RequestMessageDataCallback historyDependentItemCallback(const FullMsgId &msgId) {
if (HistoryItem *item = App::histItemById(_dependent)) { return [dependent = msgId](ChannelData *channel, MsgId msgId) {
item->updateDependencyItem(); if (HistoryItem *item = App::histItemById(dependent)) {
} item->updateDependencyItem();
}
};
} }
void HistoryMessageUnreadBar::init(int count) { void HistoryMessageUnreadBar::init(int count) {
@ -4901,7 +4912,9 @@ bool HistoryGif::playInline(bool autoplay) {
if (!cAutoPlayGif()) { if (!cAutoPlayGif()) {
App::stopGifItems(); App::stopGifItems();
} }
_gif = new Media::Clip::Reader(_data->location(), _data->data(), func(_parent, &HistoryItem::clipCallback)); _gif = new Media::Clip::Reader(_data->location(), _data->data(), [this](Media::Clip::Notification notification) {
_parent->clipCallback(notification);
});
App::regGifItem(_gif, _parent); App::regGifItem(_gif, _parent);
if (gif()) _gif->setAutoplay(); if (gif()) _gif->setAutoplay();
} }
@ -6828,7 +6841,7 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
if (auto reply = Get<HistoryMessageReply>()) { if (auto reply = Get<HistoryMessageReply>()) {
reply->replyToMsgId = config.replyTo; reply->replyToMsgId = config.replyTo;
if (!reply->updateData(this) && App::api()) { if (!reply->updateData(this) && App::api()) {
App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, std_::make_unique<HistoryDependentItemCallback>(fullId())); App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, historyDependentItemCallback(fullId()));
} }
} }
if (auto via = Get<HistoryMessageVia>()) { if (auto via = Get<HistoryMessageVia>()) {
@ -8379,7 +8392,7 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) {
if (auto dependent = GetDependentData()) { if (auto dependent = GetDependentData()) {
dependent->msgId = message.vreply_to_msg_id.v; dependent->msgId = message.vreply_to_msg_id.v;
if (!updateDependent() && App::api()) { if (!updateDependent() && App::api()) {
App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, std_::make_unique<HistoryDependentItemCallback>(fullId())); App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, historyDependentItemCallback(fullId()));
} }
} }
} }

View file

@ -48,6 +48,7 @@ public:
void step_typings(uint64 ms, bool timer); void step_typings(uint64 ms, bool timer);
History *find(const PeerId &peerId); History *find(const PeerId &peerId);
History *findOrInsert(const PeerId &peerId);
History *findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead); History *findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead);
void clear(); void clear();
@ -934,17 +935,6 @@ private:
StylePtr _st; StylePtr _st;
}; };
class HistoryDependentItemCallback : public SharedCallback<void, ChannelData*, MsgId> {
public:
HistoryDependentItemCallback(FullMsgId dependent) : _dependent(dependent) {
}
void call(ChannelData *channel, MsgId msgId) const override;
private:
FullMsgId _dependent;
};
// any HistoryItem can have this Interface for // any HistoryItem can have this Interface for
// displaying the day mark above the message // displaying the day mark above the message
struct HistoryMessageDate : public BaseComponent<HistoryMessageDate> { struct HistoryMessageDate : public BaseComponent<HistoryMessageDate> {

View file

@ -44,8 +44,6 @@ FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
connect(_inner, SIGNAL(stickerChosen(DocumentData*,FieldAutocomplete::ChooseMethod)), this, SIGNAL(stickerChosen(DocumentData*,FieldAutocomplete::ChooseMethod))); connect(_inner, SIGNAL(stickerChosen(DocumentData*,FieldAutocomplete::ChooseMethod)), this, SIGNAL(stickerChosen(DocumentData*,FieldAutocomplete::ChooseMethod)));
connect(_inner, SIGNAL(mustScrollTo(int, int)), _scroll, SLOT(scrollToY(int, int))); connect(_inner, SIGNAL(mustScrollTo(int, int)), _scroll, SLOT(scrollToY(int, int)));
connect(App::wnd(), SIGNAL(imageLoaded()), _inner, SLOT(update()));
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
_scroll->setFocusPolicy(Qt::NoFocus); _scroll->setFocusPolicy(Qt::NoFocus);
_scroll->viewport()->setFocusPolicy(Qt::NoFocus); _scroll->viewport()->setFocusPolicy(Qt::NoFocus);
@ -539,6 +537,7 @@ FieldAutocompleteInner::FieldAutocompleteInner(FieldAutocomplete *parent, Mentio
, _previewShown(false) { , _previewShown(false) {
_previewTimer.setSingleShot(true); _previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview())); connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
} }
void FieldAutocompleteInner::paintEvent(QPaintEvent *e) { void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
@ -933,7 +932,4 @@ void FieldAutocompleteInner::onPreview() {
} }
} }
FieldAutocompleteInner::~FieldAutocompleteInner() {
}
} // namespace internal } // namespace internal

View file

@ -138,7 +138,7 @@ private:
namespace internal { namespace internal {
class FieldAutocompleteInner final : public TWidget { class FieldAutocompleteInner final : public TWidget, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:
@ -150,8 +150,6 @@ public:
void setRecentInlineBotsInRows(int32 bots); void setRecentInlineBotsInRows(int32 bots);
~FieldAutocompleteInner();
signals: signals:
void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const; void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const;
void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const; void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const;

View file

@ -101,6 +101,14 @@ public:
constexpr int ScrollDateHideTimeout = 1000; constexpr int ScrollDateHideTimeout = 1000;
ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() {
return [](ChannelData *channel, MsgId msgId) {
if (App::main()) {
App::main()->messageDataReceived(channel, msgId);
}
};
}
} // namespace } // namespace
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
@ -1684,7 +1692,7 @@ void HistoryInner::toggleScrollDateShown() {
_scrollDateShown = !_scrollDateShown; _scrollDateShown = !_scrollDateShown;
auto from = _scrollDateShown ? 0. : 1.; auto from = _scrollDateShown ? 0. : 1.;
auto to = _scrollDateShown ? 1. : 0.; auto to = _scrollDateShown ? 1. : 0.;
START_ANIMATION(_scrollDateOpacity, func(this, &HistoryInner::repaintScrollDateCallback), from, to, st::btnAttachEmoji.duration, anim::linear); _scrollDateOpacity.start([this] { repaintScrollDateCallback(); }, from, to, st::btnAttachEmoji.duration);
} }
void HistoryInner::repaintScrollDateCallback() { void HistoryInner::repaintScrollDateCallback() {
@ -3032,7 +3040,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
setAcceptDrops(true); setAcceptDrops(true);
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); subscribe(FileDownload::ImageLoaded(), [this] { update(); });
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
connect(&_reportSpamPanel, SIGNAL(reportClicked()), this, SLOT(onReportSpamClicked())); connect(&_reportSpamPanel, SIGNAL(reportClicked()), this, SLOT(onReportSpamClicked()));
connect(&_reportSpamPanel, SIGNAL(hideClicked()), this, SLOT(onReportSpamHide())); connect(&_reportSpamPanel, SIGNAL(hideClicked()), this, SLOT(onReportSpamHide()));
@ -4117,7 +4125,7 @@ void HistoryWidget::applyDraft(bool parseLinks) {
if (_editMsgId || _replyToId) { if (_editMsgId || _replyToId) {
updateReplyEditTexts(); updateReplyEditTexts();
if (!_replyEditMsg && App::api()) { if (!_replyEditMsg && App::api()) {
App::api()->requestMessageData(_peer->asChannel(), _editMsgId ? _editMsgId : _replyToId, std_::make_unique<ReplyEditMessageDataCallback>()); App::api()->requestMessageData(_peer->asChannel(), _editMsgId ? _editMsgId : _replyToId, replyEditMessageDataCallback());
} }
} }
} }
@ -7633,7 +7641,7 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
update(); update();
} }
if (!_pinnedBar->msg && App::api()) { if (!_pinnedBar->msg && App::api()) {
App::api()->requestMessageData(_peer->asChannel(), _pinnedBar->msgId, std_::make_unique<ReplyEditMessageDataCallback>()); App::api()->requestMessageData(_peer->asChannel(), _pinnedBar->msgId, replyEditMessageDataCallback());
} }
} else if (_pinnedBar) { } else if (_pinnedBar) {
destroyPinnedBar(); destroyPinnedBar();
@ -7652,12 +7660,6 @@ void HistoryWidget::destroyPinnedBar() {
_inPinnedMsg = false; _inPinnedMsg = false;
} }
void HistoryWidget::ReplyEditMessageDataCallback::call(ChannelData *channel, MsgId msgId) const {
if (App::main()) {
App::main()->messageDataReceived(channel, msgId);
}
}
bool HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &caption) { bool HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &caption) {
if (!_history || !doc || !canSendMessages(_peer)) { if (!_history || !doc || !canSendMessages(_peer)) {
return false; return false;

View file

@ -908,11 +908,6 @@ private:
void destroyPinnedBar(); void destroyPinnedBar();
void unpinDone(const MTPUpdates &updates); void unpinDone(const MTPUpdates &updates);
class ReplyEditMessageDataCallback : public SharedCallback<void, ChannelData*, MsgId> {
public:
void call(ChannelData *channel, MsgId msgId) const override;
};
bool sendExistingDocument(DocumentData *doc, const QString &caption); bool sendExistingDocument(DocumentData *doc, const QString &caption);
void sendExistingPhoto(PhotoData *photo, const QString &caption); void sendExistingPhoto(PhotoData *photo, const QString &caption);

View file

@ -135,7 +135,9 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading(); bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading();
if (loaded && !gif() && _gif != Media::Clip::BadReader) { if (loaded && !gif() && _gif != Media::Clip::BadReader) {
Gif *that = const_cast<Gif*>(this); Gif *that = const_cast<Gif*>(this);
that->_gif = new Media::Clip::Reader(document->location(), document->data(), func(that, &Gif::clipCallback)); that->_gif = new Media::Clip::Reader(document->location(), document->data(), [that](Media::Clip::Notification notification) {
that->clipCallback(notification);
});
if (gif()) _gif->setAutoplay(); if (gif()) _gif->setAutoplay();
} }
@ -165,9 +167,9 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
} }
if (radial || (!_gif && !loaded && !loading) || (_gif == Media::Clip::BadReader)) { if (radial || (!_gif && !loaded && !loading) || (_gif == Media::Clip::BadReader)) {
float64 radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1; auto radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1.;
if (_animation && _animation->_a_over.animating(context->ms)) { if (_animation && _animation->_a_over.animating(context->ms)) {
float64 over = _animation->_a_over.current(); auto over = _animation->_a_over.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.fillRect(r, st::black); p.fillRect(r, st::black);
} else { } else {
@ -219,7 +221,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
bool wasactive = (_state & StateFlag::DeleteOver); bool wasactive = (_state & StateFlag::DeleteOver);
if (active != wasactive) { if (active != wasactive) {
auto from = active ? 0. : 1., to = active ? 1. : 0.; auto from = active ? 0. : 1., to = active ? 1. : 0.;
START_ANIMATION(_a_deleteOver, func(this, &Gif::update), from, to, st::stickersRowDuration, anim::linear); _a_deleteOver.start([this] { update(); }, from, to, st::stickersRowDuration);
if (active) { if (active) {
_state |= StateFlag::DeleteOver; _state |= StateFlag::DeleteOver;
} else { } else {
@ -233,7 +235,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
if (!getShownDocument()->loaded()) { if (!getShownDocument()->loaded()) {
ensureAnimation(); ensureAnimation();
auto from = active ? 0. : 1., to = active ? 1. : 0.; auto from = active ? 0. : 1., to = active ? 1. : 0.;
START_ANIMATION(_animation->_a_over, func(this, &Gif::update), from, to, st::stickersRowDuration, anim::linear); _animation->_a_over.start([this] { update(); }, from, to, st::stickersRowDuration);
} }
if (active) { if (active) {
_state |= StateFlag::Over; _state |= StateFlag::Over;
@ -386,7 +388,7 @@ void Sticker::preload() const {
void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const { void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
bool loaded = getShownDocument()->loaded(); bool loaded = getShownDocument()->loaded();
float64 over = _a_over.isNull() ? (_active ? 1 : 0) : _a_over.current(); auto over = _a_over.current(_active ? 1. : 0.);
if (over > 0) { if (over > 0) {
p.setOpacity(over); p.setOpacity(over);
App::roundRect(p, QRect(QPoint(0, 0), st::stickerPanSize), st::emojiPanHover, StickerHoverCorners); App::roundRect(p, QRect(QPoint(0, 0), st::stickerPanSize), st::emojiPanHover, StickerHoverCorners);
@ -415,7 +417,7 @@ void Sticker::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
_active = active; _active = active;
auto from = active ? 0. : 1., to = active ? 1. : 0.; auto from = active ? 0. : 1., to = active ? 1. : 0.;
START_ANIMATION(_a_over, func(this, &Sticker::update), from, to, st::stickersRowDuration, anim::linear); _a_over.start([this] { update(); }, from, to, st::stickersRowDuration);
} }
} }
ItemBase::clickHandlerActiveChanged(p, active); ItemBase::clickHandlerActiveChanged(p, active);

View file

@ -437,7 +437,7 @@ MediaPreviewWidget::MediaPreviewWidget(QWidget *parent) : TWidget(parent)
, _a_shown(animation(this, &MediaPreviewWidget::step_shown)) , _a_shown(animation(this, &MediaPreviewWidget::step_shown))
, _emojiSize(EmojiSizes[EIndex + 1] / cIntRetinaFactor()) { , _emojiSize(EmojiSizes[EIndex + 1] / cIntRetinaFactor()) {
setAttribute(Qt::WA_TransparentForMouseEvents); setAttribute(Qt::WA_TransparentForMouseEvents);
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); subscribe(FileDownload::ImageLoaded(), [this] { update(); });
} }
void MediaPreviewWidget::paintEvent(QPaintEvent *e) { void MediaPreviewWidget::paintEvent(QPaintEvent *e) {
@ -456,11 +456,11 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) {
p.drawPixmap((width() - w) / 2, (height() - h) / 2, image); p.drawPixmap((width() - w) / 2, (height() - h) / 2, image);
if (!_emojiList.isEmpty()) { if (!_emojiList.isEmpty()) {
int emojiCount = _emojiList.size(); int emojiCount = _emojiList.size();
int emojiWidth = emojiCount * _emojiSize + (emojiCount - 1) * st::stickerEmojiSkip; int emojiWidth = (emojiCount * _emojiSize) + (emojiCount - 1) * st::stickerEmojiSkip;
int emojiLeft = (width() - emojiWidth) / 2; int emojiLeft = (width() - emojiWidth) / 2;
int esize = _emojiSize * cIntRetinaFactor(); int esize = EmojiSizes[EIndex + 1];
for_const (auto emoji, _emojiList) { 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)); p.drawPixmapLeft(emojiLeft, (height() - h) / 2 - (_emojiSize * 2), width(), App::emojiLarge(), QRect(emoji->x * esize, emoji->y * esize, esize, esize));
emojiLeft += _emojiSize + st::stickerEmojiSkip; emojiLeft += _emojiSize + st::stickerEmojiSkip;
} }
} }
@ -638,7 +638,9 @@ QPixmap MediaPreviewWidget::currentImage() const {
if (_document->loaded()) { if (_document->loaded()) {
if (!_gif && _gif != Media::Clip::BadReader) { if (!_gif && _gif != Media::Clip::BadReader) {
auto that = const_cast<MediaPreviewWidget*>(this); auto that = const_cast<MediaPreviewWidget*>(this);
that->_gif = new Media::Clip::Reader(_document->location(), _document->data(), func(that, &MediaPreviewWidget::clipCallback)); that->_gif = new Media::Clip::Reader(_document->location(), _document->data(), [this, that](Media::Clip::Notification notification) {
that->clipCallback(notification);
});
if (gif()) _gif->setAutoplay(); if (gif()) _gif->setAutoplay();
} }
} }

View file

@ -129,7 +129,7 @@ private:
}; };
class MediaPreviewWidget : public TWidget { class MediaPreviewWidget : public TWidget, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -2897,18 +2897,18 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha
bool isFinal = true; bool isFinal = true;
switch (diff.type()) { switch (diff.type()) {
case mtpc_updates_channelDifferenceEmpty: { case mtpc_updates_channelDifferenceEmpty: {
const auto &d(diff.c_updates_channelDifferenceEmpty()); auto &d = diff.c_updates_channelDifferenceEmpty();
if (d.has_timeout()) timeout = d.vtimeout.v; if (d.has_timeout()) timeout = d.vtimeout.v;
isFinal = d.is_final(); isFinal = d.is_final();
channel->ptsInit(d.vpts.v); channel->ptsInit(d.vpts.v);
} break; } break;
case mtpc_updates_channelDifferenceTooLong: { case mtpc_updates_channelDifferenceTooLong: {
const auto &d(diff.c_updates_channelDifferenceTooLong()); auto &d = diff.c_updates_channelDifferenceTooLong();
App::feedUsers(d.vusers); App::feedUsers(d.vusers);
App::feedChats(d.vchats); App::feedChats(d.vchats);
History *h = App::historyLoaded(channel->id); auto h = App::historyLoaded(channel->id);
if (h) { if (h) {
h->setNotLoadedAtBottom(); h->setNotLoadedAtBottom();
} }
@ -2934,7 +2934,7 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha
} break; } break;
case mtpc_updates_channelDifference: { case mtpc_updates_channelDifference: {
const auto &d(diff.c_updates_channelDifference()); auto &d = diff.c_updates_channelDifference();
App::feedUsers(d.vusers); App::feedUsers(d.vusers);
App::feedChats(d.vchats); App::feedChats(d.vchats);
@ -2943,11 +2943,11 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha
feedMessageIds(d.vother_updates); feedMessageIds(d.vother_updates);
// feed messages and groups, copy from App::feedMsgs // feed messages and groups, copy from App::feedMsgs
History *h = App::history(channel->id); auto h = App::history(channel->id);
const auto &vmsgs(d.vnew_messages.c_vector().v); auto &vmsgs = d.vnew_messages.c_vector().v;
QMap<uint64, int32> msgsIds; QMap<uint64, int> msgsIds;
for (int32 i = 0, l = vmsgs.size(); i < l; ++i) { for (int i = 0, l = vmsgs.size(); i < l; ++i) {
const auto &msg(vmsgs.at(i)); auto &msg = vmsgs[i];
switch (msg.type()) { switch (msg.type()) {
case mtpc_message: { case mtpc_message: {
const auto &d(msg.c_message()); const auto &d(msg.c_message());
@ -2961,9 +2961,9 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha
case mtpc_messageService: msgsIds.insert((uint64(uint32(msg.c_messageService().vid.v)) << 32) | uint64(i), i + 1); break; case mtpc_messageService: msgsIds.insert((uint64(uint32(msg.c_messageService().vid.v)) << 32) | uint64(i), i + 1); break;
} }
} }
for (QMap<uint64, int32>::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { for_const (auto msgIndex, msgsIds) {
if (i.value() > 0) { // add message if (msgIndex > 0) { // add message
const auto &msg(vmsgs.at(i.value() - 1)); auto &msg = vmsgs.at(msgIndex - 1);
if (channel->id != peerFromMessage(msg)) { if (channel->id != peerFromMessage(msg)) {
LOG(("API Error: message with invalid peer returned in channelDifference, channelId: %1, peer: %2").arg(peerToChannel(channel->id)).arg(peerFromMessage(msg))); LOG(("API Error: message with invalid peer returned in channelDifference, channelId: %1, peer: %2").arg(peerToChannel(channel->id)).arg(peerFromMessage(msg)));
continue; // wtf continue; // wtf
@ -4043,7 +4043,7 @@ DataIsLoadedResult allDataLoadedForMessage(const MTPMessage &msg) {
void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
switch (updates.type()) { switch (updates.type()) {
case mtpc_updates: { case mtpc_updates: {
const auto &d(updates.c_updates()); auto &d = updates.c_updates();
if (d.vseq.v) { if (d.vseq.v) {
if (d.vseq.v <= updSeq) return; if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) { if (d.vseq.v > updSeq + 1) {
@ -4060,7 +4060,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break; } break;
case mtpc_updatesCombined: { case mtpc_updatesCombined: {
const auto &d(updates.c_updatesCombined()); auto &d = updates.c_updatesCombined();
if (d.vseq_start.v) { if (d.vseq_start.v) {
if (d.vseq_start.v <= updSeq) return; if (d.vseq_start.v <= updSeq) return;
if (d.vseq_start.v > updSeq + 1) { if (d.vseq_start.v > updSeq + 1) {
@ -4077,15 +4077,14 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break; } break;
case mtpc_updateShort: { case mtpc_updateShort: {
const auto &d(updates.c_updateShort()); auto &d = updates.c_updateShort();
feedUpdate(d.vupdate); feedUpdate(d.vupdate);
updSetState(0, d.vdate.v, updQts, updSeq); updSetState(0, d.vdate.v, updQts, updSeq);
} break; } break;
case mtpc_updateShortMessage: { case mtpc_updateShortMessage: {
const auto &d(updates.c_updateShortMessage()); auto &d = updates.c_updateShortMessage();
if (!App::userLoaded(d.vuser_id.v) if (!App::userLoaded(d.vuser_id.v)
|| (d.has_via_bot_id() && !App::userLoaded(d.vvia_bot_id.v)) || (d.has_via_bot_id() && !App::userLoaded(d.vvia_bot_id.v))
|| (d.has_entities() && !mentionUsersLoaded(d.ventities)) || (d.has_entities() && !mentionUsersLoaded(d.ventities))
@ -4099,7 +4098,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
// update before applying skipped // update before applying skipped
MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id; MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id;
HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.is_out() ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread); auto item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.is_out() ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread);
if (item) { if (item) {
_history->peerMessagesUpdated(item->history()->peer->id); _history->peerMessagesUpdated(item->history()->peer->id);
} }
@ -4110,7 +4109,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break; } break;
case mtpc_updateShortChatMessage: { case mtpc_updateShortChatMessage: {
const auto &d(updates.c_updateShortChatMessage()); auto &d = updates.c_updateShortChatMessage();
bool noFrom = !App::userLoaded(d.vfrom_id.v); bool noFrom = !App::userLoaded(d.vfrom_id.v);
if (!App::chatLoaded(d.vchat_id.v) if (!App::chatLoaded(d.vchat_id.v)
|| noFrom || noFrom
@ -4127,7 +4126,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
// update before applying skipped // update before applying skipped
MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id; MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id;
HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread); auto item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread);
if (item) { if (item) {
_history->peerMessagesUpdated(item->history()->peer->id); _history->peerMessagesUpdated(item->history()->peer->id);
} }
@ -4138,7 +4137,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break; } break;
case mtpc_updateShortSentMessage: { case mtpc_updateShortSentMessage: {
const auto &d(updates.c_updateShortSentMessage()); auto &d = updates.c_updateShortSentMessage();
if (randomId) { if (randomId) {
PeerId peerId = 0; PeerId peerId = 0;
QString text; QString text;
@ -4148,7 +4147,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
if (peerId) { if (peerId) {
if (auto item = App::histItemById(peerToChannel(peerId), d.vid.v)) { if (auto item = App::histItemById(peerToChannel(peerId), d.vid.v)) {
if (d.has_entities() && !mentionUsersLoaded(d.ventities)) { if (d.has_entities() && !mentionUsersLoaded(d.ventities)) {
api()->requestMessageData(item->history()->peer->asChannel(), item->id, nullptr); api()->requestMessageData(item->history()->peer->asChannel(), item->id, ApiWrap::RequestMessageDataCallback());
} }
auto entities = d.has_entities() ? entitiesFromMTP(d.ventities.c_vector().v) : EntitiesInText(); auto entities = d.has_entities() ? entitiesFromMTP(d.ventities.c_vector().v) : EntitiesInText();
item->setText({ text, entities }); item->setText({ text, entities });
@ -4524,13 +4523,13 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break; } break;
case mtpc_updatePrivacy: { case mtpc_updatePrivacy: {
const auto &d(update.c_updatePrivacy()); auto &d = update.c_updatePrivacy();
} break; } break;
/////// Channel updates /////// Channel updates
case mtpc_updateChannel: { case mtpc_updateChannel: {
const auto &d(update.c_updateChannel()); auto &d = update.c_updateChannel();
if (ChannelData *channel = App::channelLoaded(d.vchannel_id.v)) { if (auto channel = App::channelLoaded(d.vchannel_id.v)) {
App::markPeerUpdated(channel); App::markPeerUpdated(channel);
channel->inviter = 0; channel->inviter = 0;
if (!channel->amIn()) { if (!channel->amIn()) {
@ -4544,7 +4543,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateNewChannelMessage: { case mtpc_updateNewChannelMessage: {
auto &d = update.c_updateNewChannelMessage(); auto &d = update.c_updateNewChannelMessage();
ChannelData *channel = App::channelLoaded(peerToChannel(peerFromMessage(d.vmessage))); auto channel = App::channelLoaded(peerToChannel(peerFromMessage(d.vmessage)));
DataIsLoadedResult isDataLoaded = allDataLoadedForMessage(d.vmessage); DataIsLoadedResult isDataLoaded = allDataLoadedForMessage(d.vmessage);
if (!requestingDifference() && (!channel || isDataLoaded != DataIsLoadedResult::Ok)) { if (!requestingDifference() && (!channel || isDataLoaded != DataIsLoadedResult::Ok)) {
MTP_LOG(0, ("getDifference { good - after not all data loaded in updateNewChannelMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); MTP_LOG(0, ("getDifference { good - after not all data loaded in updateNewChannelMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
@ -4579,8 +4578,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} }
} }
if (needToAdd) { if (needToAdd) {
HistoryItem *item = App::histories().addNewMessage(d.vmessage, NewMessageUnread); if (auto item = App::histories().addNewMessage(d.vmessage, NewMessageUnread)) {
if (item) {
_history->peerMessagesUpdated(item->history()->peer->id); _history->peerMessagesUpdated(item->history()->peer->id);
} }
} }
@ -4590,8 +4588,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break; } break;
case mtpc_updateEditChannelMessage: { case mtpc_updateEditChannelMessage: {
const auto &d(update.c_updateEditChannelMessage()); auto &d = update.c_updateEditChannelMessage();
ChannelData *channel = App::channelLoaded(peerToChannel(peerFromMessage(d.vmessage))); auto channel = App::channelLoaded(peerToChannel(peerFromMessage(d.vmessage)));
if (channel && !_handlingChannelDifference) { if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference if (channel->ptsRequesting()) { // skip global updates while getting channel difference
@ -4610,7 +4608,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break; } break;
case mtpc_updateEditMessage: { case mtpc_updateEditMessage: {
const auto &d(update.c_updateEditMessage()); auto &d = update.c_updateEditMessage();
if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) {
return; return;
@ -4623,9 +4621,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break; } break;
case mtpc_updateChannelPinnedMessage: { case mtpc_updateChannelPinnedMessage: {
const auto &d(update.c_updateChannelPinnedMessage()); auto &d = update.c_updateChannelPinnedMessage();
if (ChannelData *channel = App::channelLoaded(d.vchannel_id.v)) { if (auto channel = App::channelLoaded(d.vchannel_id.v)) {
if (channel->isMegagroup()) { if (channel->isMegagroup()) {
channel->mgInfo->pinnedMsgId = d.vid.v; channel->mgInfo->pinnedMsgId = d.vid.v;
if (App::api()) { if (App::api()) {
@ -4636,13 +4634,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break; } break;
case mtpc_updateReadChannelInbox: { case mtpc_updateReadChannelInbox: {
auto &d(update.c_updateReadChannelInbox()); auto &d = update.c_updateReadChannelInbox();
auto channel = App::channelLoaded(d.vchannel_id.v);
App::feedInboxRead(peerFromChannel(d.vchannel_id.v), d.vmax_id.v); App::feedInboxRead(peerFromChannel(d.vchannel_id.v), d.vmax_id.v);
} break; } break;
case mtpc_updateReadChannelOutbox: { case mtpc_updateReadChannelOutbox: {
auto &d(update.c_updateReadChannelOutbox()); auto &d = update.c_updateReadChannelOutbox();
auto peerId = peerFromChannel(d.vchannel_id.v); auto peerId = peerFromChannel(d.vchannel_id.v);
auto when = requestingDifference() ? 0 : unixtime(); auto when = requestingDifference() ? 0 : unixtime();
App::feedOutboxRead(peerId, d.vmax_id.v, when); App::feedOutboxRead(peerId, d.vmax_id.v, when);
@ -4652,8 +4649,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break; } break;
case mtpc_updateDeleteChannelMessages: { case mtpc_updateDeleteChannelMessages: {
const auto &d(update.c_updateDeleteChannelMessages()); auto &d = update.c_updateDeleteChannelMessages();
ChannelData *channel = App::channelLoaded(d.vchannel_id.v); auto channel = App::channelLoaded(d.vchannel_id.v);
if (channel && !_handlingChannelDifference) { if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference if (channel->ptsRequesting()) { // skip global updates while getting channel difference
@ -4673,8 +4670,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break; } break;
case mtpc_updateChannelTooLong: { case mtpc_updateChannelTooLong: {
const auto &d(update.c_updateChannelTooLong()); auto &d = update.c_updateChannelTooLong();
if (ChannelData *channel = App::channelLoaded(d.vchannel_id.v)) { if (auto channel = App::channelLoaded(d.vchannel_id.v)) {
if (!d.has_pts() || channel->pts() < d.vpts.v) { if (!d.has_pts() || channel->pts() < d.vpts.v) {
getChannelDifference(channel); getChannelDifference(channel);
} }
@ -4682,8 +4679,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break; } break;
case mtpc_updateChannelMessageViews: { case mtpc_updateChannelMessageViews: {
const auto &d(update.c_updateChannelMessageViews()); auto &d = update.c_updateChannelMessageViews();
if (HistoryItem *item = App::histItemById(d.vchannel_id.v, d.vid.v)) { if (auto item = App::histItemById(d.vchannel_id.v, d.vid.v)) {
item->setViewsCount(d.vviews.v); item->setViewsCount(d.vviews.v);
} }
} break; } break;

View file

@ -406,8 +406,7 @@ MainWindow::MainWindow() {
connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock())); connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock()));
connect(this, SIGNAL(imageLoaded()), this, SLOT(notifyUpdateAllPhotos())); subscribe(FileDownload::ImageLoaded(), [this] { notifyUpdateAllPhotos(); });
subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); }); subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); });
setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_NoSystemBackground);

View file

@ -288,9 +288,7 @@ signals:
void tempDirClearFailed(int task); void tempDirClearFailed(int task);
void newAuthorization(); void newAuthorization();
void imageLoaded(); private slots:
private slots:
void onStateChanged(Qt::WindowState state); void onStateChanged(Qt::WindowState state);
void onSettingsDestroyed(QObject *was); void onSettingsDestroyed(QObject *was);

View file

@ -209,6 +209,9 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q
} }
QSize toSize(size.isEmpty() ? QSize(_width, _height) : size); QSize toSize(size.isEmpty() ? QSize(_width, _height) : size);
if (!size.isEmpty() && rotationSwapWidthHeight()) {
toSize.transpose();
}
if (to.isNull() || to.size() != toSize) { if (to.isNull() || to.size() != toSize) {
to = QImage(toSize, QImage::Format_ARGB32); to = QImage(toSize, QImage::Format_ARGB32);
} }
@ -231,6 +234,15 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q
return false; return false;
} }
} }
if (_rotation != Rotation::None) {
QTransform rotationTransform;
switch (_rotation) {
case Rotation::Degrees90: rotationTransform.rotate(90); break;
case Rotation::Degrees180: rotationTransform.rotate(180); break;
case Rotation::Degrees270: rotationTransform.rotate(270); break;
}
to = to.transformed(rotationTransform);
}
// Read some future packets for audio stream. // Read some future packets for audio stream.
if (_audioStreamId >= 0) { if (_audioStreamId >= 0) {
@ -247,6 +259,15 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q
return true; return true;
} }
FFMpegReaderImplementation::Rotation FFMpegReaderImplementation::rotationFromDegrees(int degrees) const {
switch (degrees) {
case 90: return Rotation::Degrees90;
case 180: return Rotation::Degrees180;
case 270: return Rotation::Degrees270;
}
return Rotation::None;
}
bool FFMpegReaderImplementation::start(Mode mode, int64 &positionMs) { bool FFMpegReaderImplementation::start(Mode mode, int64 &positionMs) {
_mode = mode; _mode = mode;
@ -286,6 +307,16 @@ bool FFMpegReaderImplementation::start(Mode mode, int64 &positionMs) {
} }
_packetNull.stream_index = _streamId; _packetNull.stream_index = _streamId;
auto rotateTag = av_dict_get(_fmtContext->streams[_streamId]->metadata, "rotate", NULL, 0);
if (rotateTag && *rotateTag->value) {
auto stringRotateTag = QString::fromUtf8(rotateTag->value);
auto toIntSucceeded = false;
auto rotateDegrees = stringRotateTag.toInt(&toIntSucceeded);
if (toIntSucceeded) {
_rotation = rotationFromDegrees(rotateDegrees);
}
}
_codecContext = avcodec_alloc_context3(nullptr); _codecContext = avcodec_alloc_context3(nullptr);
if (!_codecContext) { if (!_codecContext) {
LOG(("Audio Error: Unable to avcodec_alloc_context3 %1").arg(logData())); LOG(("Audio Error: Unable to avcodec_alloc_context3 %1").arg(logData()));

View file

@ -71,6 +71,17 @@ private:
int64 countPacketMs(AVPacket *packet) const; int64 countPacketMs(AVPacket *packet) const;
PacketResult readAndProcessPacket(); PacketResult readAndProcessPacket();
enum class Rotation {
None,
Degrees90,
Degrees180,
Degrees270,
};
Rotation rotationFromDegrees(int degrees) const;
bool rotationSwapWidthHeight() const {
return (_rotation == Rotation::Degrees90) || (_rotation == Rotation::Degrees270);
}
void startPacket(); void startPacket();
void finishPacket(); void finishPacket();
void clearPacketQueue(); void clearPacketQueue();
@ -80,6 +91,8 @@ private:
Mode _mode = Mode::Normal; Mode _mode = Mode::Normal;
Rotation _rotation = Rotation::None;
uchar *_ioBuffer = nullptr; uchar *_ioBuffer = nullptr;
AVIOContext *_ioContext = nullptr; AVIOContext *_ioContext = nullptr;
AVFormatContext *_fmtContext = nullptr; AVFormatContext *_fmtContext = nullptr;

View file

@ -180,8 +180,8 @@ void Reader::moveToNextWrite() const {
void Reader::callback(Reader *reader, int32 threadIndex, Notification notification) { void Reader::callback(Reader *reader, int32 threadIndex, Notification notification) {
// check if reader is not deleted already // check if reader is not deleted already
if (managers.size() > threadIndex && managers.at(threadIndex)->carries(reader)) { if (managers.size() > threadIndex && managers.at(threadIndex)->carries(reader) && reader->_callback) {
reader->_callback.call(notification); reader->_callback(notification);
} }
} }
@ -588,15 +588,12 @@ void Manager::start(Reader *reader) {
} }
void Manager::update(Reader *reader) { void Manager::update(Reader *reader) {
QReadLocker lock(&_readerPointersMutex); QMutexLocker lock(&_readerPointersMutex);
auto i = _readerPointers.constFind(reader); auto i = _readerPointers.find(reader);
if (i == _readerPointers.cend()) { if (i == _readerPointers.cend()) {
lock.unlock(); _readerPointers.insert(reader, QAtomicInt(1));
QWriteLocker lock(&_readerPointersMutex);
_readerPointers.insert(reader, MutableAtomicInt(1));
} else { } else {
i->v.storeRelease(1); i->storeRelease(1);
} }
emit processDelayed(); emit processDelayed();
} }
@ -604,13 +601,13 @@ void Manager::update(Reader *reader) {
void Manager::stop(Reader *reader) { void Manager::stop(Reader *reader) {
if (!carries(reader)) return; if (!carries(reader)) return;
QWriteLocker lock(&_readerPointersMutex); QMutexLocker lock(&_readerPointersMutex);
_readerPointers.remove(reader); _readerPointers.remove(reader);
emit processDelayed(); emit processDelayed();
} }
bool Manager::carries(Reader *reader) const { bool Manager::carries(Reader *reader) const {
QReadLocker lock(&_readerPointersMutex); QMutexLocker lock(&_readerPointersMutex);
return _readerPointers.contains(reader); return _readerPointers.contains(reader);
} }
@ -629,19 +626,13 @@ Manager::ReaderPointers::const_iterator Manager::constUnsafeFindReaderPointer(Re
} }
bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, uint64 ms) { bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, uint64 ms) {
QReadLocker lock(&_readerPointersMutex); QMutexLocker lock(&_readerPointersMutex);
auto it = constUnsafeFindReaderPointer(reader); auto it = unsafeFindReaderPointer(reader);
if (result == ProcessResult::Error) { if (result == ProcessResult::Error) {
if (it != _readerPointers.cend()) { if (it != _readerPointers.cend()) {
lock.unlock(); it.key()->error();
QWriteLocker lock(&_readerPointersMutex); emit callback(it.key(), it.key()->threadIndex(), NotificationReinit);
_readerPointers.erase(it);
auto i = unsafeFindReaderPointer(reader);
if (i != _readerPointers.cend()) {
i.key()->error();
emit callback(i.key(), i.key()->threadIndex(), NotificationReinit);
_readerPointers.erase(i);
}
} }
return false; return false;
} else if (result == ProcessResult::Finished) { } else if (result == ProcessResult::Finished) {
@ -663,8 +654,8 @@ bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, u
// See if we need to pause GIF because it is not displayed right now. // See if we need to pause GIF because it is not displayed right now.
if (!reader->_autoPausedGif && reader->_mode == Reader::Mode::Gif && result == ProcessResult::Repaint) { if (!reader->_autoPausedGif && reader->_mode == Reader::Mode::Gif && result == ProcessResult::Repaint) {
int32 ishowing, iprevious; int32 ishowing, iprevious;
Reader::Frame *showing = it.key()->frameToShow(&ishowing), *previous = it.key()->frameToWriteNext(false, &iprevious); auto showing = it.key()->frameToShow(&ishowing), previous = it.key()->frameToWriteNext(false, &iprevious);
t_assert(previous != 0 && showing != 0 && ishowing >= 0 && iprevious >= 0); t_assert(previous != nullptr && showing != nullptr && ishowing >= 0 && iprevious >= 0);
if (reader->_frames[ishowing].when > 0 && showing->displayed.loadAcquire() <= 0) { // current frame was not shown if (reader->_frames[ishowing].when > 0 && showing->displayed.loadAcquire() <= 0) { // current frame was not shown
if (reader->_frames[ishowing].when + WaitBeforeGifPause < ms || (reader->_frames[iprevious].when && previous->displayed.loadAcquire() <= 0)) { if (reader->_frames[ishowing].when + WaitBeforeGifPause < ms || (reader->_frames[iprevious].when && previous->displayed.loadAcquire() <= 0)) {
reader->_autoPausedGif = true; reader->_autoPausedGif = true;
@ -675,7 +666,7 @@ bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, u
} }
if (result == ProcessResult::Started || result == ProcessResult::CopyFrame) { if (result == ProcessResult::Started || result == ProcessResult::CopyFrame) {
t_assert(reader->_frame >= 0); t_assert(reader->_frame >= 0);
Reader::Frame *frame = it.key()->_frames + reader->_frame; auto frame = it.key()->_frames + reader->_frame;
frame->clear(); frame->clear();
frame->pix = reader->frame()->pix; frame->pix = reader->frame()->pix;
frame->original = reader->frame()->original; frame->original = reader->frame()->original;
@ -710,8 +701,8 @@ Manager::ResultHandleState Manager::handleResult(ReaderPrivate *reader, ProcessR
if (result == ProcessResult::Repaint) { if (result == ProcessResult::Repaint) {
{ {
QReadLocker lock(&_readerPointersMutex); QMutexLocker lock(&_readerPointersMutex);
ReaderPointers::const_iterator it = constUnsafeFindReaderPointer(reader); auto it = constUnsafeFindReaderPointer(reader);
if (it != _readerPointers.cend()) { if (it != _readerPointers.cend()) {
int32 index = 0; int32 index = 0;
Reader *r = it.key(); Reader *r = it.key();
@ -742,9 +733,9 @@ void Manager::process() {
bool checkAllReaders = false; bool checkAllReaders = false;
uint64 ms = getms(), minms = ms + 86400 * 1000ULL; uint64 ms = getms(), minms = ms + 86400 * 1000ULL;
{ {
QReadLocker lock(&_readerPointersMutex); QMutexLocker lock(&_readerPointersMutex);
for (auto it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) { for (auto it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) {
if (it->v.loadAcquire() && it.key()->_private != nullptr) { if (it->loadAcquire() && it.key()->_private != nullptr) {
auto i = _readers.find(it.key()->_private); auto i = _readers.find(it.key()->_private);
if (i == _readers.cend()) { if (i == _readers.cend()) {
_readers.insert(it.key()->_private, 0); _readers.insert(it.key()->_private, 0);
@ -759,9 +750,9 @@ void Manager::process() {
i.key()->resumeVideo(ms); i.key()->resumeVideo(ms);
} }
} }
Reader::Frame *frame = it.key()->frameToWrite(); auto frame = it.key()->frameToWrite();
if (frame) it.key()->_private->_request = frame->request; if (frame) it.key()->_private->_request = frame->request;
it->v.storeRelease(0); it->storeRelease(0);
} }
} }
checkAllReaders = (_readers.size() > _readerPointers.size()); checkAllReaders = (_readers.size() > _readerPointers.size());
@ -787,8 +778,8 @@ void Manager::process() {
i.value() = (ms + 86400 * 1000ULL); i.value() = (ms + 86400 * 1000ULL);
} }
} else if (checkAllReaders) { } else if (checkAllReaders) {
QReadLocker lock(&_readerPointersMutex); QMutexLocker lock(&_readerPointersMutex);
ReaderPointers::const_iterator it = constUnsafeFindReaderPointer(reader); auto it = constUnsafeFindReaderPointer(reader);
if (it == _readerPointers.cend()) { if (it == _readerPointers.cend()) {
_loadLevel.fetchAndAddRelaxed(-1 * (reader->_width > 0 ? reader->_width * reader->_height : AverageGifSize)); _loadLevel.fetchAndAddRelaxed(-1 * (reader->_width > 0 ? reader->_width * reader->_height : AverageGifSize));
delete reader; delete reader;
@ -820,8 +811,8 @@ void Manager::finish() {
void Manager::clear() { void Manager::clear() {
{ {
QWriteLocker lock(&_readerPointersMutex); QMutexLocker lock(&_readerPointersMutex);
for (ReaderPointers::iterator it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) { for (auto it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) {
it.key()->_private = nullptr; it.key()->_private = nullptr;
} }
_readerPointers.clear(); _readerPointers.clear();

View file

@ -52,7 +52,7 @@ enum ReaderSteps {
class ReaderPrivate; class ReaderPrivate;
class Reader { class Reader {
public: public:
using Callback = Function<void, Notification>; using Callback = base::lambda_unique<void(Notification)>;
enum class Mode { enum class Mode {
Gif, Gif,
Video, Video,
@ -211,14 +211,9 @@ private:
void clear(); void clear();
QAtomicInt _loadLevel; QAtomicInt _loadLevel;
struct MutableAtomicInt { using ReaderPointers = QMap<Reader*, QAtomicInt>;
MutableAtomicInt(int value) : v(value) {
}
mutable QAtomicInt v;
};
typedef QMap<Reader*, MutableAtomicInt> ReaderPointers;
ReaderPointers _readerPointers; ReaderPointers _readerPointers;
mutable QReadWriteLock _readerPointersMutex; mutable QMutex _readerPointersMutex;
ReaderPointers::const_iterator constUnsafeFindReaderPointer(ReaderPrivate *reader) const; ReaderPointers::const_iterator constUnsafeFindReaderPointer(ReaderPrivate *reader) const;
ReaderPointers::iterator unsafeFindReaderPointer(ReaderPrivate *reader); ReaderPointers::iterator unsafeFindReaderPointer(ReaderPrivate *reader);

View file

@ -66,9 +66,7 @@ void TitleButton::updatePauseState() {
void TitleButton::setShowPause(bool showPause) { void TitleButton::setShowPause(bool showPause) {
if (_showPause != showPause) { if (_showPause != showPause) {
_showPause = showPause; _showPause = showPause;
START_ANIMATION(_iconTransformToPause, func([this]() { _iconTransformToPause.start([this] { update(); }, _showPause ? 0. : 1., _showPause ? 1. : 0., st::mediaPlayerTitleButtonTransformDuration);
update();
}), _showPause ? 0. : 1., _showPause ? 1. : 0., st::mediaPlayerTitleButtonTransformDuration, anim::linear);
update(); update();
} }
} }
@ -97,9 +95,7 @@ void TitleButton::paintEvent(QPaintEvent *e) {
void TitleButton::onStateChanged(int oldState, ButtonStateChangeSource source) { void TitleButton::onStateChanged(int oldState, ButtonStateChangeSource source) {
if ((oldState & StateOver) != (_state & StateOver)) { if ((oldState & StateOver) != (_state & StateOver)) {
auto over = (_state & StateOver); auto over = (_state & StateOver);
START_ANIMATION(_iconFg, func([this]() { _iconFg.start([this] { update(); }, over ? st::titleButtonFg->c : st::titleButtonActiveFg->c, over ? st::titleButtonActiveFg->c : st::titleButtonFg->c, st::titleButtonDuration);
update();
}), over ? st::titleButtonFg->c : st::titleButtonActiveFg->c, over ? st::titleButtonActiveFg->c : st::titleButtonFg->c, st::titleButtonDuration, anim::linear);
} }
} }

View file

@ -56,7 +56,10 @@ Instance::Instance() {
handleSongUpdate(audioId); handleSongUpdate(audioId);
} }
}); });
Notify::registerPeerObserver(Notify::PeerUpdate::Flag::SharedMediaChanged, this, &Instance::notifyPeerUpdated); auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
} }
void Instance::notifyPeerUpdated(const Notify::PeerUpdate &update) { void Instance::notifyPeerUpdated(const Notify::PeerUpdate &update) {

View file

@ -53,7 +53,7 @@ struct UpdatedEvent {
const AudioPlaybackState *playbackState; const AudioPlaybackState *playbackState;
}; };
class Instance : private base::Subscriber, public Notify::Observer { class Instance : private base::Subscriber {
public: public:
void play(); void play();
void pause(); void pause();

View file

@ -51,7 +51,7 @@ Widget::Widget(QWidget *parent) : TWidget(parent)
} }
bool Widget::overlaps(const QRect &globalRect) { bool Widget::overlaps(const QRect &globalRect) {
if (isHidden() || !_a_appearance.isNull()) return false; if (isHidden() || _a_appearance.animating()) return false;
auto marginLeft = rtl() ? 0 : contentLeft(); auto marginLeft = rtl() ? 0 : contentLeft();
auto marginRight = rtl() ? contentLeft() : 0; auto marginRight = rtl() ? contentLeft() : 0;
@ -171,18 +171,18 @@ void Widget::onHideStart() {
void Widget::startAnimation() { void Widget::startAnimation() {
auto from = _hiding ? 1. : 0.; auto from = _hiding ? 1. : 0.;
auto to = _hiding ? 0. : 1.; auto to = _hiding ? 0. : 1.;
if (_a_appearance.isNull()) { if (!_a_appearance.animating()) {
showChildren(); showChildren();
_cache = myGrab(this); _cache = myGrab(this);
} }
hideChildren(); hideChildren();
START_ANIMATION(_a_appearance, func([this]() { _a_appearance.start([this]() {
update(); update();
if (!_a_appearance.animating(getms()) && _hiding) { if (!_a_appearance.animating(getms()) && _hiding) {
_hiding = false; _hiding = false;
hidingFinished(); hidingFinished();
} }
}), from, to, st::defaultInnerDropdown.duration, anim::linear); }, from, to, st::defaultInnerDropdown.duration);
} }
void Widget::hidingFinished() { void Widget::hidingFinished() {

View file

@ -41,8 +41,8 @@ Controller::Controller(QWidget *parent) : TWidget(parent)
, _toPlayLeft(this, st::mediaviewPlayProgressLabel) , _toPlayLeft(this, st::mediaviewPlayProgressLabel)
, _fadeAnimation(std_::make_unique<Ui::FadeAnimation>(this)) { , _fadeAnimation(std_::make_unique<Ui::FadeAnimation>(this)) {
_fadeAnimation->show(); _fadeAnimation->show();
_fadeAnimation->setFinishedCallback(func(this, &Controller::fadeFinished)); _fadeAnimation->setFinishedCallback([this] { fadeFinished(); });
_fadeAnimation->setUpdatedCallback(func(this, &Controller::fadeUpdated)); _fadeAnimation->setUpdatedCallback([this](float64 opacity) { fadeUpdated(opacity); });
_volumeController->setVolume(Global::VideoVolume()); _volumeController->setVolume(Global::VideoVolume());

View file

@ -55,6 +55,7 @@ void Playback::updateState(const AudioPlaybackState &playbackState) {
_position = position; _position = position;
_duration = duration; _duration = duration;
} }
_slider->update();
} }
} // namespace Clip } // namespace Clip

View file

@ -100,7 +100,7 @@ void VolumeController::setOver(bool over) {
_over = over; _over = over;
auto from = _over ? 0. : 1., to = _over ? 1. : 0.; auto from = _over ? 0. : 1., to = _over ? 1. : 0.;
START_ANIMATION(_a_over, func(this, &VolumeController::updateCallback), from, to, st::mediaviewOverDuration, anim::linear); _a_over.start([this] { update(); }, from, to, st::mediaviewOverDuration);
} }
} // namespace Clip } // namespace Clip

View file

@ -43,9 +43,6 @@ protected:
void leaveEvent(QEvent *e) override; void leaveEvent(QEvent *e) override;
private: private:
void updateCallback() {
update();
}
void setOver(bool over); void setOver(bool over);
void changeVolume(float64 newVolume); void changeVolume(float64 newVolume);

View file

@ -1368,7 +1368,9 @@ void MediaView::createClipReader() {
_current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixSmooth | ImagePixBlurred, st::mvDocIconSize, st::mvDocIconSize); _current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixSmooth | ImagePixBlurred, st::mvDocIconSize, st::mvDocIconSize);
} }
auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif; auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif;
_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), mode); _gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) {
clipCallback(notification);
}, mode);
// Correct values will be set when gif gets inited. // Correct values will be set when gif gets inited.
_videoPaused = _videoIsSilent = _videoStopped = false; _videoPaused = _videoIsSilent = _videoStopped = false;
@ -1439,7 +1441,9 @@ void MediaView::restartVideoAtSeekPosition(int64 positionMs) {
if (_current.isNull()) { if (_current.isNull()) {
_current = _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), getms()); _current = _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), getms());
} }
_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), Media::Clip::Reader::Mode::Video, positionMs); _gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) {
clipCallback(notification);
}, Media::Clip::Reader::Mode::Video, positionMs);
// Correct values will be set when gif gets inited. // Correct values will be set when gif gets inited.
_videoPaused = _videoIsSilent = _videoStopped = false; _videoPaused = _videoIsSilent = _videoStopped = false;

View file

@ -206,7 +206,7 @@ namespace {
} }
req = i.value(); req = i.value();
} }
if (internal::Session *session = internal::getSession(newdcWithShift)) { if (auto session = internal::getSession(newdcWithShift)) {
internal::registerRequest(requestId, (dcWithShift < 0) ? -newdcWithShift : newdcWithShift); internal::registerRequest(requestId, (dcWithShift < 0) ? -newdcWithShift : newdcWithShift);
session->sendPrepared(req); session->sendPrepared(req);
} }

View file

@ -207,9 +207,8 @@ void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray &
_fileIsOpen = false; _fileIsOpen = false;
psPostprocessFile(QFileInfo(_file).absoluteFilePath()); psPostprocessFile(QFileInfo(_file).absoluteFilePath());
} }
emit App::wnd()->imageLoaded();
emit progress(this); emit progress(this);
FileDownload::internal::notifyImageLoaded(); FileDownload::ImageLoaded().notify();
loadNext(); loadNext();
} }
@ -516,8 +515,6 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
} }
removeFromQueue(); removeFromQueue();
emit App::wnd()->imageLoaded();
if (!_queue->queries) { if (!_queue->queries) {
App::app()->killDownloadSessionsStart(_dc); App::app()->killDownloadSessionsStart(_dc);
} }
@ -544,7 +541,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
} }
emit progress(this); emit progress(this);
if (_complete) { if (_complete) {
FileDownload::internal::notifyImageLoaded(); FileDownload::ImageLoaded().notify();
} }
loadNext(); loadNext();
} }
@ -669,13 +666,11 @@ void webFileLoader::onFinished(const QByteArray &data) {
} }
removeFromQueue(); removeFromQueue();
emit App::wnd()->imageLoaded();
if (_localStatus == LocalNotFound || _localStatus == LocalFailed) { if (_localStatus == LocalNotFound || _localStatus == LocalFailed) {
Local::writeWebFile(_url, _data); Local::writeWebFile(_url, _data);
} }
emit progress(this); emit progress(this);
FileDownload::internal::notifyImageLoaded(); FileDownload::ImageLoaded().notify();
loadNext(); loadNext();
} }
@ -1093,21 +1088,12 @@ namespace MTP {
namespace FileDownload { namespace FileDownload {
namespace { namespace {
using internal::ImageLoadedHandler; base::Observable<void> ImageLoadedObservable;
Notify::SimpleObservedEventRegistrator<ImageLoadedHandler> creator(nullptr, nullptr);
} // namespace } // namespace
namespace internal { base::Observable<void> &ImageLoaded() {
return ImageLoadedObservable;
Notify::ConnectionId plainRegisterImageLoadedObserver(ImageLoadedHandler &&handler) {
return creator.registerObserver(std_::forward<ImageLoadedHandler>(handler));
} }
void notifyImageLoaded() { } // namespace FileDownload
creator.notify();
}
} // namespace internal
}

View file

@ -396,19 +396,7 @@ void reinitWebLoadManager();
void stopWebLoadManager(); void stopWebLoadManager();
namespace FileDownload { namespace FileDownload {
namespace internal {
using ImageLoadedHandler = Function<void>; base::Observable<void> &ImageLoaded();
Notify::ConnectionId plainRegisterImageLoadedObserver(ImageLoadedHandler &&handler);
void notifyImageLoaded();
} // namespace internal
template <typename ObserverType>
void registerImageLoadedObserver(ObserverType *observer, void (ObserverType::*handler)()) {
auto connection = internal::plainRegisterImageLoadedObserver(func(observer, handler));
Notify::observerRegistered(observer, connection);
}
} // namespace FileDownload } // namespace FileDownload

View file

@ -31,8 +31,6 @@ void emitPeerUpdated();
namespace Notify { namespace Notify {
namespace { namespace {
using internal::PeerUpdateHandler;
using SmallUpdatesList = QVector<PeerUpdate>; using SmallUpdatesList = QVector<PeerUpdate>;
NeverFreedPointer<SmallUpdatesList> SmallUpdates; NeverFreedPointer<SmallUpdatesList> SmallUpdates;
using AllUpdatesList = QMap<PeerData*, PeerUpdate>; using AllUpdatesList = QMap<PeerData*, PeerUpdate>;
@ -46,19 +44,11 @@ void FinishCallback() {
SmallUpdates.clear(); SmallUpdates.clear();
AllUpdates.clear(); AllUpdates.clear();
} }
ObservedEventRegistrator<PeerUpdate::Flags, PeerUpdateHandler> creator(StartCallback, FinishCallback);
base::Observable<PeerUpdate, PeerUpdatedHandler> PeerUpdatedObservable;
} // namespace } // namespace
namespace internal {
ConnectionId plainRegisterPeerObserver(PeerUpdate::Flags events, PeerUpdateHandler &&handler) {
constexpr auto tmp = sizeof(PeerUpdate);
return creator.registerObserver(events, std_::forward<PeerUpdateHandler>(handler));
}
} // namespace internal
void mergePeerUpdate(PeerUpdate &mergeTo, const PeerUpdate &mergeFrom) { void mergePeerUpdate(PeerUpdate &mergeTo, const PeerUpdate &mergeFrom) {
if (!(mergeTo.flags & PeerUpdate::Flag::NameChanged)) { if (!(mergeTo.flags & PeerUpdate::Flag::NameChanged)) {
if (mergeFrom.flags & PeerUpdate::Flag::NameChanged) { if (mergeFrom.flags & PeerUpdate::Flag::NameChanged) {
@ -73,7 +63,8 @@ void mergePeerUpdate(PeerUpdate &mergeTo, const PeerUpdate &mergeFrom) {
} }
void peerUpdatedDelayed(const PeerUpdate &update) { void peerUpdatedDelayed(const PeerUpdate &update) {
t_assert(creator.started()); SmallUpdates.makeIfNull();
AllUpdates.makeIfNull();
Global::RefHandleDelayedPeerUpdates().call(); Global::RefHandleDelayedPeerUpdates().call();
@ -85,6 +76,7 @@ void peerUpdatedDelayed(const PeerUpdate &update) {
return; return;
} }
} }
if (AllUpdates->isEmpty()) { if (AllUpdates->isEmpty()) {
if (existingUpdatesCount < 5) { if (existingUpdatesCount < 5) {
SmallUpdates->push_back(update); SmallUpdates->push_back(update);
@ -102,24 +94,27 @@ void peerUpdatedDelayed(const PeerUpdate &update) {
} }
void peerUpdatedSendDelayed() { void peerUpdatedSendDelayed() {
if (!creator.started()) return;
App::emitPeerUpdated(); App::emitPeerUpdated();
if (SmallUpdates->isEmpty()) return; if (!SmallUpdates || !AllUpdates || SmallUpdates->empty()) return;
auto smallList = createAndSwap(*SmallUpdates); auto smallList = createAndSwap(*SmallUpdates);
auto allList = createAndSwap(*AllUpdates); auto allList = createAndSwap(*AllUpdates);
for_const (auto &update, smallList) { for (auto &update : smallList) {
creator.notify(update.flags, update); PeerUpdated().notify(std_::move(update), true);
} }
for_const (auto &update, allList) { for (auto &update : allList) {
creator.notify(update.flags, update); PeerUpdated().notify(std_::move(update), true);
} }
if (SmallUpdates->isEmpty()) { if (SmallUpdates->isEmpty()) {
std::swap(smallList, *SmallUpdates); std::swap(smallList, *SmallUpdates);
SmallUpdates->resize(0); SmallUpdates->resize(0);
} }
} }
base::Observable<PeerUpdate, PeerUpdatedHandler> &PeerUpdated() {
return PeerUpdatedObservable;
}
} // namespace Notify } // namespace Notify

View file

@ -89,17 +89,22 @@ inline void peerUpdatedDelayed(PeerData *peer, PeerUpdate::Flags events) {
} }
void peerUpdatedSendDelayed(); void peerUpdatedSendDelayed();
namespace internal { class PeerUpdatedHandler {
public:
template <typename Lambda>
PeerUpdatedHandler(PeerUpdate::Flags events, Lambda &&handler) : _events(events), _handler(std_::move(handler)) {
}
void operator()(const PeerUpdate &update) const {
if (update.flags & _events) {
_handler(update);
}
}
using PeerUpdateHandler = Function<void, const PeerUpdate&>; private:
ConnectionId plainRegisterPeerObserver(PeerUpdate::Flags events, PeerUpdateHandler &&handler); PeerUpdate::Flags _events;
base::lambda_unique<void(const PeerUpdate&)> _handler;
} // namespace internal };
base::Observable<PeerUpdate, PeerUpdatedHandler> &PeerUpdated();
template <typename ObserverType>
void registerPeerObserver(PeerUpdate::Flags events, ObserverType *observer, void (ObserverType::*handler)(const PeerUpdate &)) {
auto connection = internal::plainRegisterPeerObserver(events, func(observer, handler));
observerRegistered(observer, connection);
}
} // namespace Notify } // namespace Notify

View file

@ -89,7 +89,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD
, _touchAccelerationTime(0) , _touchAccelerationTime(0)
, _touchTime(0) , _touchTime(0)
, _menu(0) { , _menu(0) {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); subscribe(FileDownload::ImageLoaded(), [this] { update(); });
resize(_width, st::wndMinHeight); resize(_width, st::wndMinHeight);

View file

@ -33,7 +33,7 @@ class Date;
} // namespace Overview } // namespace Overview
class OverviewWidget; class OverviewWidget;
class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender { class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -39,7 +39,9 @@ ActionsWidget::ActionsWidget(QWidget *parent, PeerData *peer) : BlockWidget(pare
| UpdateFlag::UserIsBlocked | UpdateFlag::UserIsBlocked
| UpdateFlag::BotCommandsChanged | UpdateFlag::BotCommandsChanged
| UpdateFlag::MembersChanged; | UpdateFlag::MembersChanged;
Notify::registerPeerObserver(observeEvents, this, &ActionsWidget::notifyPeerUpdated); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
validateBlockStatus(); validateBlockStatus();
refreshButtons(); refreshButtons();

View file

@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Profile { namespace Profile {
class BlockWidget : public ScrolledWidget, public Notify::Observer { class BlockWidget : public ScrolledWidget, protected base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -68,8 +68,12 @@ CoverWidget::CoverWidget(QWidget *parent, PeerData *peer) : TWidget(parent)
auto observeEvents = ButtonsUpdateFlags auto observeEvents = ButtonsUpdateFlags
| UpdateFlag::NameChanged | UpdateFlag::NameChanged
| UpdateFlag::UserOnlineChanged; | UpdateFlag::UserOnlineChanged;
Notify::registerPeerObserver(observeEvents, this, &CoverWidget::notifyPeerUpdated); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
FileDialog::registerObserver(this, &CoverWidget::notifyFileQueryUpdated); notifyPeerUpdated(update);
}));
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
notifyFileQueryUpdated(update);
});
connect(App::app(), SIGNAL(peerPhotoDone(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId))); connect(App::app(), SIGNAL(peerPhotoDone(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId)));
connect(App::app(), SIGNAL(peerPhotoFail(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId))); connect(App::app(), SIGNAL(peerPhotoFail(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId)));
@ -285,7 +289,7 @@ void CoverWidget::dragEnterEvent(QDragEnterEvent *e) {
void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) { void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) {
if (_dropArea && !_dropArea->hiding()) { if (_dropArea && !_dropArea->hiding()) {
_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); _dropArea->hideAnimated([this](CoverDropArea *area) { dropAreaHidden(area); });
} }
} }
@ -306,7 +310,7 @@ void CoverWidget::dropEvent(QDropEvent *e) {
} }
if (!_dropArea->hiding()) { if (!_dropArea->hiding()) {
_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); _dropArea->hideAnimated([this](CoverDropArea *area) { dropAreaHidden(area); });
} }
e->acceptProposedAction(); e->acceptProposedAction();

View file

@ -40,7 +40,7 @@ class BackButton;
class UserpicButton; class UserpicButton;
class CoverDropArea; class CoverDropArea;
class CoverWidget final : public TWidget, public Notify::Observer { class CoverWidget final : public TWidget, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -57,7 +57,9 @@ void CoverDropArea::paintEvent(QPaintEvent *e) {
_cache = QPixmap(); _cache = QPixmap();
if (_hiding) { if (_hiding) {
hide(); hide();
_hideFinishCallback.call(this); if (_hideFinishCallback) {
_hideFinishCallback(this);
}
return; return;
} }
} }
@ -93,7 +95,7 @@ void CoverDropArea::setupAnimation() {
_cache = myGrab(this); _cache = myGrab(this);
} }
auto from = _hiding ? 1. : 0., to = _hiding ? 0. : 1.; auto from = _hiding ? 1. : 0., to = _hiding ? 0. : 1.;
START_ANIMATION(_a_appearance, func(this, &CoverDropArea::refreshCallback), from, to, st::profileDropAreaDuration, anim::linear); _a_appearance.start([this]() { update(); }, from, to, st::profileDropAreaDuration);
} }
} // namespace Profile } // namespace Profile

View file

@ -28,7 +28,7 @@ public:
void showAnimated(); void showAnimated();
using HideFinishCallback = Function<void, CoverDropArea*>; using HideFinishCallback = base::lambda_unique<void(CoverDropArea*)>;
void hideAnimated(HideFinishCallback &&callback); void hideAnimated(HideFinishCallback &&callback);
bool hiding() const { bool hiding() const {
@ -39,9 +39,6 @@ protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
private: private:
void refreshCallback() {
update();
}
void setupAnimation(); void setupAnimation();
QString _title, _subtitle; QString _title, _subtitle;

View file

@ -83,7 +83,9 @@ FixedBar::FixedBar(QWidget *parent, PeerData *peer) : TWidget(parent)
auto observeEvents = ButtonsUpdateFlags auto observeEvents = ButtonsUpdateFlags
| UpdateFlag::MigrationChanged; | UpdateFlag::MigrationChanged;
Notify::registerPeerObserver(observeEvents, this, &FixedBar::notifyPeerUpdate); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdate(update);
}));
refreshRightActions(); refreshRightActions();
} }

View file

@ -34,7 +34,7 @@ namespace Profile {
class BackButton; class BackButton;
class FixedBar final : public TWidget, public Notify::Observer { class FixedBar final : public TWidget, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -36,7 +36,9 @@ InfoWidget::InfoWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, pe
| UpdateFlag::UsernameChanged | UpdateFlag::UsernameChanged
| UpdateFlag::UserPhoneChanged | UpdateFlag::UserPhoneChanged
| UpdateFlag::UserCanShareContact; | UpdateFlag::UserCanShareContact;
Notify::registerPeerObserver(observeEvents, this, &InfoWidget::notifyPeerUpdated); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
refreshLabels(); refreshLabels();
} }
@ -149,15 +151,13 @@ void InfoWidget::refreshAbout() {
textParseEntities(aboutText, TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands, &aboutEntities); textParseEntities(aboutText, TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands, &aboutEntities);
_about->setMarkedText({ aboutText, aboutEntities }); _about->setMarkedText({ aboutText, aboutEntities });
_about->setSelectable(true); _about->setSelectable(true);
_about->setClickHandlerHook(func(this, &InfoWidget::aboutClickHandlerHook)); _about->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) {
BotCommandClickHandler::setPeerForCommand(peer());
return true;
});
} }
} }
bool InfoWidget::aboutClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) {
BotCommandClickHandler::setPeerForCommand(peer());
return true;
}
void InfoWidget::refreshMobileNumber() { void InfoWidget::refreshMobileNumber() {
TextWithEntities phoneText; TextWithEntities phoneText;
if (auto user = peer()->asUser()) { if (auto user = peer()->asUser()) {

View file

@ -51,8 +51,6 @@ private:
void refreshChannelLink(); void refreshChannelLink();
void refreshVisibility(); void refreshVisibility();
bool aboutClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
// labelWidget may be nullptr. // labelWidget may be nullptr.
void setLabeledText(ChildWidget<FlatLabel> *labelWidget, const QString &label, void setLabeledText(ChildWidget<FlatLabel> *labelWidget, const QString &label,
ChildWidget<FlatLabel> *textWidget, const TextWithEntities &textWithEntities, const QString &copyText); ChildWidget<FlatLabel> *textWidget, const TextWithEntities &textWithEntities, const QString &copyText);

View file

@ -33,7 +33,9 @@ using UpdateFlag = Notify::PeerUpdate::Flag;
InviteLinkWidget::InviteLinkWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_invite_link_section)) { InviteLinkWidget::InviteLinkWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_invite_link_section)) {
auto observeEvents = UpdateFlag::InviteLinkChanged | UpdateFlag::UsernameChanged; auto observeEvents = UpdateFlag::InviteLinkChanged | UpdateFlag::UsernameChanged;
Notify::registerPeerObserver(observeEvents, this, &InviteLinkWidget::notifyPeerUpdated); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
refreshLink(); refreshLink();
refreshVisibility(); refreshVisibility();
@ -99,19 +101,17 @@ void InviteLinkWidget::refreshLink() {
_link->setMarkedText(linkData); _link->setMarkedText(linkData);
_link->setSelectable(true); _link->setSelectable(true);
_link->setContextCopyText(QString()); _link->setContextCopyText(QString());
_link->setClickHandlerHook(func(this, &InviteLinkWidget::clickHandlerHook)); _link->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) {
} auto link = getInviteLink();
} if (link.isEmpty()) {
return true;
}
bool InviteLinkWidget::clickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) { QApplication::clipboard()->setText(link);
auto link = getInviteLink(); Ui::showLayer(new InformBox(lang(lng_group_invite_copied)));
if (link.isEmpty()) { return false;
return true; });
} }
QApplication::clipboard()->setText(link);
Ui::showLayer(new InformBox(lang(lng_group_invite_copied)));
return false;
} }
} // namespace Profile } // namespace Profile

View file

@ -46,8 +46,6 @@ private:
void refreshLink(); void refreshLink();
void refreshVisibility(); void refreshVisibility();
bool clickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
ChildWidget<FlatLabel> _link = { nullptr }; ChildWidget<FlatLabel> _link = { nullptr };
}; };

View file

@ -49,16 +49,14 @@ MembersWidget::MembersWidget(QWidget *parent, PeerData *peer, TitleVisibility ti
auto observeEvents = UpdateFlag::AdminsChanged auto observeEvents = UpdateFlag::AdminsChanged
| UpdateFlag::MembersChanged | UpdateFlag::MembersChanged
| UpdateFlag::UserOnlineChanged; | UpdateFlag::UserOnlineChanged;
Notify::registerPeerObserver(observeEvents, this, &MembersWidget::notifyPeerUpdated); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
FileDownload::registerImageLoadedObserver(this, &MembersWidget::repaintCallback); notifyPeerUpdated(update);
}));
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
refreshMembers(); refreshMembers();
} }
void MembersWidget::repaintCallback() {
update();
}
void MembersWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) { void MembersWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
if (update.peer != peer()) { if (update.peer != peer()) {
if (update.flags & UpdateFlag::UserOnlineChanged) { if (update.flags & UpdateFlag::UserOnlineChanged) {
@ -83,7 +81,7 @@ void MembersWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
} }
} }
} }
repaintCallback(); this->update();
} }
void MembersWidget::refreshUserOnline(UserData *user) { void MembersWidget::refreshUserOnline(UserData *user) {
@ -315,17 +313,15 @@ void MembersWidget::refreshLimitReached() {
QString link = textRichPrepare(lang(lng_profile_migrate_learn_more)); QString link = textRichPrepare(lang(lng_profile_migrate_learn_more));
QString text = qsl("%1%2%3\n%4 [a href=\"https://telegram.org/blog/supergroups5k\"]%5[/a]").arg(textcmdStartSemibold()).arg(title).arg(textcmdStopSemibold()).arg(body).arg(link); QString text = qsl("%1%2%3\n%4 [a href=\"https://telegram.org/blog/supergroups5k\"]%5[/a]").arg(textcmdStartSemibold()).arg(title).arg(textcmdStopSemibold()).arg(body).arg(link);
_limitReachedInfo->setRichText(text); _limitReachedInfo->setRichText(text);
_limitReachedInfo->setClickHandlerHook(func(this, &MembersWidget::limitReachedHook)); _limitReachedInfo->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new ConvertToSupergroupBox(peer()->asChat()));
return false;
});
} else if (!limitReachedShown && _limitReachedInfo) { } else if (!limitReachedShown && _limitReachedInfo) {
_limitReachedInfo.destroy(); _limitReachedInfo.destroy();
} }
} }
bool MembersWidget::limitReachedHook(const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new ConvertToSupergroupBox(peer()->asChat()));
return false;
}
void MembersWidget::checkSelfAdmin(ChatData *chat) { void MembersWidget::checkSelfAdmin(ChatData *chat) {
if (chat->participants.isEmpty()) return; if (chat->participants.isEmpty()) return;
@ -608,7 +604,9 @@ ChannelMembersWidget::ChannelMembersWidget(QWidget *parent, PeerData *peer) : Bl
| UpdateFlag::ChannelCanViewMembers | UpdateFlag::ChannelCanViewMembers
| UpdateFlag::AdminsChanged | UpdateFlag::AdminsChanged
| UpdateFlag::MembersChanged; | UpdateFlag::MembersChanged;
Notify::registerPeerObserver(observeEvents, this, &ChannelMembersWidget::notifyPeerUpdated); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
refreshButtons(); refreshButtons();
} }

View file

@ -78,7 +78,6 @@ private slots:
private: private:
// Observed notifications. // Observed notifications.
void notifyPeerUpdated(const Notify::PeerUpdate &update); void notifyPeerUpdated(const Notify::PeerUpdate &update);
void repaintCallback();
void preloadUserPhotos(); void preloadUserPhotos();

View file

@ -51,7 +51,9 @@ SettingsWidget::SettingsWidget(QWidget *parent, PeerData *peer) : BlockWidget(pa
observeEvents |= UpdateFlag::UsernameChanged | UpdateFlag::InviteLinkChanged; observeEvents |= UpdateFlag::UsernameChanged | UpdateFlag::InviteLinkChanged;
} }
} }
Notify::registerPeerObserver(observeEvents, this, &SettingsWidget::notifyPeerUpdated); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
refreshButtons(); refreshButtons();
_enableNotifications->finishAnimations(); _enableNotifications->finishAnimations();

View file

@ -51,7 +51,10 @@ QString getButtonText(MediaOverviewType type, int count) {
SharedMediaWidget::SharedMediaWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_shared_media)) SharedMediaWidget::SharedMediaWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_shared_media))
, _history(App::history(peer)) , _history(App::history(peer))
, _migrated(peer->migrateFrom() ? App::history(peer->migrateFrom()) : nullptr) { , _migrated(peer->migrateFrom() ? App::history(peer->migrateFrom()) : nullptr) {
Notify::registerPeerObserver(Notify::PeerUpdate::Flag::SharedMediaChanged, this, &SharedMediaWidget::notifyPeerUpdated); auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
App::main()->preloadOverviews(peer); App::main()->preloadOverviews(peer);
if (_migrated) { if (_migrated) {

View file

@ -36,8 +36,16 @@ UserpicButton::UserpicButton(QWidget *parent, PeerData *peer) : Button(parent),
_userpic = prepareUserpicPixmap(); _userpic = prepareUserpicPixmap();
} }
Notify::registerPeerObserver(Notify::PeerUpdate::Flag::PhotoChanged, this, &UserpicButton::notifyPeerUpdated); auto observeEvents = Notify::PeerUpdate::Flag::PhotoChanged;
FileDownload::registerImageLoadedObserver(this, &UserpicButton::notifyImageLoaded); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
subscribe(FileDownload::ImageLoaded(), [this] {
if (_waiting && _peer->userpicLoaded()) {
_waiting = false;
startNewPhotoShowing();
}
});
} }
void UserpicButton::showFinished() { void UserpicButton::showFinished() {
@ -45,7 +53,7 @@ void UserpicButton::showFinished() {
_notShownYet = false; _notShownYet = false;
if (!_waiting) { if (!_waiting) {
_a_appearance.finish(); _a_appearance.finish();
START_ANIMATION(_a_appearance, func(this, &UserpicButton::refreshCallback), 0, 1, st::profilePhotoDuration, anim::linear); _a_appearance.start([this] { update(); }, 0, 1, st::profilePhotoDuration);
} }
} }
} }
@ -68,13 +76,6 @@ void UserpicButton::notifyPeerUpdated(const Notify::PeerUpdate &update) {
this->update(); this->update();
} }
void UserpicButton::notifyImageLoaded() {
if (_waiting && _peer->userpicLoaded()) {
_waiting = false;
startNewPhotoShowing();
}
}
void UserpicButton::processPeerPhoto() { void UserpicButton::processPeerPhoto() {
bool hasPhoto = (_peer->photoId && _peer->photoId != UnknownPeerPhotoId); bool hasPhoto = (_peer->photoId && _peer->photoId != UnknownPeerPhotoId);
setCursor(hasPhoto ? style::cur_pointer : style::cur_default); setCursor(hasPhoto ? style::cur_pointer : style::cur_default);
@ -100,7 +101,7 @@ void UserpicButton::startNewPhotoShowing() {
} }
_a_appearance.finish(); _a_appearance.finish();
START_ANIMATION(_a_appearance, func(this, &UserpicButton::refreshCallback), 0, 1, st::profilePhotoDuration, anim::linear); _a_appearance.start([this] { update(); }, 0, 1, st::profilePhotoDuration);
update(); update();
} }

View file

@ -28,7 +28,7 @@ struct PeerUpdate;
namespace Profile { namespace Profile {
class UserpicButton final : public Button, public Notify::Observer { class UserpicButton final : public Button, private base::Subscriber {
public: public:
UserpicButton(QWidget *parent, PeerData *peer); UserpicButton(QWidget *parent, PeerData *peer);
@ -41,11 +41,6 @@ protected:
private: private:
void notifyPeerUpdated(const Notify::PeerUpdate &update); void notifyPeerUpdated(const Notify::PeerUpdate &update);
void notifyImageLoaded();
void refreshCallback() {
update();
}
void processPeerPhoto(); void processPeerPhoto();
void processNewPeerPhoto(); void processNewPeerPhoto();

View file

@ -163,9 +163,11 @@ void BackgroundRow::updateImage() {
} }
BackgroundWidget::BackgroundWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_background)) { BackgroundWidget::BackgroundWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_background)) {
FileDialog::registerObserver(this, &BackgroundWidget::notifyFileQueryUpdated);
createControls(); createControls();
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
notifyFileQueryUpdated(update);
});
subscribe(Window::chatBackground(), [this](const Window::ChatBackgroundUpdate &update) { subscribe(Window::chatBackground(), [this](const Window::ChatBackgroundUpdate &update) {
using Update = Window::ChatBackgroundUpdate; using Update = Window::ChatBackgroundUpdate;
if (update.type == Update::Type::New) { if (update.type == Update::Type::New) {

View file

@ -32,7 +32,7 @@ class WidgetSlideWrap;
namespace Settings { namespace Settings {
class BlockWidget : public ScrolledWidget, public Notify::Observer, protected base::Subscriber { class BlockWidget : public ScrolledWidget, protected base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -57,8 +57,12 @@ CoverWidget::CoverWidget(QWidget *parent, UserData *self) : BlockWidget(parent,
connect(_editNameInline, SIGNAL(clicked()), this, SLOT(onEditName())); connect(_editNameInline, SIGNAL(clicked()), this, SLOT(onEditName()));
auto observeEvents = Notify::PeerUpdate::Flag::NameChanged; auto observeEvents = Notify::PeerUpdate::Flag::NameChanged;
Notify::registerPeerObserver(observeEvents, this, &CoverWidget::notifyPeerUpdated); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
FileDialog::registerObserver(this, &CoverWidget::notifyFileQueryUpdated); notifyPeerUpdated(update);
}));
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
notifyFileQueryUpdated(update);
});
connect(App::app(), SIGNAL(peerPhotoDone(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId))); connect(App::app(), SIGNAL(peerPhotoDone(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId)));
connect(App::app(), SIGNAL(peerPhotoFail(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId))); connect(App::app(), SIGNAL(peerPhotoFail(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId)));
@ -217,7 +221,7 @@ void CoverWidget::dragEnterEvent(QDragEnterEvent *e) {
void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) { void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) {
if (_dropArea && !_dropArea->hiding()) { if (_dropArea && !_dropArea->hiding()) {
_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); _dropArea->hideAnimated([this](Profile::CoverDropArea *area) { dropAreaHidden(area); });
} }
} }
@ -228,7 +232,7 @@ void CoverWidget::dropEvent(QDropEvent *e) {
if (mimeData->hasImage()) { if (mimeData->hasImage()) {
img = qvariant_cast<QImage>(mimeData->imageData()); img = qvariant_cast<QImage>(mimeData->imageData());
} else { } else {
const auto &urls = mimeData->urls(); auto urls = mimeData->urls();
if (urls.size() == 1) { if (urls.size() == 1) {
auto &url = urls.at(0); auto &url = urls.at(0);
if (url.isLocalFile()) { if (url.isLocalFile()) {
@ -238,7 +242,7 @@ void CoverWidget::dropEvent(QDropEvent *e) {
} }
if (!_dropArea->hiding()) { if (!_dropArea->hiding()) {
_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); _dropArea->hideAnimated([this](Profile::CoverDropArea *area) { dropAreaHidden(area); });
} }
e->acceptProposedAction(); e->acceptProposedAction();

View file

@ -171,7 +171,9 @@ GeneralWidget::GeneralWidget(QWidget *parent, UserData *self) : BlockWidget(pare
, _changeLanguage(this, lang(lng_settings_change_lang), st::defaultBoxLinkButton) { , _changeLanguage(this, lang(lng_settings_change_lang), st::defaultBoxLinkButton) {
connect(_changeLanguage, SIGNAL(clicked()), this, SLOT(onChangeLanguage())); connect(_changeLanguage, SIGNAL(clicked()), this, SLOT(onChangeLanguage()));
subscribe(Global::RefChooseCustomLang(), [this]() { chooseCustomLang(); }); subscribe(Global::RefChooseCustomLang(), [this]() { chooseCustomLang(); });
FileDialog::registerObserver(this, &GeneralWidget::notifyFileQueryUpdated); subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
notifyFileQueryUpdated(update);
});
refreshControls(); refreshControls();
} }

View file

@ -34,7 +34,9 @@ using UpdateFlag = Notify::PeerUpdate::Flag;
InfoWidget::InfoWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_info)) { InfoWidget::InfoWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_info)) {
auto observeEvents = UpdateFlag::UsernameChanged | UpdateFlag::UserPhoneChanged; auto observeEvents = UpdateFlag::UsernameChanged | UpdateFlag::UserPhoneChanged;
Notify::registerPeerObserver(observeEvents, this, &InfoWidget::notifyPeerUpdated); subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
createControls(); createControls();
} }
@ -81,7 +83,10 @@ void InfoWidget::refreshUsername() {
usernameText.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, usernameText.text.size(), qsl("https://telegram.me/") + self()->username)); usernameText.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, usernameText.text.size(), qsl("https://telegram.me/") + self()->username));
setLabeledText(_username, lang(lng_profile_username), usernameText, TextWithEntities(), copyText); setLabeledText(_username, lang(lng_profile_username), usernameText, TextWithEntities(), copyText);
if (auto text = _username->entity()->textLabel()) { if (auto text = _username->entity()->textLabel()) {
text->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook)); text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new UsernameBox());
return false;
});
} }
} }
@ -96,19 +101,20 @@ void InfoWidget::refreshLink() {
} }
setLabeledText(_link, lang(lng_profile_link), linkText, linkTextShort, QString()); setLabeledText(_link, lang(lng_profile_link), linkText, linkTextShort, QString());
if (auto text = _link->entity()->textLabel()) { if (auto text = _link->entity()->textLabel()) {
text->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook)); text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new UsernameBox());
return false;
});
} }
if (auto shortText = _link->entity()->shortTextLabel()) { if (auto shortText = _link->entity()->shortTextLabel()) {
shortText->setExpandLinksMode(ExpandLinksUrlOnly); shortText->setExpandLinksMode(ExpandLinksUrlOnly);
shortText->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook)); shortText->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new UsernameBox());
return false;
});
} }
} }
bool InfoWidget::usernameClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new UsernameBox());
return false;
}
void InfoWidget::setLabeledText(ChildWidget<LabeledWrap> &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText) { void InfoWidget::setLabeledText(ChildWidget<LabeledWrap> &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText) {
if (textWithEntities.text.isEmpty()) { if (textWithEntities.text.isEmpty()) {
row->slideUp(); row->slideUp();

View file

@ -38,8 +38,6 @@ private:
// Observed notifications. // Observed notifications.
void notifyPeerUpdated(const Notify::PeerUpdate &update); void notifyPeerUpdated(const Notify::PeerUpdate &update);
bool usernameClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
void createControls(); void createControls();
void refreshControls(); void refreshControls();
void refreshMobileNumber(); void refreshMobileNumber();

View file

@ -59,6 +59,7 @@ void InnerWidget::selfUpdated() {
void InnerWidget::refreshBlocks() { void InnerWidget::refreshBlocks() {
_cover.destroyDelayed(); _cover.destroyDelayed();
for_const (auto block, _blocks) { for_const (auto block, _blocks) {
block->hide();
block->deleteLater(); block->deleteLater();
} }
_blocks.clear(); _blocks.clear();
@ -81,6 +82,9 @@ void InnerWidget::refreshBlocks() {
if (_cover) { if (_cover) {
_cover->show(); _cover->show();
if (_showFinished) {
_cover->showFinished();
}
} }
for_const (auto block, _blocks) { for_const (auto block, _blocks) {
block->show(); block->show();
@ -89,6 +93,7 @@ void InnerWidget::refreshBlocks() {
} }
void InnerWidget::showFinished() { void InnerWidget::showFinished() {
_showFinished = true;
if (_cover) { if (_cover) {
_cover->showFinished(); _cover->showFinished();
} }

View file

@ -65,6 +65,7 @@ private:
UserData *_self = nullptr; UserData *_self = nullptr;
int _contentLeft = 0; int _contentLeft = 0;
bool _showFinished = false;
int _visibleTop = 0; int _visibleTop = 0;
int _visibleBottom = 0; int _visibleBottom = 0;

View file

@ -26,6 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_settings.h" #include "styles/style_settings.h"
#include "ui/scrollarea.h" #include "ui/scrollarea.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "mainwidget.h"
#include "localstorage.h" #include "localstorage.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "application.h" #include "application.h"
@ -80,6 +81,11 @@ void fillCodes() {
}); });
Ui::showLayer(box.release()); Ui::showLayer(box.release());
}); });
Codes.insert(qsl("getdifference"), []() {
if (auto main = App::main()) {
main->getDifference();
}
});
} }
void codesFeedString(const QString &text) { void codesFeedString(const QString &text) {

View file

@ -801,7 +801,6 @@ StickerPanInner::StickerPanInner() : ScrolledWidget()
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(onImageLoaded()));
connect(&_settings, SIGNAL(clicked()), this, SLOT(onSettings())); connect(&_settings, SIGNAL(clicked()), this, SLOT(onSettings()));
_previewTimer.setSingleShot(true); _previewTimer.setSingleShot(true);
@ -809,6 +808,11 @@ StickerPanInner::StickerPanInner() : ScrolledWidget()
_updateInlineItems.setSingleShot(true); _updateInlineItems.setSingleShot(true);
connect(&_updateInlineItems, SIGNAL(timeout()), this, SLOT(onUpdateInlineItems())); connect(&_updateInlineItems, SIGNAL(timeout()), this, SLOT(onUpdateInlineItems()));
subscribe(FileDownload::ImageLoaded(), [this] {
update();
readVisibleSets();
});
} }
void StickerPanInner::setMaxHeight(int32 h) { void StickerPanInner::setMaxHeight(int32 h) {
@ -855,11 +859,6 @@ void StickerPanInner::readVisibleSets() {
} }
} }
void StickerPanInner::onImageLoaded() {
update();
readVisibleSets();
}
int StickerPanInner::featuredRowHeight() const { int StickerPanInner::featuredRowHeight() const {
return st::featuredStickersHeader + st::stickerPanSize.height() + st::featuredStickersSkip; return st::featuredStickersHeader + st::stickerPanSize.height() + st::featuredStickersSkip;
} }

View file

@ -207,7 +207,7 @@ struct StickerIcon {
int pixh = 0; int pixh = 0;
}; };
class StickerPanInner : public ScrolledWidget { class StickerPanInner : public ScrolledWidget, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:
@ -274,7 +274,6 @@ private slots:
void onPreview(); void onPreview();
void onUpdateInlineItems(); void onUpdateInlineItems();
void onSwitchPm(); void onSwitchPm();
void onImageLoaded();
signals: signals:
void selected(DocumentData *sticker); void selected(DocumentData *sticker);

View file

@ -27,12 +27,11 @@ static const ChannelId NoChannel = 0;
typedef int32 MsgId; typedef int32 MsgId;
struct FullMsgId { struct FullMsgId {
FullMsgId() : channel(NoChannel), msg(0) { FullMsgId() = default;
}
FullMsgId(ChannelId channel, MsgId msg) : channel(channel), msg(msg) { FullMsgId(ChannelId channel, MsgId msg) : channel(channel), msg(msg) {
} }
ChannelId channel; ChannelId channel = NoChannel;
MsgId msg; MsgId msg = 0;
}; };
typedef uint64 PeerId; typedef uint64 PeerId;

View file

@ -120,7 +120,7 @@ AnimationManager::AnimationManager() : _timer(this), _iterating(false) {
void AnimationManager::start(Animation *obj) { void AnimationManager::start(Animation *obj) {
if (_iterating) { if (_iterating) {
_starting.insert(obj, NullType()); _starting.insert(obj);
if (!_stopping.isEmpty()) { if (!_stopping.isEmpty()) {
_stopping.remove(obj); _stopping.remove(obj);
} }
@ -128,21 +128,21 @@ void AnimationManager::start(Animation *obj) {
if (_objects.isEmpty()) { if (_objects.isEmpty()) {
_timer.start(AnimationTimerDelta); _timer.start(AnimationTimerDelta);
} }
_objects.insert(obj, NullType()); _objects.insert(obj);
} }
} }
void AnimationManager::stop(Animation *obj) { void AnimationManager::stop(Animation *obj) {
if (_iterating) { if (_iterating) {
_stopping.insert(obj, NullType()); _stopping.insert(obj);
if (!_starting.isEmpty()) { if (!_starting.isEmpty()) {
_starting.remove(obj); _starting.remove(obj);
} }
} else { } else {
AnimatingObjects::iterator i = _objects.find(obj); auto i = _objects.find(obj);
if (i != _objects.cend()) { if (i != _objects.cend()) {
_objects.erase(i); _objects.erase(i);
if (_objects.isEmpty()) { if (_objects.empty()) {
_timer.stop(); _timer.stop();
} }
} }
@ -152,26 +152,26 @@ void AnimationManager::stop(Animation *obj) {
void AnimationManager::timeout() { void AnimationManager::timeout() {
_iterating = true; _iterating = true;
uint64 ms = getms(); uint64 ms = getms();
for (AnimatingObjects::const_iterator i = _objects.begin(), e = _objects.end(); i != e; ++i) { for_const (auto object, _objects) {
if (!_stopping.contains(i.key())) { if (!_stopping.contains(object)) {
i.key()->step(ms, true); object->step(ms, true);
} }
} }
_iterating = false; _iterating = false;
if (!_starting.isEmpty()) { if (!_starting.isEmpty()) {
for (AnimatingObjects::iterator i = _starting.begin(), e = _starting.end(); i != e; ++i) { for_const (auto object, _starting) {
_objects.insert(i.key(), NullType()); _objects.insert(object);
} }
_starting.clear(); _starting.clear();
} }
if (!_stopping.isEmpty()) { if (!_stopping.isEmpty()) {
for (AnimatingObjects::iterator i = _stopping.begin(), e = _stopping.end(); i != e; ++i) { for_const (auto object, _stopping) {
_objects.remove(i.key()); _objects.remove(object);
} }
_stopping.clear(); _stopping.clear();
} }
if (!_objects.size()) { if (_objects.empty()) {
_timer.stop(); _timer.stop();
} }
} }

View file

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "core/basic_types.h" #include "core/basic_types.h"
#include "core/lambda_wrap.h"
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtGui/QColor> #include <QtGui/QColor>
@ -57,6 +58,7 @@ namespace anim {
class fvalue { // float animated value class fvalue { // float animated value
public: public:
using ValueType = float64;
fvalue() { fvalue() {
} }
@ -88,15 +90,14 @@ namespace anim {
_delta = 0; _delta = 0;
} }
typedef float64 Type;
private: private:
float64 _cur, _from, _delta; float64 _cur, _from, _delta;
}; };
class ivalue { // int animated value class ivalue { // int animated value
public: public:
using ValueType = int32;
ivalue() { ivalue() {
} }
@ -128,16 +129,15 @@ namespace anim {
_delta = 0; _delta = 0;
} }
typedef int32 Type;
private: private:
int32 _cur; int32 _cur;
float64 _from, _delta; float64 _from, _delta;
}; };
class cvalue { // QColor animated value class cvalue { // QColor animated value
public: public:
using ValueType = QColor;
cvalue() { cvalue() {
} }
@ -199,12 +199,10 @@ namespace anim {
_delta_r = _delta_g = _delta_b = _delta_a = 0; _delta_r = _delta_g = _delta_b = _delta_a = 0;
} }
typedef QColor Type;
private: private:
QColor _cur; QColor _cur;
float64 _from_r, _from_g, _from_b, _from_a, _delta_r, _delta_g, _delta_b, _delta_a; float64 _from_r, _from_g, _from_b, _from_a, _delta_r, _delta_g, _delta_b, _delta_a;
}; };
void startManager(); void startManager();
@ -380,105 +378,81 @@ AnimationCallbacks animation(Param param, Type *obj, typename AnimationCallbacks
template <typename AnimType> template <typename AnimType>
class SimpleAnimation { class SimpleAnimation {
public: public:
using Callback = Function<void>; using ValueType = typename AnimType::ValueType;
using Callback = base::lambda_unique<void()>;
SimpleAnimation() { bool animating() const {
if (_data) {
if (_data->a_animation.animating()) {
return true;
}
_data.reset();
}
return false;
} }
bool animating(uint64 ms) { bool animating(uint64 ms) {
if (_data && _data->_a.animating()) { if (animating()) {
_data->_a.step(ms); _data->a_animation.step(ms);
return _data && _data->_a.animating(); return animating();
} }
return false; return false;
} }
bool isNull() const { ValueType current() const {
return !_data; t_assert(_data != nullptr);
return _data->value.current();
} }
ValueType current(const ValueType &def) const {
typename AnimType::Type current() { return _data ? current() : def;
return _data ? _data->a.current() : typename AnimType::Type();
} }
ValueType current(uint64 ms, const ValueType &def) {
typename AnimType::Type current(const typename AnimType::Type &def) {
return _data ? _data->a.current() : def;
}
typename AnimType::Type current(uint64 ms, const typename AnimType::Type &def) {
return animating(ms) ? current() : def; return animating(ms) ? current() : def;
} }
void setup(const typename AnimType::Type &from, Callback &&update) { template <typename Lambda>
void start(Lambda &&updateCallback, const ValueType &from, const ValueType &to, float64 duration, anim::transition transition = anim::linear) {
if (!_data) { if (!_data) {
_data = new Data(from, std_::move(update), animation(this, &SimpleAnimation<AnimType>::step)); _data = std_::make_unique<Data>(from, std_::move(updateCallback));
} else {
_data->a = AnimType(from, from);
}
}
void start(const typename AnimType::Type &to, float64 duration, anim::transition transition = anim::linear) {
if (_data) {
_data->a.start(to);
_data->_a.start();
_data->duration = duration;
_data->transition = transition;
} }
_data->value.start(to);
_data->duration = duration;
_data->transition = transition;
_data->a_animation.start();
} }
void finish() { void finish() {
if (isNull()) { if (_data) {
return; _data->value.finish();
_data->a_animation.stop();
_data.reset();
} }
_data->a.finish();
_data->_a.stop();
delete _data;
_data = nullptr;
}
~SimpleAnimation() {
deleteAndMark(_data);
} }
private: private:
struct Data { struct Data {
Data(const typename AnimType::Type &from, Callback &&update, AnimationCallbacks &&acb) Data(const ValueType &from, Callback &&updateCallback)
: a(from, from) : value(from, from)
, _a(std_::move(acb)) , a_animation(animation(this, &Data::step))
, update(std_::move(update)) , updateCallback(std_::move(updateCallback)) {
, duration(0)
, transition(anim::linear) {
} }
AnimType a; void step(float64 ms, bool timer) {
Animation _a; auto dt = (ms >= duration) ? 1. : (ms / duration);
Callback update; if (dt >= 1) {
float64 duration; value.finish();
anim::transition transition; a_animation.stop();
} else {
value.update(dt, transition);
}
updateCallback();
}
AnimType value;
Animation a_animation;
Callback updateCallback;
float64 duration = 0.;
anim::transition transition = anim::linear;
}; };
Data *_data = nullptr; mutable std_::unique_ptr<Data> _data;
void step(float64 ms, bool timer) {
float64 dt = (ms >= _data->duration) ? 1 : (ms / _data->duration);
if (dt >= 1) {
_data->a.finish();
_data->_a.stop();
} else {
_data->a.update(dt, _data->transition);
}
Callback callbackCache, *toCall = &_data->update;
if (!_data->_a.animating()) {
callbackCache = std_::move(_data->update);
toCall = &callbackCache;
delete _data;
_data = nullptr;
}
if (timer) {
toCall->call();
}
}
}; };
@ -486,18 +460,8 @@ using FloatAnimation = SimpleAnimation<anim::fvalue>;
using IntAnimation = SimpleAnimation<anim::ivalue>; using IntAnimation = SimpleAnimation<anim::ivalue>;
using ColorAnimation = SimpleAnimation<anim::cvalue>; using ColorAnimation = SimpleAnimation<anim::cvalue>;
// Macro allows us to lazily create updateCallback.
#define ENSURE_ANIMATION(animation, updateCallback, from) \
if ((animation).isNull()) { \
(animation).setup((from), (updateCallback)); \
}
#define START_ANIMATION(animation, updateCallback, from, to, duration, transition) \
ENSURE_ANIMATION(animation, updateCallback, from); \
(animation).start((to), (duration), (transition))
class AnimationManager : public QObject { class AnimationManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
AnimationManager(); AnimationManager();
@ -511,7 +475,7 @@ public slots:
void clipCallback(Media::Clip::Reader *reader, qint32 threadIndex, qint32 notification); void clipCallback(Media::Clip::Reader *reader, qint32 threadIndex, qint32 notification);
private: private:
typedef QMap<Animation*, NullType> AnimatingObjects; using AnimatingObjects = OrderedSet<Animation*>;
AnimatingObjects _objects, _starting, _stopping; AnimatingObjects _objects, _starting, _stopping;
QTimer _timer; QTimer _timer;
bool _iterating; bool _iterating;

View file

@ -118,7 +118,7 @@ void HistoryDownButton::hideAnimated() {
void HistoryDownButton::toggleAnimated() { void HistoryDownButton::toggleAnimated() {
_shown = !_shown; _shown = !_shown;
float64 from = _shown ? 0. : 1., to = _shown ? 1. : 0.; float64 from = _shown ? 0. : 1., to = _shown ? 1. : 0.;
START_ANIMATION(_a_show, func(this, &HistoryDownButton::repaintCallback), from, to, st::btnAttachEmoji.duration, anim::linear); _a_show.start([this] { update(); }, from, to, st::btnAttachEmoji.duration);
} }
void HistoryDownButton::finishAnimation() { void HistoryDownButton::finishAnimation() {

View file

@ -47,9 +47,6 @@ protected:
private: private:
void toggleAnimated(); void toggleAnimated();
void repaintCallback() {
update();
}
void step_arrowOver(float64 ms, bool timer); void step_arrowOver(float64 ms, bool timer);
QPixmap _cache; QPixmap _cache;

View file

@ -49,7 +49,7 @@ void IconButton::onStateChanged(int oldState, ButtonStateChangeSource source) {
if (over != (oldState & StateOver)) { if (over != (oldState & StateOver)) {
auto from = over ? 0. : 1.; auto from = over ? 0. : 1.;
auto to = over ? 1. : 0.; auto to = over ? 1. : 0.;
START_ANIMATION(_a_over, func(this, &IconButton::updateCallback), from, to, _st.duration, anim::linear); _a_over.start([this] { update(); }, from, to, _st.duration);
} }
} }

View file

@ -37,10 +37,6 @@ protected:
void onStateChanged(int oldState, ButtonStateChangeSource source) override; void onStateChanged(int oldState, ButtonStateChangeSource source) override;
private: private:
void updateCallback() {
update();
}
const style::IconButton &_st; const style::IconButton &_st;
const style::icon *_iconOverride = nullptr; const style::icon *_iconOverride = nullptr;

View file

@ -65,7 +65,9 @@ void FadeAnimation::stopAnimation() {
_cache = QPixmap(); _cache = QPixmap();
updateCallback(); updateCallback();
_widget->showChildren(); _widget->showChildren();
_finishedCallback.call(); if (_finishedCallback) {
_finishedCallback();
}
} }
if (_visible == _widget->isHidden()) { if (_visible == _widget->isHidden()) {
_widget->setVisible(_visible); _widget->setVisible(_visible);
@ -91,7 +93,9 @@ void FadeAnimation::startAnimation(int duration) {
_cache = myGrab(_widget); _cache = myGrab(_widget);
_widget->hideChildren(); _widget->hideChildren();
} }
START_ANIMATION(_animation, func(this, &FadeAnimation::updateCallback), _visible ? 0. : 1., _visible ? 1. : 0., duration, anim::linear); auto from = _visible ? 0. : 1.;
auto to = _visible ? 1. : 0.;
_animation.start([this]() { updateCallback(); }, from, to, duration);
updateCallback(); updateCallback();
if (_widget->isHidden()) { if (_widget->isHidden()) {
_widget->show(); _widget->show();
@ -101,7 +105,9 @@ void FadeAnimation::startAnimation(int duration) {
void FadeAnimation::updateCallback() { void FadeAnimation::updateCallback() {
if (_animation.animating(getms())) { if (_animation.animating(getms())) {
_widget->update(); _widget->update();
_updatedCallback.call(_animation.current()); if (_updatedCallback) {
_updatedCallback(_animation.current(_visible ? 1. : 0.));
}
} else { } else {
stopAnimation(); stopAnimation();
} }

View file

@ -31,10 +31,10 @@ public:
bool paint(Painter &p); bool paint(Painter &p);
void refreshCache(); void refreshCache();
using FinishedCallback = Function<void>; using FinishedCallback = base::lambda_unique<void()>;
void setFinishedCallback(FinishedCallback &&callback); void setFinishedCallback(FinishedCallback &&callback);
using UpdatedCallback = Function<void, float64>; using UpdatedCallback = base::lambda_unique<void(float64)>;
void setUpdatedCallback(UpdatedCallback &&callback); void setUpdatedCallback(UpdatedCallback &&callback);
void show(); void show();

View file

@ -255,7 +255,7 @@ QString filedialogAllFilesFilter() {
namespace FileDialog { namespace FileDialog {
namespace { namespace {
using internal::QueryUpdateHandler; base::Observable<QueryUpdate> QueryDoneObservable;
struct Query { struct Query {
enum class Type { enum class Type {
@ -285,16 +285,10 @@ void StartCallback() {
Queries.makeIfNull(); Queries.makeIfNull();
} }
void FinishCallback() {
Queries.clear();
}
Notify::SimpleObservedEventRegistrator<QueryUpdateHandler> creator(StartCallback, FinishCallback);
} // namespace } // namespace
QueryId queryReadFile(const QString &caption, const QString &filter) { QueryId queryReadFile(const QString &caption, const QString &filter) {
t_assert(creator.started()); Queries.makeIfNull();
Queries->push_back(Query(Query::Type::ReadFile, caption, filter)); Queries->push_back(Query(Query::Type::ReadFile, caption, filter));
Global::RefHandleFileDialogQueue().call(); Global::RefHandleFileDialogQueue().call();
@ -302,7 +296,7 @@ QueryId queryReadFile(const QString &caption, const QString &filter) {
} }
QueryId queryReadFiles(const QString &caption, const QString &filter) { QueryId queryReadFiles(const QString &caption, const QString &filter) {
t_assert(creator.started()); Queries.makeIfNull();
Queries->push_back(Query(Query::Type::ReadFiles, caption, filter)); Queries->push_back(Query(Query::Type::ReadFiles, caption, filter));
Global::RefHandleFileDialogQueue().call(); Global::RefHandleFileDialogQueue().call();
@ -310,7 +304,7 @@ QueryId queryReadFiles(const QString &caption, const QString &filter) {
} }
QueryId queryWriteFile(const QString &caption, const QString &filter, const QString &filePath) { QueryId queryWriteFile(const QString &caption, const QString &filter, const QString &filePath) {
t_assert(creator.started()); Queries.makeIfNull();
Queries->push_back(Query(Query::Type::WriteFile, caption, filter, filePath)); Queries->push_back(Query(Query::Type::WriteFile, caption, filter, filePath));
Global::RefHandleFileDialogQueue().call(); Global::RefHandleFileDialogQueue().call();
@ -318,7 +312,7 @@ QueryId queryWriteFile(const QString &caption, const QString &filter, const QStr
} }
QueryId queryReadFolder(const QString &caption) { QueryId queryReadFolder(const QString &caption) {
t_assert(creator.started()); Queries.makeIfNull();
Queries->push_back(Query(Query::Type::ReadFolder, caption)); Queries->push_back(Query(Query::Type::ReadFolder, caption));
Global::RefHandleFileDialogQueue().call(); Global::RefHandleFileDialogQueue().call();
@ -326,7 +320,7 @@ QueryId queryReadFolder(const QString &caption) {
} }
bool processQuery() { bool processQuery() {
if (!creator.started() || !Global::started() || Queries->isEmpty()) return false; if (!Queries || !Global::started() || Queries->isEmpty()) return false;
auto query = Queries->front(); auto query = Queries->front();
Queries->pop_front(); Queries->pop_front();
@ -374,17 +368,14 @@ bool processQuery() {
} }
// No one knows what happened during filedialogGet*() call in the event loop. // No one knows what happened during filedialogGet*() call in the event loop.
if (!creator.started() || !Global::started()) return false; if (!Queries || !Global::started()) return false;
creator.notify(update); QueryDone().notify(std_::move(update));
return true; return true;
} }
namespace internal { base::Observable<QueryUpdate> &QueryDone() {
return QueryDoneObservable;
Notify::ConnectionId plainRegisterObserver(QueryUpdateHandler &&handler) {
return creator.registerObserver(std_::forward<QueryUpdateHandler>(handler));
} }
} // namespace internal
} // namespace FileDialog } // namespace FileDialog

View file

@ -63,17 +63,6 @@ QueryId queryReadFolder(const QString &caption);
// NB! This function enters an event loop. // NB! This function enters an event loop.
bool processQuery(); bool processQuery();
namespace internal { base::Observable<QueryUpdate> &QueryDone();
using QueryUpdateHandler = Function<void, const QueryUpdate&>;
Notify::ConnectionId plainRegisterObserver(QueryUpdateHandler &&handler);
} // namespace internal
template <typename ObserverType>
void registerObserver(ObserverType *observer, void (ObserverType::*handler)(const QueryUpdate &)) {
auto connection = internal::plainRegisterObserver(func(observer, handler));
Notify::observerRegistered(observer, connection);
}
} // namespace FileDialog } // namespace FileDialog

Some files were not shown because too many files have changed in this diff Show more