Beta 9034004 version:

Some lang grammar fixes, all "audio" changed to "voice message"
PeerData can have three loaded states (not loaded, minimal, full)
Interface/Interfaces renamed to Component/Composer
HistoryReply moved to a Component named HistoryMessageReply
This commit is contained in:
John Preston 2016-03-25 14:29:45 +03:00
parent a299c1f9e8
commit 599ede9a0b
22 changed files with 1036 additions and 1038 deletions

View File

@ -663,9 +663,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_stickers_count" = "{count:Loading...|# sticker|# stickers}"; "lng_stickers_count" = "{count:Loading...|# sticker|# stickers}";
"lng_in_dlg_photo" = "Photo"; "lng_in_dlg_photo" = "Photo";
"lng_in_dlg_video" = "Video"; "lng_in_dlg_video" = "Video file";
"lng_in_dlg_audio_file" = "Audio file";
"lng_in_dlg_contact" = "Contact"; "lng_in_dlg_contact" = "Contact";
"lng_in_dlg_audio" = "Audio"; "lng_in_dlg_audio" = "Voice message";
"lng_in_dlg_file" = "File"; "lng_in_dlg_file" = "File";
"lng_in_dlg_sticker" = "Sticker"; "lng_in_dlg_sticker" = "Sticker";
"lng_in_dlg_sticker_emoji" = "{emoji} (sticker)"; "lng_in_dlg_sticker_emoji" = "{emoji} (sticker)";
@ -720,28 +721,29 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_user_typing" = "{user} is typing"; "lng_user_typing" = "{user} is typing";
"lng_users_typing" = "{user} and {second_user} are typing"; "lng_users_typing" = "{user} and {second_user} are typing";
"lng_many_typing" = "{count:_not_used_|# is|# are} typing"; "lng_many_typing" = "{count:_not_used_|# is|# are} typing";
"lng_send_action_record_video" = "recording video"; "lng_send_action_record_video" = "recording a video";
"lng_user_action_record_video" = "{user} is recording a video"; "lng_user_action_record_video" = "{user} is recording a video";
"lng_send_action_upload_video" = "sending video"; "lng_send_action_upload_video" = "sending a video";
"lng_user_action_upload_video" = "{user} is sending a video"; "lng_user_action_upload_video" = "{user} is sending a video";
"lng_send_action_record_audio" = "recording audio"; "lng_send_action_record_audio" = "recording a voice message";
"lng_user_action_record_audio" = "{user} is recording an audio"; "lng_user_action_record_audio" = "{user} is recording a voice message";
"lng_send_action_upload_audio" = "sending audio"; "lng_send_action_upload_audio" = "sending a voice message";
"lng_user_action_upload_audio" = "{user} is sending an audio"; "lng_user_action_upload_audio" = "{user} is sending a voice message";
"lng_send_action_upload_photo" = "sending photo"; "lng_send_action_upload_photo" = "sending a photo";
"lng_user_action_upload_photo" = "{user} is sending a photo"; "lng_user_action_upload_photo" = "{user} is sending a photo";
"lng_send_action_upload_file" = "sending file"; "lng_send_action_upload_file" = "sending a file";
"lng_user_action_upload_file" = "{user} is sending a file"; "lng_user_action_upload_file" = "{user} is sending a file";
"lng_send_action_geo_location" = "picking location"; "lng_send_action_geo_location" = "picking a location";
"lng_user_action_geo_location" = "{user} is picking a location"; "lng_user_action_geo_location" = "{user} is picking a location";
"lng_send_action_choose_contact" = "choosing contact"; "lng_send_action_choose_contact" = "choosing a contact";
"lng_user_action_choose_contact" = "{user} is choosing a contact"; "lng_user_action_choose_contact" = "{user} is choosing a contact";
"lng_unread_bar" = "{count:_not_used_|# unread message|# unread messages}"; "lng_unread_bar" = "{count:_not_used_|# unread message|# unread messages}";
"lng_maps_point" = "Location"; "lng_maps_point" = "Location";
"lng_save_photo" = "Save image"; "lng_save_photo" = "Save image";
"lng_save_video" = "Save video"; "lng_save_video" = "Save video file";
"lng_save_audio" = "Save audio"; "lng_save_audio_file" = "Save audio file";
"lng_save_audio" = "Save voice message";
"lng_save_file" = "Save file"; "lng_save_file" = "Save file";
"lng_save_downloaded" = "{ready} / {total} {mb}"; "lng_save_downloaded" = "{ready} / {total} {mb}";
"lng_duration_and_size" = "{duration}, {size}"; "lng_duration_and_size" = "{duration}, {size}";
@ -766,8 +768,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_context_cancel_download" = "Cancel Download"; "lng_context_cancel_download" = "Cancel Download";
"lng_context_show_in_folder" = "Show in Folder"; "lng_context_show_in_folder" = "Show in Folder";
"lng_context_show_in_finder" = "Show in Finder"; "lng_context_show_in_finder" = "Show in Finder";
"lng_context_save_video" = "Save Video As..."; "lng_context_save_video" = "Save Video File As...";
"lng_context_save_audio" = "Save Audio As..."; "lng_context_save_audio_file" = "Save Audio File As...";
"lng_context_save_audio" = "Save Voice Message As...";
"lng_context_pack_info" = "Pack Info"; "lng_context_pack_info" = "Pack Info";
"lng_context_pack_add" = "Add Stickers"; "lng_context_pack_add" = "Add Stickers";
"lng_context_save_file" = "Save File As..."; "lng_context_save_file" = "Save File As...";

View File

@ -478,7 +478,13 @@ namespace App {
if (!data) continue; if (!data) continue;
data->loaded = true; if (minimal) {
if (data->loadedStatus == PeerData::NotLoaded) {
data->loadedStatus = PeerData::MinimalLoaded;
}
} else if (data->loadedStatus != PeerData::FullLoaded) {
data->loadedStatus = PeerData::FullLoaded;
}
if (status && !minimal) switch (status->type()) { if (status && !minimal) switch (status->type()) {
case mtpc_userStatusEmpty: data->onlineTill = 0; break; case mtpc_userStatusEmpty: data->onlineTill = 0; break;
case mtpc_userStatusRecently: case mtpc_userStatusRecently:
@ -655,7 +661,13 @@ namespace App {
} }
if (!data) continue; if (!data) continue;
data->loaded = true; if (minimal) {
if (data->loadedStatus == PeerData::NotLoaded) {
data->loadedStatus = PeerData::MinimalLoaded;
}
} else if (data->loadedStatus != PeerData::FullLoaded) {
data->loadedStatus = PeerData::FullLoaded;
}
if (App::main()) { if (App::main()) {
if (emitPeerUpdated) { if (emitPeerUpdated) {
App::main()->peerUpdated(data); App::main()->peerUpdated(data);
@ -1000,7 +1012,7 @@ namespace App {
} }
void checkSavedGif(HistoryItem *item) { void checkSavedGif(HistoryItem *item) {
if (!item->Is<HistoryMessageForwarded>() && (item->out() || item->history()->peer == App::self())) { if (!item->Has<HistoryMessageForwarded>() && (item->out() || item->history()->peer == App::self())) {
if (HistoryMedia *media = item->getMedia()) { if (HistoryMedia *media = item->getMedia()) {
if (DocumentData *doc = media->getDocument()) { if (DocumentData *doc = media->getDocument()) {
if (doc->isGifv()) { if (doc->isGifv()) {
@ -1394,41 +1406,16 @@ namespace App {
return 0; return 0;
} }
PeerData *peerLoaded(const PeerId &peer) {
PeersData::const_iterator i = peersData.constFind(peer);
return (i != peersData.cend()) ? i.value() : 0;
}
UserData *userLoaded(const PeerId &id) {
PeerData *peer = peerLoaded(id);
return (peer && peer->loaded) ? peer->asUser() : 0;
}
ChatData *chatLoaded(const PeerId &id) {
PeerData *peer = peerLoaded(id);
return (peer && peer->loaded) ? peer->asChat() : 0;
}
ChannelData *channelLoaded(const PeerId &id) {
PeerData *peer = peerLoaded(id);
return (peer && peer->loaded) ? peer->asChannel() : 0;
}
UserData *userLoaded(int32 user_id) {
return userLoaded(peerFromUser(user_id));
}
ChatData *chatLoaded(int32 chat_id) {
return chatLoaded(peerFromChat(chat_id));
}
ChannelData *channelLoaded(int32 channel_id) {
return channelLoaded(peerFromChannel(channel_id));
}
UserData *curUser() { UserData *curUser() {
return user(MTP::authedId()); return user(MTP::authedId());
} }
PeerData *peer(const PeerId &id) { PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) {
PeersData::const_iterator i = peersData.constFind(id); if (!id) return nullptr;
auto i = peersData.constFind(id);
if (i == peersData.cend()) { if (i == peersData.cend()) {
PeerData *newData = 0; PeerData *newData = nullptr;
if (peerIsUser(id)) { if (peerIsUser(id)) {
newData = new UserData(id); newData = new UserData(id);
} else if (peerIsChat(id)) { } else if (peerIsChat(id)) {
@ -1436,33 +1423,26 @@ namespace App {
} else if (peerIsChannel(id)) { } else if (peerIsChannel(id)) {
newData = new ChannelData(id); newData = new ChannelData(id);
} }
if (!newData) return 0; t_assert(newData != nullptr);
newData->input = MTPinputPeer(MTP_inputPeerEmpty()); newData->input = MTPinputPeer(MTP_inputPeerEmpty());
i = peersData.insert(id, newData); i = peersData.insert(id, newData);
} }
switch (restriction) {
case PeerData::MinimalLoaded: {
if (i.value()->loadedStatus == PeerData::NotLoaded) {
return nullptr;
}
} break;
case PeerData::FullLoaded: {
if (i.value()->loadedStatus != PeerData::FullLoaded) {
return nullptr;
}
} break;
}
return i.value(); return i.value();
} }
UserData *user(const PeerId &id) {
return peer(id)->asUser();
}
ChatData *chat(const PeerId &id) {
return peer(id)->asChat();
}
ChannelData *channel(const PeerId &id) {
return peer(id)->asChannel();
}
UserData *user(int32 user_id) {
return user(peerFromUser(user_id));
}
ChatData *chat(int32 chat_id) {
return chat(peerFromChat(chat_id));
}
ChannelData *channel(int32 channel_id) {
return channel(peerFromChannel(channel_id));
}
UserData *self() { UserData *self() {
return ::self; return ::self;
} }

View File

@ -110,21 +110,47 @@ namespace App {
WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = 0); WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = 0);
WebPageData *feedWebPage(const MTPWebPage &webpage); WebPageData *feedWebPage(const MTPWebPage &webpage);
PeerData *peerLoaded(const PeerId &id); PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded);
UserData *userLoaded(const PeerId &id); inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
ChatData *chatLoaded(const PeerId &id); return asUser(peer(id, restriction));
ChannelData *channelLoaded(const PeerId &id); }
UserData *userLoaded(int32 user); inline ChatData *chat(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
ChatData *chatLoaded(int32 chat); return asChat(peer(id, restriction));
ChannelData *channelLoaded(int32 channel); }
inline ChannelData *channel(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChannel(peer(id, restriction));
}
inline UserData *user(UserId userId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asUser(peer(peerFromUser(userId), restriction));
}
inline ChatData *chat(ChatId chatId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChat(peer(peerFromChat(chatId), restriction));
}
inline ChannelData *channel(ChannelId channelId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChannel(peer(peerFromChannel(channelId), restriction));
}
inline PeerData *peerLoaded(const PeerId &id) {
return peer(id, PeerData::FullLoaded);
}
inline UserData *userLoaded(const PeerId &id) {
return user(id, PeerData::FullLoaded);
}
inline ChatData *chatLoaded(const PeerId &id) {
return chat(id, PeerData::FullLoaded);
}
inline ChannelData *channelLoaded(const PeerId &id) {
return channel(id, PeerData::FullLoaded);
}
inline UserData *userLoaded(UserId userId) {
return user(userId, PeerData::FullLoaded);
}
inline ChatData *chatLoaded(ChatId chatId) {
return chat(chatId, PeerData::FullLoaded);
}
inline ChannelData *channelLoaded(ChannelId channelId) {
return channel(channelId, PeerData::FullLoaded);
}
PeerData *peer(const PeerId &id);
UserData *user(const PeerId &id);
ChatData *chat(const PeerId &id);
ChannelData *channel(const PeerId &id);
UserData *user(int32 user_id);
ChatData *chat(int32 chat_id);
ChannelData *channel(int32 channel_id);
UserData *self(); UserData *self();
PeerData *peerByName(const QString &username); PeerData *peerByName(const QString &username);
QString peerName(const PeerData *peer, bool forDialogs = false); QString peerName(const PeerData *peer, bool forDialogs = false);

View File

@ -224,18 +224,15 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) {
App::feedUsers(d.vusers); App::feedUsers(d.vusers);
const QVector<MTPImportedContact> &v(d.vimported.c_vector().v); const QVector<MTPImportedContact> &v(d.vimported.c_vector().v);
int32 uid = 0; UserData *user = nullptr;
if (!v.isEmpty()) { if (!v.isEmpty()) {
const MTPDimportedContact &c(v.front().c_importedContact()); const MTPDimportedContact &c(v.front().c_importedContact());
if (c.vclient_id.v != _contactId) return; if (c.vclient_id.v != _contactId) return;
uid = c.vuser_id.v; user = App::userLoaded(c.vuser_id.v);
if (uid && !App::userLoaded(uid)) {
uid = 0;
}
} }
if (uid) { if (user) {
Notify::userIsContactChanged(App::userLoaded(peerFromUser(uid)), true); Notify::userIsContactChanged(user, true);
Ui::hideLayer(); Ui::hideLayer();
} else { } else {
_save.hide(); _save.hide();

View File

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
static const int32 AppVersion = 9034; static const int32 AppVersion = 9034;
static const wchar_t *AppVersionStr = L"0.9.34"; static const wchar_t *AppVersionStr = L"0.9.34";
static const bool DevVersion = false; static const bool DevVersion = false;
#define BETA_VERSION (9034003ULL) // just comment this line to build public version #define BETA_VERSION (9034004ULL) // just comment this line to build public version
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)"; static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop"; static const wchar_t *AppName = L"Telegram Desktop";

View File

@ -2534,20 +2534,32 @@ Text::Text(style::font font, const QString &text, const TextParseOptions &option
} }
} }
Text::Text(const Text &other) : Text::Text(const Text &other)
_minResizeWidth(other._minResizeWidth), _maxWidth(other._maxWidth), : _minResizeWidth(other._minResizeWidth)
_minHeight(other._minHeight), , _maxWidth(other._maxWidth)
_text(other._text), , _minHeight(other._minHeight)
_font(other._font), , _text(other._text)
_blocks(other._blocks.size()), , _font(other._font)
_links(other._links), , _blocks(other._blocks.size())
_startDir(other._startDir) , _links(other._links)
{ , _startDir(other._startDir) {
for (int32 i = 0, l = _blocks.size(); i < l; ++i) { for (int32 i = 0, l = _blocks.size(); i < l; ++i) {
_blocks[i] = other._blocks.at(i)->clone(); _blocks[i] = other._blocks.at(i)->clone();
} }
} }
Text::Text(Text &&other)
: _minResizeWidth(other._minResizeWidth)
, _maxWidth(other._maxWidth)
, _minHeight(other._minHeight)
, _text(other._text)
, _font(other._font)
, _blocks(other._blocks)
, _links(other._links)
, _startDir(other._startDir) {
other.clearFields();
}
Text &Text::operator=(const Text &other) { Text &Text::operator=(const Text &other) {
_minResizeWidth = other._minResizeWidth; _minResizeWidth = other._minResizeWidth;
_maxWidth = other._maxWidth; _maxWidth = other._maxWidth;
@ -2563,10 +2575,23 @@ Text &Text::operator=(const Text &other) {
return *this; return *this;
} }
Text &Text::operator=(Text &&other) {
_minResizeWidth = other._minResizeWidth;
_maxWidth = other._maxWidth;
_minHeight = other._minHeight;
_text = other._text;
_font = other._font;
_blocks = other._blocks;
_links = other._links;
_startDir = other._startDir;
other.clearFields();
return *this;
}
void Text::setText(style::font font, const QString &text, const TextParseOptions &options) { void Text::setText(style::font font, const QString &text, const TextParseOptions &options) {
if (!_textStyle) _initDefault(); if (!_textStyle) _initDefault();
_font = font; _font = font;
clean(); clear();
{ {
TextParser parser(this, text, options); TextParser parser(this, text, options);
} }
@ -2644,7 +2669,7 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) {
void Text::setMarkedText(style::font font, const QString &text, const EntitiesInText &entities, const TextParseOptions &options) { void Text::setMarkedText(style::font font, const QString &text, const EntitiesInText &entities, const TextParseOptions &options) {
if (!_textStyle) _initDefault(); if (!_textStyle) _initDefault();
_font = font; _font = font;
clean(); clear();
{ {
// QString newText; // utf16 of the text for emoji // QString newText; // utf16 of the text for emoji
// newText.reserve(8 * text.size()); // newText.reserve(8 * text.size());
@ -3216,10 +3241,14 @@ EntitiesInText Text::originalEntities() const {
return result; return result;
} }
void Text::clean() { void Text::clear() {
for (TextBlocks::iterator i = _blocks.begin(), e = _blocks.end(); i != e; ++i) { for (TextBlocks::iterator i = _blocks.begin(), e = _blocks.end(); i != e; ++i) {
delete *i; delete *i;
} }
clearFields();
}
void Text::clearFields() {
_blocks.clear(); _blocks.clear();
_links.clear(); _links.clear();
_maxWidth = _minHeight = 0; _maxWidth = _minHeight = 0;

View File

@ -598,7 +598,9 @@ public:
Text(int32 minResizeWidth = QFIXED_MAX); Text(int32 minResizeWidth = QFIXED_MAX);
Text(style::font font, const QString &text, const TextParseOptions &options = _defaultOptions, int32 minResizeWidth = QFIXED_MAX, bool richText = false); Text(style::font font, const QString &text, const TextParseOptions &options = _defaultOptions, int32 minResizeWidth = QFIXED_MAX, bool richText = false);
Text(const Text &other); Text(const Text &other);
Text(Text &&other);
Text &operator=(const Text &other); Text &operator=(const Text &other);
Text &operator=(Text &&other);
int32 countWidth(int32 width) const; int32 countWidth(int32 width) const;
int32 countHeight(int32 width) const; int32 countHeight(int32 width) const;
@ -686,15 +688,19 @@ public:
return true; return true;
} }
void clean(); void clear();
~Text() { ~Text() {
clean(); clear();
} }
private: private:
void recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir = Qt::LayoutDirectionAuto); void recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir = Qt::LayoutDirectionAuto);
// clear() deletes all blocks and calls this method
// it is also called from move constructor / assignment operator
void clearFields();
QFixed _minResizeWidth, _maxWidth; QFixed _minResizeWidth, _maxWidth;
int32 _minHeight; int32 _minHeight;

File diff suppressed because it is too large Load Diff

View File

@ -936,7 +936,6 @@ protected:
}; };
class HistoryReply; // dynamic_cast optimize
class HistoryMessage; // dynamic_cast optimize class HistoryMessage; // dynamic_cast optimize
enum HistoryCursorState { enum HistoryCursorState {
@ -962,43 +961,104 @@ enum HistoryItemType {
HistoryItemJoined HistoryItemJoined
}; };
struct HistoryMessageVia : public BasicInterface<HistoryMessageVia> { struct HistoryMessageVia : public BaseComponent<HistoryMessageVia> {
HistoryMessageVia(Interfaces *); HistoryMessageVia(Composer*) {
}
void create(int32 userId); void create(int32 userId);
void resize(int32 availw) const; void resize(int32 availw) const;
UserData *_bot; UserData *_bot = nullptr;
mutable QString _text; mutable QString _text;
mutable int32 _width, _maxWidth; mutable int _width = 0;
mutable int _maxWidth = 0;
TextLinkPtr _lnk; TextLinkPtr _lnk;
}; };
struct HistoryMessageViews : public BasicInterface<HistoryMessageViews> { struct HistoryMessageViews : public BaseComponent<HistoryMessageViews> {
HistoryMessageViews(Interfaces *); HistoryMessageViews(Composer*) {
}
QString _viewsText; QString _viewsText;
int32 _views, _viewsWidth; int _views = 0;
int _viewsWidth = 0;
}; };
struct HistoryMessageSigned : public BasicInterface<HistoryMessageSigned> { struct HistoryMessageSigned : public BaseComponent<HistoryMessageSigned> {
HistoryMessageSigned(Interfaces *); HistoryMessageSigned(Composer*) {
}
void create(UserData *from, const QDateTime &date); void create(UserData *from, const QDateTime &date);
int32 maxWidth() const; int maxWidth() const;
Text _signature; Text _signature;
}; };
struct HistoryMessageForwarded : public BasicInterface<HistoryMessageForwarded> { struct HistoryMessageForwarded : public BaseComponent<HistoryMessageForwarded> {
HistoryMessageForwarded(Interfaces *); HistoryMessageForwarded(Composer*) {
}
void create(const HistoryMessageVia *via) const; void create(const HistoryMessageVia *via) const;
bool display(bool hasVia) const;
PeerData *_authorOriginal, *_fromOriginal; PeerData *_authorOriginal = nullptr;
MsgId _originalId; PeerData *_fromOriginal = nullptr;
mutable Text _text; MsgId _originalId = 0;
mutable Text _text = { 1 };
}; };
struct HistoryMessageReply : public BaseComponent<HistoryMessageReply> {
HistoryMessageReply(Composer*) {
}
HistoryMessageReply &operator=(HistoryMessageReply &&other) {
replyToMsgId = other.replyToMsgId;
std::swap(replyToMsg, other.replyToMsg);
replyToLnk = std11::move(other.replyToLnk);
replyToName = std11::move(other.replyToName);
replyToText = std11::move(other.replyToText);
replyToVersion = other.replyToVersion;
_maxReplyWidth = other._maxReplyWidth;
std::swap(_replyToVia, other._replyToVia);
return *this;
}
~HistoryMessageReply() {
// clearData() should be called by holder
t_assert(replyToMsg == nullptr);
t_assert(_replyToVia == nullptr);
}
bool updateData(HistoryMessage *holder, bool force = false);
void clearData(HistoryMessage *holder); // must be called before destructor
void checkNameUpdate() const;
void updateName() const;
void resize(int width) const;
void itemRemoved(HistoryMessage *holder, HistoryItem *removed);
enum PaintFlag {
PaintInBubble = 0x01,
PaintSelected = 0x02,
};
Q_DECLARE_FLAGS(PaintFlags, PaintFlag);
void paint(Painter &p, const HistoryItem *holder, int x, int y, int w, PaintFlags flags) const;
MsgId replyToId() const {
return replyToMsgId;
}
int replyToWidth() const {
return _maxReplyWidth;
}
TextLinkPtr replyToLink() const {
return replyToLnk;
}
MsgId replyToMsgId = 0;
HistoryItem *replyToMsg = nullptr;
TextLinkPtr replyToLnk;
mutable Text replyToName, replyToText;
mutable int replyToVersion = 0;
mutable int _maxReplyWidth = 0;
HistoryMessageVia *_replyToVia = nullptr;
int toWidth = 0;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(HistoryMessageReply::PaintFlags);
class HistoryDependentItemCallback : public SharedCallback2<void, ChannelData*, MsgId> { class HistoryDependentItemCallback : public SharedCallback2<void, ChannelData*, MsgId> {
public: public:
HistoryDependentItemCallback(FullMsgId dependent) : _dependent(dependent) { HistoryDependentItemCallback(FullMsgId dependent) : _dependent(dependent) {
@ -1012,28 +1072,30 @@ private:
// 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 BasicInterface<HistoryMessageDate> { struct HistoryMessageDate : public BaseComponent<HistoryMessageDate> {
HistoryMessageDate(Interfaces *); HistoryMessageDate(Composer*) {
}
void init(const QDateTime &date); void init(const QDateTime &date);
int height() const; int height() const;
void paint(Painter &p, int y, int w) const; void paint(Painter &p, int y, int w) const;
QString _text; QString _text;
int _width; int _width = 0;
}; };
// any HistoryItem can have this Interface for // any HistoryItem can have this Interface for
// displaying the unread messages bar above the message // displaying the unread messages bar above the message
struct HistoryMessageUnreadBar : public BasicInterface<HistoryMessageUnreadBar> { struct HistoryMessageUnreadBar : public BaseComponent<HistoryMessageUnreadBar> {
HistoryMessageUnreadBar(Interfaces *); HistoryMessageUnreadBar(Composer*) {
}
void init(int count); void init(int count);
int height() const; int height() const;
void paint(Painter &p, int y, int w) const; void paint(Painter &p, int y, int w) const;
QString _text; QString _text;
int _width; int _width = 0;
// if unread bar is freezed the new messages do not // if unread bar is freezed the new messages do not
// increment the counter displayed by this bar // increment the counter displayed by this bar
@ -1041,11 +1103,11 @@ struct HistoryMessageUnreadBar : public BasicInterface<HistoryMessageUnreadBar>
// it happens when we've opened the conversation and // it happens when we've opened the conversation and
// we've seen the bar and new messages are marked as read // we've seen the bar and new messages are marked as read
// as soon as they are added to the chat history // as soon as they are added to the chat history
bool _freezed; bool _freezed = false;
}; };
class HistoryMedia; class HistoryMedia;
class HistoryItem : public HistoryElem, public Interfaces { class HistoryItem : public HistoryElem, public Composer {
public: public:
HistoryItem(const HistoryItem &) = delete; HistoryItem(const HistoryItem &) = delete;
@ -1075,8 +1137,11 @@ public:
return true; return true;
} }
virtual UserData *viaBot() const { UserData *viaBot() const {
return 0; if (const HistoryMessageVia *via = Get<HistoryMessageVia>()) {
return via->_bot;
}
return nullptr;
} }
History *history() const { History *history() const {
@ -1165,6 +1230,9 @@ public:
bool isSilent() const { bool isSilent() const {
return _flags & MTPDmessage::Flag::f_silent; return _flags & MTPDmessage::Flag::f_silent;
} }
bool hasOutLayout() const {
return out() && !isPost();
}
virtual int32 viewsCount() const { virtual int32 viewsCount() const {
return hasViews() ? 1 : -1; return hasViews() ? 1 : -1;
} }
@ -1315,10 +1383,10 @@ public:
virtual const HistoryMessage *toHistoryMessage() const { // dynamic_cast optimize virtual const HistoryMessage *toHistoryMessage() const { // dynamic_cast optimize
return 0; return 0;
} }
virtual HistoryReply *toHistoryReply() { // dynamic_cast optimize MsgId replyToId() const {
return 0; if (auto *reply = Get<HistoryMessageReply>()) {
} return reply->replyToId();
virtual const HistoryReply *toHistoryReply() const { // dynamic_cast optimize }
return 0; return 0;
} }
@ -1433,7 +1501,7 @@ protected:
// this should be used only in previousItemChanged() // this should be used only in previousItemChanged()
// to add required bits to the Interfaces mask // to add required bits to the Interfaces mask
// after that always use Is<HistoryMessageDate>() // after that always use Has<HistoryMessageDate>()
bool displayDate() const { bool displayDate() const {
if (HistoryItem *prev = previous()) { if (HistoryItem *prev = previous()) {
return prev->date.date().day() != date.date().day(); return prev->date.date().day() != date.date().day();
@ -1750,7 +1818,7 @@ public:
return _caption.original(); return _caption.original();
} }
bool needsBubble(const HistoryItem *parent) const override { bool needsBubble(const HistoryItem *parent) const override {
return !_caption.isEmpty() || parent->Is<HistoryMessageForwarded>() || parent->toHistoryReply() || parent->viaBot(); return !_caption.isEmpty() || parent->Has<HistoryMessageForwarded>() || parent->Has<HistoryMessageReply>() || parent->viaBot();
} }
bool customInfoLayout() const override { bool customInfoLayout() const override {
return _caption.isEmpty(); return _caption.isEmpty();
@ -1819,7 +1887,7 @@ public:
return _caption.original(); return _caption.original();
} }
bool needsBubble(const HistoryItem *parent) const override { bool needsBubble(const HistoryItem *parent) const override {
return !_caption.isEmpty() || parent->Is<HistoryMessageForwarded>() || parent->toHistoryReply() || parent->viaBot(); return !_caption.isEmpty() || parent->Has<HistoryMessageForwarded>() || parent->Has<HistoryMessageReply>() || parent->viaBot();
} }
bool customInfoLayout() const override { bool customInfoLayout() const override {
return _caption.isEmpty(); return _caption.isEmpty();
@ -1850,25 +1918,25 @@ private:
}; };
struct HistoryDocumentThumbed : public BasicInterface<HistoryDocumentThumbed> { struct HistoryDocumentThumbed : public BaseComponent<HistoryDocumentThumbed> {
HistoryDocumentThumbed(Interfaces *interfaces) : _thumbw(0), _linkw(0) { HistoryDocumentThumbed(Composer*) {
} }
TextLinkPtr _linksavel, _linkcancell; TextLinkPtr _linksavel, _linkcancell;
int32 _thumbw; int _thumbw = 0;
mutable int32 _linkw; mutable int _linkw = 0;
mutable QString _link; mutable QString _link;
}; };
struct HistoryDocumentCaptioned : public BasicInterface<HistoryDocumentCaptioned> { struct HistoryDocumentCaptioned : public BaseComponent<HistoryDocumentCaptioned> {
HistoryDocumentCaptioned(Interfaces *interfaces) : _caption(st::msgFileMinWidth - st::msgPadding.left() - st::msgPadding.right()) { HistoryDocumentCaptioned(Composer*) : _caption(st::msgFileMinWidth - st::msgPadding.left() - st::msgPadding.right()) {
} }
Text _caption; Text _caption;
}; };
struct HistoryDocumentNamed : public BasicInterface<HistoryDocumentNamed> { struct HistoryDocumentNamed : public BaseComponent<HistoryDocumentNamed> {
HistoryDocumentNamed(Interfaces *interfaces) : _namew(0) { HistoryDocumentNamed(Composer*) {
} }
QString _name; QString _name;
int32 _namew; int _namew = 0;
}; };
class HistoryDocument; class HistoryDocument;
struct HistoryDocumentVoicePlayback { struct HistoryDocumentVoicePlayback {
@ -1878,18 +1946,22 @@ struct HistoryDocumentVoicePlayback {
anim::fvalue a_progress; anim::fvalue a_progress;
Animation _a_progress; Animation _a_progress;
}; };
struct HistoryDocumentVoice : public BasicInterface<HistoryDocumentVoice> { struct HistoryDocumentVoice : public BaseComponent<HistoryDocumentVoice> {
HistoryDocumentVoice(Interfaces *that) : _playback(0) { HistoryDocumentVoice(Composer*) {
}
HistoryDocumentVoice &operator=(HistoryDocumentVoice &&other) {
std::swap(_playback, other._playback);
return *this;
} }
~HistoryDocumentVoice() { ~HistoryDocumentVoice() {
deleteAndMark(_playback); deleteAndMark(_playback);
} }
void ensurePlayback(const HistoryDocument *interfaces) const; void ensurePlayback(const HistoryDocument *interfaces) const;
void checkPlaybackFinished() const; void checkPlaybackFinished() const;
mutable HistoryDocumentVoicePlayback *_playback; mutable HistoryDocumentVoicePlayback *_playback = nullptr;
}; };
class HistoryDocument : public HistoryFileMedia, public Interfaces { class HistoryDocument : public HistoryFileMedia, public Composer {
public: public:
HistoryDocument(DocumentData *document, const QString &caption, const HistoryItem *parent); HistoryDocument(DocumentData *document, const QString &caption, const HistoryItem *parent);
@ -2021,7 +2093,7 @@ public:
return _caption.original(); return _caption.original();
} }
bool needsBubble(const HistoryItem *parent) const override { bool needsBubble(const HistoryItem *parent) const override {
return !_caption.isEmpty() || parent->Is<HistoryMessageForwarded>() || parent->toHistoryReply() || parent->viaBot(); return !_caption.isEmpty() || parent->Has<HistoryMessageForwarded>() || parent->Has<HistoryMessageReply>() || parent->viaBot();
} }
bool customInfoLayout() const override { bool customInfoLayout() const override {
return _caption.isEmpty(); return _caption.isEmpty();
@ -2327,7 +2399,7 @@ public:
} }
bool needsBubble(const HistoryItem *parent) const { bool needsBubble(const HistoryItem *parent) const {
return !_title.isEmpty() || !_description.isEmpty() || parent->Is<HistoryMessageForwarded>() || parent->toHistoryReply() || parent->viaBot(); return !_title.isEmpty() || !_description.isEmpty() || parent->Has<HistoryMessageForwarded>() || parent->Has<HistoryMessageReply>() || parent->viaBot();
} }
bool customInfoLayout() const { bool customInfoLayout() const {
return true; return true;
@ -2365,14 +2437,14 @@ public:
static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd) { static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd) {
return _create(history, msgId, flags, date, from, fwd); return _create(history, msgId, flags, date, from, fwd);
} }
static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities) { static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities) {
return _create(history, msgId, flags, viaBotId, date, from, msg, entities); return _create(history, msgId, flags, replyTo, viaBotId, date, from, msg, entities);
} }
static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption) { static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption) {
return _create(history, msgId, flags, viaBotId, date, from, doc, caption); return _create(history, msgId, flags, replyTo, viaBotId, date, from, doc, caption);
} }
static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption) { static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption) {
return _create(history, msgId, flags, viaBotId, date, from, photo, caption); return _create(history, msgId, flags, replyTo, viaBotId, date, from, photo, caption);
} }
void initTime(); void initTime();
@ -2380,13 +2452,6 @@ public:
void initMediaFromDocument(DocumentData *doc, const QString &caption); void initMediaFromDocument(DocumentData *doc, const QString &caption);
void fromNameUpdated(int32 width) const; void fromNameUpdated(int32 width) const;
virtual UserData *viaBot() const override {
if (const HistoryMessageVia *via = Get<HistoryMessageVia>()) {
return via->_bot;
}
return 0;
}
int32 plainMaxWidth() const; int32 plainMaxWidth() const;
void countPositionAndSize(int32 &left, int32 &width) const; void countPositionAndSize(int32 &left, int32 &width) const;
@ -2403,7 +2468,7 @@ public:
if (!hasFromName()) return false; if (!hasFromName()) return false;
if (isAttachedToPrevious()) return false; if (isAttachedToPrevious()) return false;
return (!emptyText() || !_media || !_media->isDisplayed() || toHistoryReply() || Is<HistoryMessageForwarded>() || viaBot() || !_media->hideFromName()); return (!emptyText() || !_media || !_media->isDisplayed() || Has<HistoryMessageReply>() || Has<HistoryMessageForwarded>() || viaBot() || !_media->hideFromName());
} }
bool uploading() const { bool uploading() const {
return _media && _media->uploading(); return _media && _media->uploading();
@ -2414,7 +2479,7 @@ public:
void setId(MsgId newId) override; void setId(MsgId newId) override;
void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const override; void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const override;
virtual void drawMessageText(Painter &p, QRect trect, uint32 selection) const; void dependencyItemRemoved(HistoryItem *dependency) override;
void destroy() override; void destroy() override;
@ -2422,7 +2487,6 @@ public:
bool pointInTime(int32 right, int32 bottom, int32 x, int32 y, InfoDisplayType type) const override; bool pointInTime(int32 right, int32 bottom, int32 x, int32 y, InfoDisplayType type) const override;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const override; void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const override;
virtual void getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const override; void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const override;
uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const override { uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const override {
@ -2491,6 +2555,16 @@ public:
return HistoryItem::viewsCount(); return HistoryItem::viewsCount();
} }
bool updateDependencyItem() override {
if (auto *reply = Get<HistoryMessageReply>()) {
return reply->updateData(this, true);
}
return true;
}
MsgId dependencyMsgId() const override {
return replyToId();
}
HistoryMessage *toHistoryMessage() override { // dynamic_cast optimize HistoryMessage *toHistoryMessage() override { // dynamic_cast optimize
return this; return this;
} }
@ -2509,23 +2583,26 @@ protected:
HistoryMessage(History *history, const MTPDmessage &msg); HistoryMessage(History *history, const MTPDmessage &msg);
HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd); // local forwarded HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd); // local forwarded
HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities); // local message HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities); // local message
HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption); // local document HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption); // local document
HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption); // local photo HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption); // local photo
friend class HistoryItemInstantiated<HistoryMessage>; friend class HistoryItemInstantiated<HistoryMessage>;
void initDimensions() override; void initDimensions() override;
int resizeGetHeight_(int width) override; int resizeGetHeight_(int width) override;
void createInterfaces(int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal = 0, const PeerId &fromIdOriginal = 0, MsgId originalId = 0);
bool displayForwardedFrom() const { bool displayForwardedFrom() const {
if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) { if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) {
return Is<HistoryMessageVia>() || !_media || !_media->isDisplayed() || fwd->_authorOriginal->isChannel() || !_media->hideForwardedFrom(); return Has<HistoryMessageVia>() || !_media || !_media->isDisplayed() || fwd->_authorOriginal->isChannel() || !_media->hideForwardedFrom();
} }
return false; return false;
} }
void paintForwardedInfo(Painter &p, int32 x, int32 y, int32 w, bool selected) const;
void paintForwardedInfo(Painter &p, QRect &trect, bool selected) const;
void paintReplyInfo(Painter &p, QRect &trect, bool selected) const;
// this method draws "via @bot" if it is not painted in forwarded info or in from name
void paintViaBotIdInfo(Painter &p, QRect &trect, bool selected) const;
Text _text = { int(st::msgMinWidth) }; Text _text = { int(st::msgMinWidth) };
@ -2536,79 +2613,8 @@ protected:
QString _timeText; QString _timeText;
int _timeWidth = 0; int _timeWidth = 0;
}; void createInterfacesHelper(MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId);
void createInterfaces(MsgId replyTo, int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal = 0, const PeerId &fromIdOriginal = 0, MsgId originalId = 0);
class HistoryReply : public HistoryMessage, private HistoryItemInstantiated<HistoryReply> {
public:
static HistoryReply *create(History *history, const MTPDmessage &msg) {
return _create(history, msg);
}
static HistoryReply *create(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption) {
return _create(history, msgId, flags, viaBotId, replyTo, date, from, doc, caption);
}
static HistoryReply *create(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption) {
return _create(history, msgId, flags, viaBotId, replyTo, date, from, photo, caption);
}
bool updateDependencyItem() override {
return updateReplyTo(true);
}
MsgId dependencyMsgId() const override {
return replyToId();
}
int32 replyToWidth() const;
TextLinkPtr replyToLink() const;
MsgId replyToId() const;
HistoryItem *replyToMessage() const;
void dependencyItemRemoved(HistoryItem *dependency) override;
void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const override;
void drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selected, bool likeService = false) const;
void drawMessageText(Painter &p, QRect trect, uint32 selection) const override;
void resizeVia(int32 w) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const override;
void getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const override;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const override;
PeerData *replyTo() const {
return replyToMsg ? replyToMsg->author() : 0;
}
QString selectedText(uint32 selection) const override;
HistoryReply *toHistoryReply() override { // dynamic_cast optimize
return this;
}
const HistoryReply *toHistoryReply() const override { // dynamic_cast optimize
return this;
}
~HistoryReply();
protected:
HistoryReply(History *history, const MTPDmessage &msg);
HistoryReply(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption);
HistoryReply(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption);
using HistoryItemInstantiated<HistoryReply>::_create;
friend class HistoryItemInstantiated<HistoryReply>;
void initDimensions() override;
int resizeGetHeight_(int width) override;
bool updateReplyTo(bool force = false);
void replyToNameUpdated() const;
MsgId replyToMsgId;
HistoryItem *replyToMsg;
TextLinkPtr replyToLnk;
mutable Text replyToName, replyToText;
mutable int32 replyToVersion;
mutable int32 _maxReplyWidth;
HistoryMessageVia *_replyToVia;
int32 toWidth;
}; };
@ -2627,7 +2633,7 @@ inline MTPDmessage::Flags newForwardedFlags(PeerData *p, int32 from, HistoryMess
if (from) { if (from) {
result |= MTPDmessage::Flag::f_from_id; result |= MTPDmessage::Flag::f_from_id;
} }
if (fwd->Is<HistoryMessageVia>()) { if (fwd->Has<HistoryMessageVia>()) {
result |= MTPDmessage::Flag::f_via_bot_id; result |= MTPDmessage::Flag::f_via_bot_id;
} }
if (!p->isChannel()) { if (!p->isChannel()) {
@ -2642,21 +2648,22 @@ inline MTPDmessage::Flags newForwardedFlags(PeerData *p, int32 from, HistoryMess
return result; return result;
} }
struct HistoryServicePinned : public BasicInterface<HistoryServicePinned> { struct HistoryServicePinned : public BaseComponent<HistoryServicePinned> {
HistoryServicePinned(Interfaces *); HistoryServicePinned(Composer*) {
}
MsgId msgId; MsgId msgId = 0;
HistoryItem *msg; HistoryItem *msg = nullptr;
TextLinkPtr lnk; TextLinkPtr lnk;
}; };
class HistoryServiceMessage : public HistoryItem, private HistoryItemInstantiated<HistoryServiceMessage> { class HistoryService : public HistoryItem, private HistoryItemInstantiated<HistoryService> {
public: public:
static HistoryServiceMessage *create(History *history, const MTPDmessageService &msg) { static HistoryService *create(History *history, const MTPDmessageService &msg) {
return _create(history, msg); return _create(history, msg);
} }
static HistoryServiceMessage *create(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags = 0, HistoryMedia *media = 0, int32 from = 0) { static HistoryService *create(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags = 0, HistoryMedia *media = 0, int32 from = 0) {
return _create(history, msgId, date, msg, flags, media, from); return _create(history, msgId, date, msg, flags, media, from);
} }
@ -2710,13 +2717,13 @@ public:
void setServiceText(const QString &text); void setServiceText(const QString &text);
~HistoryServiceMessage(); ~HistoryService();
protected: protected:
HistoryServiceMessage(History *history, const MTPDmessageService &msg); HistoryService(History *history, const MTPDmessageService &msg);
HistoryServiceMessage(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags = 0, HistoryMedia *media = 0, int32 from = 0); HistoryService(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags = 0, HistoryMedia *media = 0, int32 from = 0);
friend class HistoryItemInstantiated<HistoryServiceMessage>; friend class HistoryItemInstantiated<HistoryService>;
void initDimensions() override; void initDimensions() override;
int resizeGetHeight_(int width) override; int resizeGetHeight_(int width) override;
@ -2731,7 +2738,7 @@ protected:
int32 _textWidth, _textHeight; int32 _textWidth, _textHeight;
}; };
class HistoryGroup : public HistoryServiceMessage, private HistoryItemInstantiated<HistoryGroup> { class HistoryGroup : public HistoryService, private HistoryItemInstantiated<HistoryGroup> {
public: public:
static HistoryGroup *create(History *history, const MTPDmessageGroup &group, const QDateTime &date) { static HistoryGroup *create(History *history, const MTPDmessageGroup &group, const QDateTime &date) {
@ -2787,7 +2794,7 @@ private:
}; };
class HistoryCollapse : public HistoryServiceMessage, private HistoryItemInstantiated<HistoryCollapse> { class HistoryCollapse : public HistoryService, private HistoryItemInstantiated<HistoryCollapse> {
public: public:
static HistoryCollapse *create(History *history, MsgId wasMinId, const QDateTime &date) { static HistoryCollapse *create(History *history, MsgId wasMinId, const QDateTime &date) {
@ -2822,7 +2829,7 @@ private:
}; };
class HistoryJoined : public HistoryServiceMessage, private HistoryItemInstantiated<HistoryJoined> { class HistoryJoined : public HistoryService, private HistoryItemInstantiated<HistoryJoined> {
public: public:
static HistoryJoined *create(History *history, const QDateTime &date, UserData *from, MTPDmessage::Flags flags) { static HistoryJoined *create(History *history, const QDateTime &date, UserData *from, MTPDmessage::Flags flags) {

View File

@ -948,7 +948,8 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data()); PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
bool lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideo() : false; bool lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideo() : false;
bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != 0) : false; bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false;
bool lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false;
if (lnkPhoto || lnkDocument) { if (lnkPhoto || lnkDocument) {
if (isUponSelected > 0) { if (isUponSelected > 0) {
_menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true); _menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
@ -978,7 +979,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (lnkDocument && !lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { if (lnkDocument && !lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked).isEmpty()) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true); _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true);
} }
_menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsAudio ? lng_context_save_audio : lng_context_save_file)), this, SLOT(saveContextFile()))->setEnabled(true); _menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsAudio ? lng_context_save_audio : (lnkIsSong ? lng_context_save_audio_file : lng_context_save_file))), this, SLOT(saveContextFile()))->setEnabled(true);
} }
} }
if (item && item->hasDirectLink() && isUponSelected != 2 && isUponSelected != -2) { if (item && item->hasDirectLink() && isUponSelected != 2 && isUponSelected != -2) {
@ -5996,7 +5997,7 @@ void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, bool silent, const M
uint64 randomId = rand_value<uint64>(); uint64 randomId = rand_value<uint64>();
App::historyRegRandom(randomId, newId); App::historyRegRandom(randomId, newId);
History *hist = item->history(); History *hist = item->history();
MsgId replyTo = item->toHistoryReply() ? item->toHistoryReply()->replyToId() : 0; MsgId replyTo = item->replyToId();
MTPmessages_SendMedia::Flags sendFlags = 0; MTPmessages_SendMedia::Flags sendFlags = 0;
if (replyTo) { if (replyTo) {
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id; sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
@ -6048,7 +6049,7 @@ void HistoryWidget::onDocumentUploaded(const FullMsgId &newId, bool silent, cons
uint64 randomId = rand_value<uint64>(); uint64 randomId = rand_value<uint64>();
App::historyRegRandom(randomId, newId); App::historyRegRandom(randomId, newId);
History *hist = item->history(); History *hist = item->history();
MsgId replyTo = item->toHistoryReply() ? item->toHistoryReply()->replyToId() : 0; MsgId replyTo = item->replyToId();
MTPmessages_SendMedia::Flags sendFlags = 0; MTPmessages_SendMedia::Flags sendFlags = 0;
if (replyTo) { if (replyTo) {
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id; sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
@ -6077,7 +6078,7 @@ void HistoryWidget::onThumbDocumentUploaded(const FullMsgId &newId, bool silent,
uint64 randomId = rand_value<uint64>(); uint64 randomId = rand_value<uint64>();
App::historyRegRandom(randomId, newId); App::historyRegRandom(randomId, newId);
History *hist = item->history(); History *hist = item->history();
MsgId replyTo = item->toHistoryReply() ? item->toHistoryReply()->replyToId() : 0; MsgId replyTo = item->replyToId();
MTPmessages_SendMedia::Flags sendFlags = 0; MTPmessages_SendMedia::Flags sendFlags = 0;
if (replyTo) { if (replyTo) {
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id; sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
@ -6986,7 +6987,7 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
} else if (_pinnedBar->msgId != pinnedMsgId) { } else if (_pinnedBar->msgId != pinnedMsgId) {
_pinnedBar->msgId = pinnedMsgId; _pinnedBar->msgId = pinnedMsgId;
_pinnedBar->msg = 0; _pinnedBar->msg = 0;
_pinnedBar->text.clean(); _pinnedBar->text.clear();
updatePinnedBar(); updatePinnedBar();
update(); update();
} }

View File

@ -293,9 +293,10 @@ void LayoutAbstractFileItem::setStatusSize(int32 newSize, int32 fullSize, int32
} }
} }
LayoutOverviewDate::LayoutOverviewDate(const QDate &date, bool month) : LayoutItem(OverviewItemInfo::Bit()) LayoutOverviewDate::LayoutOverviewDate(const QDate &date, bool month) : LayoutItem()
, _date(date) , _date(date)
, _text(month ? langMonthFull(date) : langDayOfMonthFull(date)) { , _text(month ? langMonthFull(date) : langDayOfMonthFull(date)) {
AddComponents(OverviewItemInfo::Bit());
} }
void LayoutOverviewDate::initDimensions() { void LayoutOverviewDate::initDimensions() {
@ -311,7 +312,7 @@ void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection,
} }
} }
LayoutOverviewPhoto::LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent) : LayoutMediaItem(0, parent) LayoutOverviewPhoto::LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent) : LayoutMediaItem(parent)
, _data(photo) , _data(photo)
, _link(new PhotoLink(photo)) , _link(new PhotoLink(photo))
, _goodLoaded(false) { , _goodLoaded(false) {
@ -385,7 +386,7 @@ void LayoutOverviewPhoto::getState(TextLinkPtr &link, HistoryCursorState &cursor
} }
} }
LayoutOverviewVideo::LayoutOverviewVideo(DocumentData *video, HistoryItem *parent) : LayoutAbstractFileItem(0, parent) LayoutOverviewVideo::LayoutOverviewVideo(DocumentData *video, HistoryItem *parent) : LayoutAbstractFileItem(parent)
, _data(video) , _data(video)
, _duration(formatDurationText(_data->duration())) , _duration(formatDurationText(_data->duration()))
, _thumbLoaded(false) { , _thumbLoaded(false) {
@ -549,9 +550,11 @@ void LayoutOverviewVideo::updateStatusText() const {
} }
} }
LayoutOverviewVoice::LayoutOverviewVoice(DocumentData *voice, HistoryItem *parent) : LayoutAbstractFileItem(OverviewItemInfo::Bit(), parent) LayoutOverviewVoice::LayoutOverviewVoice(DocumentData *voice, HistoryItem *parent) : LayoutAbstractFileItem(parent)
, _data(voice) , _data(voice)
, _namel(new DocumentOpenLink(_data)) { , _namel(new DocumentOpenLink(_data)) {
AddComponents(OverviewItemInfo::Bit());
t_assert(_data->voice() != 0); t_assert(_data->voice() != 0);
setLinks(new DocumentOpenLink(_data), new DocumentOpenLink(_data), new DocumentCancelLink(_data)); setLinks(new DocumentOpenLink(_data), new DocumentOpenLink(_data), new DocumentCancelLink(_data));
@ -741,7 +744,7 @@ bool LayoutOverviewVoice::updateStatusText() const {
return showPause; return showPause;
} }
LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent) : LayoutAbstractFileItem(OverviewItemInfo::Bit(), parent) LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent) : LayoutAbstractFileItem(parent)
, _data(document) , _data(document)
, _msgl(new MessageLink(parent)) , _msgl(new MessageLink(parent))
, _namel(new DocumentOpenLink(_data)) , _namel(new DocumentOpenLink(_data))
@ -751,6 +754,8 @@ LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryIt
, _namew(st::semiboldFont->width(_name)) , _namew(st::semiboldFont->width(_name))
, _datew(st::normalFont->width(_date)) , _datew(st::normalFont->width(_date))
, _colorIndex(documentColorIndex(_data, _ext)) { , _colorIndex(documentColorIndex(_data, _ext)) {
AddComponents(OverviewItemInfo::Bit());
setLinks(new DocumentOpenLink(_data), new DocumentSaveLink(_data), new DocumentCancelLink(_data)); setLinks(new DocumentOpenLink(_data), new DocumentSaveLink(_data), new DocumentCancelLink(_data));
setStatusSize(FileStatusSizeReady, _data->size, _data->song() ? _data->song()->duration : -1, 0); setStatusSize(FileStatusSizeReady, _data->size, _data->song() ? _data->song()->duration : -1, 0);
@ -1066,7 +1071,9 @@ namespace {
} }
} }
LayoutOverviewLink::LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent) : LayoutMediaItem(OverviewItemInfo::Bit(), parent) { LayoutOverviewLink::LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent) : LayoutMediaItem(parent) {
AddComponents(OverviewItemInfo::Bit());
QString text = _parent->originalText(); QString text = _parent->originalText();
EntitiesInText entities = _parent->originalEntities(); EntitiesInText entities = _parent->originalEntities();
@ -1319,7 +1326,7 @@ LayoutOverviewLink::Link::Link(const QString &url, const QString &text)
, lnk(linkFromUrl(url)) { , lnk(linkFromUrl(url)) {
} }
LayoutInlineItem::LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo) : LayoutItem(0) LayoutInlineItem::LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo) : LayoutItem()
, _result(result) , _result(result)
, _doc(doc) , _doc(doc)
, _photo(photo) , _photo(photo)

View File

@ -101,10 +101,11 @@ public:
}; };
class LayoutMediaItem; class LayoutMediaItem;
class LayoutItem : public Interfaces { class LayoutItem : public Composer {
public: public:
LayoutItem(uint64 i_mask) : Interfaces(i_mask), _maxw(0), _minh(0) { LayoutItem() {
} }
LayoutItem &operator=(const LayoutItem &) = delete;
int32 maxWidth() const { int32 maxWidth() const {
return _maxw; return _maxw;
@ -167,14 +168,16 @@ public:
} }
protected: protected:
int32 _width, _height, _maxw, _minh; int _width = 0;
LayoutItem &operator=(const LayoutItem &); int _height = 0;
int _maxw = 0;
int _minh = 0;
}; };
class LayoutMediaItem : public LayoutItem { class LayoutMediaItem : public LayoutItem {
public: public:
LayoutMediaItem(uint64 i_mask, HistoryItem *parent) : LayoutItem(i_mask), _parent(parent) { LayoutMediaItem(HistoryItem *parent) : _parent(parent) {
} }
virtual LayoutMediaItem *toLayoutMediaItem() { virtual LayoutMediaItem *toLayoutMediaItem() {
@ -194,7 +197,7 @@ protected:
class LayoutRadialProgressItem : public LayoutMediaItem { class LayoutRadialProgressItem : public LayoutMediaItem {
public: public:
LayoutRadialProgressItem(uint64 i_mask, HistoryItem *parent) : LayoutMediaItem(i_mask, parent) LayoutRadialProgressItem(HistoryItem *parent) : LayoutMediaItem(parent)
, _radial(0) , _radial(0)
, a_iconOver(0, 0) , a_iconOver(0, 0)
, _a_iconOver(animation(this, &LayoutRadialProgressItem::step_iconOver)) { , _a_iconOver(animation(this, &LayoutRadialProgressItem::step_iconOver)) {
@ -240,7 +243,7 @@ private:
class LayoutAbstractFileItem : public LayoutRadialProgressItem { class LayoutAbstractFileItem : public LayoutRadialProgressItem {
public: public:
LayoutAbstractFileItem(uint64 i_mask, HistoryItem *parent) : LayoutRadialProgressItem(i_mask, parent) { LayoutAbstractFileItem(HistoryItem *parent) : LayoutRadialProgressItem(parent) {
} }
protected: protected:
@ -268,19 +271,19 @@ public:
}; };
class OverviewItemInfo : public BasicInterface<OverviewItemInfo> { class OverviewItemInfo : public BaseComponent<OverviewItemInfo> {
public: public:
OverviewItemInfo(Interfaces *) : _top(0) { OverviewItemInfo(Composer*) {
} }
int32 top() const { int top() const {
return _top; return _top;
} }
void setTop(int32 top) { void setTop(int top) {
_top = top; _top = top;
} }
private: private:
int32 _top; int _top = 0;
}; };

View File

@ -3550,7 +3550,7 @@ namespace Local {
return result; return result;
} }
void _writePeer(QDataStream &stream, PeerData *peer, int32 fileVersion = AppVersion) { void _writePeer(QDataStream &stream, PeerData *peer) {
stream << quint64(peer->id) << quint64(peer->photoId); stream << quint64(peer->id) << quint64(peer->photoId);
_writeStorageImageLocation(stream, peer->photoLoc); _writeStorageImageLocation(stream, peer->photoLoc);
if (peer->isUser()) { if (peer->isUser()) {
@ -3560,7 +3560,7 @@ namespace Local {
if (AppVersion >= 9012) { if (AppVersion >= 9012) {
stream << qint32(user->flags); stream << qint32(user->flags);
} }
if (AppVersion >= 9016 || fileVersion >= 9016) { if (AppVersion >= 9016) {
stream << (user->botInfo ? user->botInfo->inlinePlaceholder : QString()); stream << (user->botInfo ? user->botInfo->inlinePlaceholder : QString());
} }
stream << qint32(user->onlineTill) << qint32(user->contact) << qint32(user->botInfo ? user->botInfo->version : -1); stream << qint32(user->onlineTill) << qint32(user->contact) << qint32(user->botInfo ? user->botInfo->version : -1);
@ -3580,18 +3580,16 @@ namespace Local {
} }
PeerData *_readPeer(FileReadDescriptor &from, int32 fileVersion = 0) { PeerData *_readPeer(FileReadDescriptor &from, int32 fileVersion = 0) {
PeerData *result = 0;
quint64 peerId = 0, photoId = 0; quint64 peerId = 0, photoId = 0;
from.stream >> peerId >> photoId; from.stream >> peerId >> photoId;
StorageImageLocation photoLoc(_readStorageImageLocation(from)); StorageImageLocation photoLoc(_readStorageImageLocation(from));
result = App::peerLoaded(peerId); PeerData *result = App::peerLoaded(peerId);
bool wasLoaded = (result && result->loaded); bool wasLoaded = (result != nullptr);
if (!wasLoaded) { if (!wasLoaded) {
result = App::peer(peerId); result = App::peer(peerId);
result->loaded = true; result->loadedStatus = PeerData::FullLoaded;
} }
if (result->isUser()) { if (result->isUser()) {
UserData *user = result->asUser(); UserData *user = result->asUser();
@ -3737,7 +3735,7 @@ namespace Local {
} }
data.stream << quint32(botsCnt); data.stream << quint32(botsCnt);
for (RecentInlineBots::const_iterator i = bots.cbegin(), e = bots.cend(); i != e; ++i) { for (RecentInlineBots::const_iterator i = bots.cbegin(), e = bots.cend(); i != e; ++i) {
_writePeer(data.stream, *i, 9016); _writePeer(data.stream, *i);
} }
FileWriteDescriptor file(_recentHashtagsAndBotsKey); FileWriteDescriptor file(_recentHashtagsAndBotsKey);
file.writeEncrypted(data); file.writeEncrypted(data);

View File

@ -4099,17 +4099,17 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
case mtpc_updateShortMessage: { case mtpc_updateShortMessage: {
const MTPDupdateShortMessage &d(updates.c_updateShortMessage()); const MTPDupdateShortMessage &d(updates.c_updateShortMessage());
if (!App::userLoaded(d.vuser_id.v) || (d.has_via_bot_id() && !App::peerLoaded(peerFromUser(d.vvia_bot_id)))) { if (!App::userLoaded(d.vuser_id.v) || (d.has_via_bot_id() && !App::userLoaded(d.vvia_bot_id.v))) {
MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
return getDifference(); return getDifference();
} }
if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_messageFwdHeader) { if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_messageFwdHeader) {
const MTPDmessageFwdHeader &f(d.vfwd_from.c_messageFwdHeader()); const MTPDmessageFwdHeader &f(d.vfwd_from.c_messageFwdHeader());
if (f.has_from_id() && !App::peerLoaded(peerFromUser(f.vfrom_id))) { if (f.has_from_id() && !App::userLoaded(f.vfrom_id.v)) {
MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
return getDifference(); return getDifference();
} }
if (f.has_channel_id() && !App::peerLoaded(peerFromChannel(f.vchannel_id))) { if (f.has_channel_id() && !App::channelLoaded(f.vchannel_id.v)) {
MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
return getDifference(); return getDifference();
} }
@ -4133,18 +4133,18 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
case mtpc_updateShortChatMessage: { case mtpc_updateShortChatMessage: {
const MTPDupdateShortChatMessage &d(updates.c_updateShortChatMessage()); const MTPDupdateShortChatMessage &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) || noFrom || (d.has_via_bot_id() && !App::peerLoaded(peerFromUser(d.vvia_bot_id)))) { if (!App::chatLoaded(d.vchat_id.v) || noFrom || (d.has_via_bot_id() && !App::userLoaded(d.vvia_bot_id.v))) {
MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
if (noFrom && App::api()) App::api()->requestFullPeer(App::chatLoaded(d.vchat_id.v)); if (noFrom && App::api()) App::api()->requestFullPeer(App::chatLoaded(d.vchat_id.v));
return getDifference(); return getDifference();
} }
if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_messageFwdHeader) { if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_messageFwdHeader) {
const MTPDmessageFwdHeader &f(d.vfwd_from.c_messageFwdHeader()); const MTPDmessageFwdHeader &f(d.vfwd_from.c_messageFwdHeader());
if (f.has_from_id() && !App::peerLoaded(peerFromUser(f.vfrom_id))) { if (f.has_from_id() && !App::userLoaded(f.vfrom_id.v)) {
MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
return getDifference(); return getDifference();
} }
if (f.has_channel_id() && !App::peerLoaded(peerFromChannel(f.vchannel_id))) { if (f.has_channel_id() && !App::channelLoaded(f.vchannel_id.v)) {
MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
return getDifference(); return getDifference();
} }
@ -4357,9 +4357,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateChatUserTyping: { case mtpc_updateChatUserTyping: {
const MTPDupdateChatUserTyping &d(update.c_updateChatUserTyping()); const MTPDupdateChatUserTyping &d(update.c_updateChatUserTyping());
History *history = 0; History *history = 0;
if (PeerData *chat = App::peerLoaded(peerFromChat(d.vchat_id.v))) { if (PeerData *chat = App::chatLoaded(d.vchat_id.v)) {
history = App::historyLoaded(chat->id); history = App::historyLoaded(chat->id);
} else if (PeerData *channel = App::peerLoaded(peerFromChannel(d.vchat_id.v))) { } else if (PeerData *channel = App::channelLoaded(d.vchat_id.v)) {
history = App::historyLoaded(channel->id); history = App::historyLoaded(channel->id);
} }
UserData *user = (d.vuser_id.v == MTP::authedId()) ? 0 : App::userLoaded(d.vuser_id.v); UserData *user = (d.vuser_id.v == MTP::authedId()) ? 0 : App::userLoaded(d.vuser_id.v);

View File

@ -1267,8 +1267,9 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
_contextMenuLnk = textlnkOver(); _contextMenuLnk = textlnkOver();
PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data()); PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != 0) : false;
bool lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideo() : false; bool lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideo() : false;
bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false;
bool lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false;
if (lnkPhoto || lnkDocument) { if (lnkPhoto || lnkDocument) {
_menu = new PopupMenu(); _menu = new PopupMenu();
if (App::hoveredLinkItem()) { if (App::hoveredLinkItem()) {
@ -1282,7 +1283,7 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (lnkDocument && !lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { if (lnkDocument && !lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked).isEmpty()) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true); _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true);
} }
_menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsAudio ? lng_context_save_audio : lng_context_save_file)), this, SLOT(saveContextFile()))->setEnabled(true); _menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsAudio ? lng_context_save_audio : (lnkIsSong ? lng_context_save_audio_file : lng_context_save_file))), this, SLOT(saveContextFile()))->setEnabled(true);
} }
} }
if (isUponSelected > 1) { if (isUponSelected > 1) {

View File

@ -35,8 +35,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "localstorage.h" #include "localstorage.h"
namespace { namespace {
int32 peerColorIndex(const PeerId &peer) { int peerColorIndex(const PeerId &peer) {
int32 myId(MTP::authedId()), peerId(peerToBareInt(peer)); UserId myId(MTP::authedId()), peerId(peerToBareInt(peer));
QByteArray both(qsl("%1%2").arg(peerId).arg(myId).toUtf8()); QByteArray both(qsl("%1%2").arg(peerId).arg(myId).toUtf8());
if (both.size() > 15) { if (both.size() > 15) {
both = both.mid(0, 15); both = both.mid(0, 15);
@ -47,7 +47,7 @@ namespace {
} }
} }
style::color peerColor(int32 index) { style::color peerColor(int index) {
static const style::color peerColors[8] = { static const style::color peerColors[8] = {
style::color(st::color1), style::color(st::color1),
style::color(st::color2), style::color(st::color2),
@ -61,7 +61,7 @@ style::color peerColor(int32 index) {
return peerColors[index]; return peerColors[index];
} }
ImagePtr userDefPhoto(int32 index) { ImagePtr userDefPhoto(int index) {
static const ImagePtr userDefPhotos[UserColorsCount] = { static const ImagePtr userDefPhotos[UserColorsCount] = {
ImagePtr(qsl(":/ava/art/usercolor1.png"), "PNG"), ImagePtr(qsl(":/ava/art/usercolor1.png"), "PNG"),
ImagePtr(qsl(":/ava/art/usercolor2.png"), "PNG"), ImagePtr(qsl(":/ava/art/usercolor2.png"), "PNG"),
@ -75,7 +75,7 @@ ImagePtr userDefPhoto(int32 index) {
return userDefPhotos[index]; return userDefPhotos[index];
} }
ImagePtr chatDefPhoto(int32 index) { ImagePtr chatDefPhoto(int index) {
static const ImagePtr chatDefPhotos[4] = { static const ImagePtr chatDefPhotos[4] = {
ImagePtr(qsl(":/ava/art/chatcolor1.png"), "PNG"), ImagePtr(qsl(":/ava/art/chatcolor1.png"), "PNG"),
ImagePtr(qsl(":/ava/art/chatcolor2.png"), "PNG"), ImagePtr(qsl(":/ava/art/chatcolor2.png"), "PNG"),
@ -85,7 +85,7 @@ ImagePtr chatDefPhoto(int32 index) {
return chatDefPhotos[index]; return chatDefPhotos[index];
} }
ImagePtr channelDefPhoto(int32 index) { ImagePtr channelDefPhoto(int index) {
static const ImagePtr channelDefPhotos[4] = { static const ImagePtr channelDefPhotos[4] = {
ImagePtr(qsl(":/ava/art/channelcolor1.png"), "PNG"), ImagePtr(qsl(":/ava/art/channelcolor1.png"), "PNG"),
ImagePtr(qsl(":/ava/art/channelcolor2.png"), "PNG"), ImagePtr(qsl(":/ava/art/channelcolor2.png"), "PNG"),
@ -100,7 +100,7 @@ NotifySettingsPtr globalNotifyAllPtr = UnknownNotifySettings, globalNotifyUsersP
PeerData::PeerData(const PeerId &id) : id(id) PeerData::PeerData(const PeerId &id) : id(id)
, lnk(new PeerLink(this)) , lnk(new PeerLink(this))
, loaded(false) , loadedStatus(NotLoaded)
, colorIndex(peerColorIndex(id)) , colorIndex(peerColorIndex(id))
, color(peerColor(colorIndex)) , color(peerColor(colorIndex))
, photoId(UnknownPeerPhotoId) , photoId(UnknownPeerPhotoId)
@ -279,7 +279,7 @@ void UserData::setPhone(const QString &newPhone) {
phone = newPhone; phone = newPhone;
} }
void UserData::setBotInfoVersion(int32 version) { void UserData::setBotInfoVersion(int version) {
if (version < 0) { if (version < 0) {
if (botInfo) { if (botInfo) {
if (!botInfo->commands.isEmpty()) { if (!botInfo->commands.isEmpty()) {
@ -850,7 +850,7 @@ QString documentSaveFilename(const DocumentData *data, bool forceSavingAs = fals
} else { } else {
filter = mimeType.filterString() + qsl(";;All files (*.*)"); filter = mimeType.filterString() + qsl(";;All files (*.*)");
} }
caption = lang(lng_save_file); caption = lang(data->song() ? lng_save_audio_file : lng_save_file);
prefix = qsl("doc"); prefix = qsl("doc");
} }

View File

@ -20,9 +20,21 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
typedef int32 UserId;
typedef int32 ChatId;
typedef int32 ChannelId; typedef int32 ChannelId;
static const ChannelId NoChannel = 0; static const ChannelId NoChannel = 0;
typedef int32 MsgId;
struct FullMsgId {
FullMsgId() : channel(NoChannel), msg(0) {
}
FullMsgId(ChannelId channel, MsgId msg) : channel(channel), msg(msg) {
}
ChannelId channel;
MsgId msg;
};
typedef uint64 PeerId; typedef uint64 PeerId;
static const uint64 PeerIdMask = 0xFFFFFFFFULL; static const uint64 PeerIdMask = 0xFFFFFFFFULL;
static const uint64 PeerIdTypeMask = 0x300000000ULL; static const uint64 PeerIdTypeMask = 0x300000000ULL;
@ -38,10 +50,10 @@ inline bool peerIsChat(const PeerId &id) {
inline bool peerIsChannel(const PeerId &id) { inline bool peerIsChannel(const PeerId &id) {
return (id & PeerIdTypeMask) == PeerIdChannelShift; return (id & PeerIdTypeMask) == PeerIdChannelShift;
} }
inline PeerId peerFromUser(int32 user_id) { inline PeerId peerFromUser(UserId user_id) {
return PeerIdUserShift | uint64(uint32(user_id)); return PeerIdUserShift | uint64(uint32(user_id));
} }
inline PeerId peerFromChat(int32 chat_id) { inline PeerId peerFromChat(ChatId chat_id) {
return PeerIdChatShift | uint64(uint32(chat_id)); return PeerIdChatShift | uint64(uint32(chat_id));
} }
inline PeerId peerFromChannel(ChannelId channel_id) { inline PeerId peerFromChannel(ChannelId channel_id) {
@ -59,10 +71,10 @@ inline PeerId peerFromChannel(const MTPint &channel_id) {
inline int32 peerToBareInt(const PeerId &id) { inline int32 peerToBareInt(const PeerId &id) {
return int32(uint32(id & PeerIdMask)); return int32(uint32(id & PeerIdMask));
} }
inline int32 peerToUser(const PeerId &id) { inline UserId peerToUser(const PeerId &id) {
return peerIsUser(id) ? peerToBareInt(id) : 0; return peerIsUser(id) ? peerToBareInt(id) : 0;
} }
inline int32 peerToChat(const PeerId &id) { inline ChatId peerToChat(const PeerId &id) {
return peerIsChat(id) ? peerToBareInt(id) : 0; return peerIsChat(id) ? peerToBareInt(id) : 0;
} }
inline ChannelId peerToChannel(const PeerId &id) { inline ChannelId peerToChannel(const PeerId &id) {
@ -112,7 +124,7 @@ inline MTPDmessage::Flags flagsFromMessage(const MTPmessage &msg) {
} }
return 0; return 0;
} }
inline int32 idFromMessage(const MTPmessage &msg) { inline MsgId idFromMessage(const MTPmessage &msg) {
switch (msg.type()) { switch (msg.type()) {
case mtpc_messageEmpty: return msg.c_messageEmpty().vid.v; case mtpc_messageEmpty: return msg.c_messageEmpty().vid.v;
case mtpc_message: return msg.c_message().vid.v; case mtpc_message: return msg.c_message().vid.v;
@ -120,7 +132,7 @@ inline int32 idFromMessage(const MTPmessage &msg) {
} }
return 0; return 0;
} }
inline int32 dateFromMessage(const MTPmessage &msg) { inline TimeId dateFromMessage(const MTPmessage &msg) {
switch (msg.type()) { switch (msg.type()) {
case mtpc_message: return msg.c_message().vdate.v; case mtpc_message: return msg.c_message().vdate.v;
case mtpc_messageService: return msg.c_messageService().vdate.v; case mtpc_messageService: return msg.c_messageService().vdate.v;
@ -135,15 +147,6 @@ typedef uint64 DocumentId;
typedef uint64 WebPageId; typedef uint64 WebPageId;
static const WebPageId CancelledWebPageId = 0xFFFFFFFFFFFFFFFFULL; static const WebPageId CancelledWebPageId = 0xFFFFFFFFFFFFFFFFULL;
typedef int32 MsgId;
struct FullMsgId {
FullMsgId() : channel(NoChannel), msg(0) {
}
FullMsgId(ChannelId channel, MsgId msg) : channel(channel), msg(msg) {
}
ChannelId channel;
MsgId msg;
};
inline bool operator==(const FullMsgId &a, const FullMsgId &b) { inline bool operator==(const FullMsgId &a, const FullMsgId &b) {
return (a.channel == b.channel) && (a.msg == b.msg); return (a.channel == b.channel) && (a.msg == b.msg);
} }
@ -168,7 +171,7 @@ struct NotifySettings {
NotifySettings() : flags(MTPDpeerNotifySettings::Flag::f_show_previews), mute(0), sound("default") { NotifySettings() : flags(MTPDpeerNotifySettings::Flag::f_show_previews), mute(0), sound("default") {
} }
MTPDpeerNotifySettings::Flags flags; MTPDpeerNotifySettings::Flags flags;
int32 mute; TimeId mute;
string sound; string sound;
bool previews() const { bool previews() const {
return flags & MTPDpeerNotifySettings::Flag::f_show_previews; return flags & MTPDpeerNotifySettings::Flag::f_show_previews;
@ -184,9 +187,9 @@ static const NotifySettingsPtr EmptyNotifySettings = NotifySettingsPtr(1);
extern NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats; extern NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats;
extern NotifySettingsPtr globalNotifyAllPtr, globalNotifyUsersPtr, globalNotifyChatsPtr; extern NotifySettingsPtr globalNotifyAllPtr, globalNotifyUsersPtr, globalNotifyChatsPtr;
inline bool isNotifyMuted(NotifySettingsPtr settings, int32 *changeIn = 0) { inline bool isNotifyMuted(NotifySettingsPtr settings, TimeId *changeIn = 0) {
if (settings != UnknownNotifySettings && settings != EmptyNotifySettings) { if (settings != UnknownNotifySettings && settings != EmptyNotifySettings) {
int32 t = unixtime(); TimeId t = unixtime();
if (settings->mute > t) { if (settings->mute > t) {
if (changeIn) *changeIn = settings->mute - t + 1; if (changeIn) *changeIn = settings->mute - t + 1;
return true; return true;
@ -196,12 +199,12 @@ inline bool isNotifyMuted(NotifySettingsPtr settings, int32 *changeIn = 0) {
return false; return false;
} }
static const int32 UserColorsCount = 8; static const int UserColorsCount = 8;
style::color peerColor(int32 index); style::color peerColor(int index);
ImagePtr userDefPhoto(int32 index); ImagePtr userDefPhoto(int index);
ImagePtr chatDefPhoto(int32 index); ImagePtr chatDefPhoto(int index);
ImagePtr channelDefPhoto(int32 index); ImagePtr channelDefPhoto(int index);
static const PhotoId UnknownPeerPhotoId = 0xFFFFFFFFFFFFFFFFULL; static const PhotoId UnknownPeerPhotoId = 0xFFFFFFFFFFFFFFFFULL;
@ -276,10 +279,15 @@ public:
typedef QSet<QChar> NameFirstChars; typedef QSet<QChar> NameFirstChars;
NameFirstChars chars; NameFirstChars chars;
bool loaded; enum LoadedStatus {
NotLoaded = 0x00,
MinimalLoaded = 0x01,
FullLoaded = 0x02,
};
LoadedStatus loadedStatus;
MTPinputPeer input; MTPinputPeer input;
int32 colorIndex; int colorIndex;
style::color color; style::color color;
void setUserpic(ImagePtr userpic); void setUserpic(ImagePtr userpic);
@ -297,7 +305,7 @@ public:
PhotoId photoId; PhotoId photoId;
StorageImageLocation photoLoc; StorageImageLocation photoLoc;
int32 nameVersion; int nameVersion;
NotifySettingsPtr notify; NotifySettingsPtr notify;
@ -358,7 +366,7 @@ struct BotInfo {
} }
bool inited; bool inited;
bool readsAllHistory, cantJoinGroups; bool readsAllHistory, cantJoinGroups;
int32 version; int version;
QString description, inlinePlaceholder; QString description, inlinePlaceholder;
QList<BotCommand> commands; QList<BotCommand> commands;
Text text; // description Text text; // description
@ -382,7 +390,7 @@ public:
void setPhoto(const MTPUserProfilePhoto &photo); void setPhoto(const MTPUserProfilePhoto &photo);
void setName(const QString &first, const QString &last, const QString &phoneName, const QString &username); void setName(const QString &first, const QString &last, const QString &phoneName, const QString &username);
void setPhone(const QString &newPhone); void setPhone(const QString &newPhone);
void setBotInfoVersion(int32 version); void setBotInfoVersion(int version);
void setBotInfo(const MTPBotInfo &info); void setBotInfo(const MTPBotInfo &info);
void setNameOrPhone(const QString &newNameOrPhone); void setNameOrPhone(const QString &newNameOrPhone);
@ -407,13 +415,13 @@ public:
QString phone; QString phone;
QString nameOrPhone; QString nameOrPhone;
Text phoneText; Text phoneText;
int32 onlineTill = 0; TimeId onlineTill = 0;
int32 contact = -1; // -1 - not contact, cant add (self, empty, deleted, foreign), 0 - not contact, can add (request), 1 - contact int32 contact = -1; // -1 - not contact, cant add (self, empty, deleted, foreign), 0 - not contact, can add (request), 1 - contact
UserBlockedStatus blocked = UserBlockUnknown; UserBlockedStatus blocked = UserBlockUnknown;
typedef QList<PhotoData*> Photos; typedef QList<PhotoData*> Photos;
Photos photos; Photos photos;
int32 photosCount = -1; // -1 not loaded, 0 all loaded int photosCount = -1; // -1 not loaded, 0 all loaded
QString about; QString about;
@ -462,10 +470,10 @@ public:
ChannelData *migrateToPtr; ChannelData *migrateToPtr;
int32 count; int count;
int32 date; TimeId date;
int32 version; int version;
int32 creator; UserId creator;
MTPDchat::Flags flags; MTPDchat::Flags flags;
bool isForbidden; bool isForbidden;
@ -499,7 +507,7 @@ public:
bool isMigrated() const { bool isMigrated() const {
return flags & MTPDchat::Flag::f_migrated_to; return flags & MTPDchat::Flag::f_migrated_to;
} }
typedef QMap<UserData*, int32> Participants; typedef QMap<UserData*, int> Participants;
Participants participants; Participants participants;
typedef OrderedSet<UserData*> InvitedByMe; typedef OrderedSet<UserData*> InvitedByMe;
InvitedByMe invitedByMe; InvitedByMe invitedByMe;
@ -753,29 +761,59 @@ private:
}; };
inline bool isUser(const PeerData *peer) {
return peer ? peer->isUser() : false;
}
inline UserData *PeerData::asUser() { inline UserData *PeerData::asUser() {
return isUser() ? static_cast<UserData*>(this) : 0; return isUser() ? static_cast<UserData*>(this) : nullptr;
}
inline UserData *asUser(PeerData *peer) {
return peer ? peer->asUser() : nullptr;
} }
inline const UserData *PeerData::asUser() const { inline const UserData *PeerData::asUser() const {
return isUser() ? static_cast<const UserData*>(this) : 0; return isUser() ? static_cast<const UserData*>(this) : nullptr;
}
inline const UserData *asUser(const PeerData *peer) {
return peer ? peer->asUser() : nullptr;
}
inline bool isChat(const PeerData *peer) {
return peer ? peer->isChat() : false;
} }
inline ChatData *PeerData::asChat() { inline ChatData *PeerData::asChat() {
return isChat() ? static_cast<ChatData*>(this) : 0; return isChat() ? static_cast<ChatData*>(this) : nullptr;
}
inline ChatData *asChat(PeerData *peer) {
return peer ? peer->asChat() : nullptr;
} }
inline const ChatData *PeerData::asChat() const { inline const ChatData *PeerData::asChat() const {
return isChat() ? static_cast<const ChatData*>(this) : 0; return isChat() ? static_cast<const ChatData*>(this) : nullptr;
}
inline const ChatData *asChat(const PeerData *peer) {
return peer ? peer->asChat() : nullptr;
}
inline bool isChannel(const PeerData *peer) {
return peer ? peer->isChannel() : false;
} }
inline ChannelData *PeerData::asChannel() { inline ChannelData *PeerData::asChannel() {
return isChannel() ? static_cast<ChannelData*>(this) : 0; return isChannel() ? static_cast<ChannelData*>(this) : nullptr;
}
inline ChannelData *asChannel(PeerData *peer) {
return peer ? peer->asChannel() : nullptr;
} }
inline const ChannelData *PeerData::asChannel() const { inline const ChannelData *PeerData::asChannel() const {
return isChannel() ? static_cast<const ChannelData*>(this) : 0; return isChannel() ? static_cast<const ChannelData*>(this) : nullptr;
}
inline const ChannelData *asChannel(const PeerData *peer) {
return peer ? peer->asChannel() : nullptr;
}
inline bool isMegagroup(const PeerData *peer) {
return peer ? peer->isMegagroup() : false;
} }
inline ChatData *PeerData::migrateFrom() const { inline ChatData *PeerData::migrateFrom() const {
return (isMegagroup() && asChannel()->amIn()) ? asChannel()->mgInfo->migrateFromPtr : 0; return (isMegagroup() && asChannel()->amIn()) ? asChannel()->mgInfo->migrateFromPtr : nullptr;
} }
inline ChannelData *PeerData::migrateTo() const { inline ChannelData *PeerData::migrateTo() const {
return (isChat() && asChat()->migrateToPtr && asChat()->migrateToPtr->amIn()) ? asChat()->migrateToPtr : 0; return (isChat() && asChat()->migrateToPtr && asChat()->migrateToPtr->amIn()) ? asChat()->migrateToPtr : nullptr;
} }
inline const Text &PeerData::dialogName() const { inline const Text &PeerData::dialogName() const {
return migrateTo() ? migrateTo()->dialogName() : ((isUser() && !asUser()->phoneText.isEmpty()) ? asUser()->phoneText : nameText); return migrateTo() ? migrateTo()->dialogName() : ((isUser() && !asUser()->phoneText.isEmpty()) ? asUser()->phoneText : nameText);
@ -998,11 +1036,14 @@ public:
SongData *song() { SongData *song() {
return (type == SongDocument) ? static_cast<SongData*>(_additional) : 0; return (type == SongDocument) ? static_cast<SongData*>(_additional) : 0;
} }
const SongData *song() const {
return (type == SongDocument) ? static_cast<const SongData*>(_additional) : 0;
}
VoiceData *voice() { VoiceData *voice() {
return (type == VoiceDocument) ? static_cast<VoiceData*>(_additional) : 0; return (type == VoiceDocument) ? static_cast<VoiceData*>(_additional) : 0;
} }
const VoiceData *voice() const { const VoiceData *voice() const {
return (type == VoiceDocument) ? static_cast<VoiceData*>(_additional) : 0; return (type == VoiceDocument) ? static_cast<const VoiceData*>(_additional) : 0;
} }
bool isAnimation() const { bool isAnimation() const {
return (type == AnimatedDocument) || !mime.compare(qstr("image/gif"), Qt::CaseInsensitive); return (type == AnimatedDocument) || !mime.compare(qstr("image/gif"), Qt::CaseInsensitive);

View File

@ -120,8 +120,8 @@ namespace {
} }
} }
int32 myunixtime() { TimeId myunixtime() {
return (int32)time(NULL); return (TimeId)time(NULL);
} }
void unixtimeInit() { void unixtimeInit() {
@ -149,19 +149,19 @@ void unixtimeSet(int32 serverTime, bool force) {
_initMsgIdConstants(); _initMsgIdConstants();
} }
int32 unixtime() { TimeId unixtime() {
int32 result = myunixtime(); TimeId result = myunixtime();
QReadLocker locker(&unixtimeLock); QReadLocker locker(&unixtimeLock);
return result + unixtimeDelta; return result + unixtimeDelta;
} }
int32 fromServerTime(const MTPint &serverTime) { TimeId fromServerTime(const MTPint &serverTime) {
QReadLocker locker(&unixtimeLock); QReadLocker locker(&unixtimeLock);
return serverTime.v - unixtimeDelta; return serverTime.v - unixtimeDelta;
} }
MTPint toServerTime(const int32 &clientTime) { MTPint toServerTime(const TimeId &clientTime) {
QReadLocker locker(&unixtimeLock); QReadLocker locker(&unixtimeLock);
return MTP_int(clientTime + unixtimeDelta); return MTP_int(clientTime + unixtimeDelta);
} }
@ -1034,35 +1034,32 @@ MimeType mimeTypeForData(const QByteArray &data) {
return MimeType(QMimeDatabase().mimeTypeForData(data)); return MimeType(QMimeDatabase().mimeTypeForData(data));
} }
class InterfacesMetadatasMap : public QMap<uint64, InterfacesMetadata*> { struct ComposerMetadatasMap {
public: QMap<uint64, ComposerMetadata*> data;
~InterfacesMetadatasMap() { ~ComposerMetadatasMap() {
for (const_iterator i = cbegin(), e = cend(); i != e; ++i) { for_const (const ComposerMetadata *p, data) {
delete i.value(); delete p;
} }
} }
}; };
const InterfacesMetadata *GetInterfacesMetadata(uint64 mask) { const ComposerMetadata *GetComposerMetadata(uint64 mask) {
typedef QMap<uint64, InterfacesMetadata*> InterfacesMetadatasMap; static ComposerMetadatasMap ComposerMetadatas;
static InterfacesMetadatasMap InterfacesMetadatas; static QMutex ComposerMetadatasMutex;
static QMutex InterfacesMetadatasMutex;
QMutexLocker lock(&InterfacesMetadatasMutex); QMutexLocker lock(&ComposerMetadatasMutex);
InterfacesMetadatasMap::const_iterator i = InterfacesMetadatas.constFind(mask); auto i = ComposerMetadatas.data.constFind(mask);
if (i == InterfacesMetadatas.cend()) { if (i == ComposerMetadatas.data.cend()) {
InterfacesMetadata *meta = new InterfacesMetadata(mask); ComposerMetadata *meta = new ComposerMetadata(mask);
if (!meta) { // terminate if we can't allocate memory t_assert(meta != nullptr);
throw "Can't allocate memory!";
}
i = InterfacesMetadatas.insert(mask, meta); i = ComposerMetadatas.data.insert(mask, meta);
} }
return i.value(); return i.value();
} }
const InterfacesMetadata *Interfaces::ZeroInterfacesMetadata = GetInterfacesMetadata(0); const ComposerMetadata *Composer::ZeroComposerMetadata = GetComposerMetadata(0);
InterfaceWrapStruct InterfaceWraps[64]; ComponentWrapStruct ComponentWraps[64];
QAtomicInt InterfaceIndexLast(0); QAtomicInt ComponentIndexLast;

View File

@ -104,6 +104,30 @@ using std::string;
using std::exception; using std::exception;
using std::swap; using std::swap;
// we copy some parts of C++11 std:: library, because on OS X 10.6+
// version we can use C++11, but we can't use its library :(
namespace std11 {
template <typename T>
struct remove_reference {
typedef T type;
};
template <typename T>
struct remove_reference<T&> {
typedef T type;
};
template <typename T>
struct remove_reference<T&&> {
typedef T type;
};
template <typename T>
inline typename remove_reference<T>::type &&move(T &&value) {
return static_cast<typename remove_reference<T>::type&&>(value);
}
} // namespace std11
#include "logs.h" #include "logs.h"
static volatile int *t_assert_nullptr = 0; static volatile int *t_assert_nullptr = 0;
@ -140,12 +164,12 @@ private:
}; };
class MTPint; class MTPint;
typedef int32 TimeId;
int32 myunixtime(); TimeId myunixtime();
void unixtimeInit(); void unixtimeInit();
void unixtimeSet(int32 servertime, bool force = false); void unixtimeSet(TimeId servertime, bool force = false);
int32 unixtime(); TimeId unixtime();
int32 fromServerTime(const MTPint &serverTime); TimeId fromServerTime(const MTPint &serverTime);
uint64 msgid(); uint64 msgid();
int32 reqid(); int32 reqid();
@ -541,24 +565,26 @@ inline void destroyImplementation(I *&ptr) {
deleteAndMark(ptr); deleteAndMark(ptr);
} }
class Interfaces; class Composer;
typedef void(*InterfaceConstruct)(void *location, Interfaces *interfaces); typedef void(*ComponentConstruct)(void *location, Composer *composer);
typedef void(*InterfaceDestruct)(void *location); typedef void(*ComponentDestruct)(void *location);
typedef void(*InterfaceMove)(void *location, void *waslocation); typedef void(*ComponentMove)(void *location, void *waslocation);
struct InterfaceWrapStruct { struct ComponentWrapStruct {
InterfaceWrapStruct() : Size(0), Construct(0), Destruct(0) { // don't init any fields, because it is only created in
// global scope, so it will be filled by zeros from the start
ComponentWrapStruct() {
} }
InterfaceWrapStruct(int size, InterfaceConstruct construct, InterfaceDestruct destruct, InterfaceMove move) ComponentWrapStruct(int size, ComponentConstruct construct, ComponentDestruct destruct, ComponentMove move)
: Size(size) : Size(size)
, Construct(construct) , Construct(construct)
, Destruct(destruct) , Destruct(destruct)
, Move(move) { , Move(move) {
} }
int Size; int Size;
InterfaceConstruct Construct; ComponentConstruct Construct;
InterfaceDestruct Destruct; ComponentDestruct Destruct;
InterfaceMove Move; ComponentMove Move;
}; };
template <int Value, int Denominator> template <int Value, int Denominator>
@ -567,36 +593,43 @@ struct CeilDivideMinimumOne {
}; };
template <typename Type> template <typename Type>
struct InterfaceWrapTemplate { struct ComponentWrapTemplate {
static const int Size = CeilDivideMinimumOne<sizeof(Type), sizeof(uint64)>::Result * sizeof(uint64); static const int Size = CeilDivideMinimumOne<sizeof(Type), sizeof(uint64)>::Result * sizeof(uint64);
static void Construct(void *location, Interfaces *interfaces) { static void Construct(void *location, Composer *composer) {
new (location) Type(interfaces); new (location) Type(composer);
} }
static void Destruct(void *location) { static void Destruct(void *location) {
((Type*)location)->~Type(); ((Type*)location)->~Type();
} }
static void Move(void *location, void *waslocation) { static void Move(void *location, void *waslocation) {
*(Type*)location = *(Type*)waslocation; *(Type*)location = std11::move(*(Type*)waslocation);
} }
}; };
extern InterfaceWrapStruct InterfaceWraps[64]; extern ComponentWrapStruct ComponentWraps[64];
extern QAtomicInt InterfaceIndexLast; extern QAtomicInt ComponentIndexLast;
template <typename Type> template <typename Type>
class BasicInterface { class BaseComponent {
public: public:
BaseComponent() {
}
BaseComponent(const BaseComponent &other) = delete;
BaseComponent &operator=(const BaseComponent &other) = delete;
BaseComponent(BaseComponent &&other) = delete;
BaseComponent &operator=(BaseComponent &&other) = default;
static int Index() { static int Index() {
static QAtomicInt _index(0); static QAtomicInt _index(0);
if (int index = _index.loadAcquire()) { if (int index = _index.loadAcquire()) {
return index - 1; return index - 1;
} }
while (true) { while (true) {
int last = InterfaceIndexLast.loadAcquire(); int last = ComponentIndexLast.loadAcquire();
if (InterfaceIndexLast.testAndSetOrdered(last, last + 1)) { if (ComponentIndexLast.testAndSetOrdered(last, last + 1)) {
t_assert(last < 64); t_assert(last < 64);
if (_index.testAndSetOrdered(0, last + 1)) { if (_index.testAndSetOrdered(0, last + 1)) {
InterfaceWraps[last] = InterfaceWrapStruct(InterfaceWrapTemplate<Type>::Size, InterfaceWrapTemplate<Type>::Construct, InterfaceWrapTemplate<Type>::Destruct, InterfaceWrapTemplate<Type>::Move); ComponentWraps[last] = ComponentWrapStruct(ComponentWrapTemplate<Type>::Size, ComponentWrapTemplate<Type>::Construct, ComponentWrapTemplate<Type>::Destruct, ComponentWrapTemplate<Type>::Move);
} }
break; break;
} }
@ -609,22 +642,14 @@ public:
}; };
template <typename Type> class ComposerMetadata {
class BasicInterfaceWithPointer : public BasicInterface<Type> {
public:
BasicInterfaceWithPointer(Interfaces *interfaces) : interfaces(interfaces) {
}
Interfaces *interfaces = 0;
};
class InterfacesMetadata {
public: public:
InterfacesMetadata(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 = (1 << i); uint64 m = (1 << i);
if (_mask & m) { if (_mask & m) {
int s = InterfaceWraps[i].Size; int s = ComponentWraps[i].Size;
if (s) { if (s) {
offsets[i] = size; offsets[i] = size;
size += s; size += s;
@ -660,15 +685,15 @@ private:
}; };
const InterfacesMetadata *GetInterfacesMetadata(uint64 mask); const ComposerMetadata *GetComposerMetadata(uint64 mask);
class Interfaces { class Composer {
public: public:
Interfaces(uint64 mask = 0) : _data(zerodata()) { Composer(uint64 mask = 0) : _data(zerodata()) {
if (mask) { if (mask) {
const InterfacesMetadata *meta = GetInterfacesMetadata(mask); const ComposerMetadata *meta = GetComposerMetadata(mask);
int32 size = sizeof(const InterfacesMetadata *) + meta->size; int size = sizeof(meta) + meta->size;
void *data = operator new(size); void *data = operator new(size);
if (!data) { // terminate if we can't allocate memory if (!data) { // terminate if we can't allocate memory
throw "Can't allocate memory!"; throw "Can't allocate memory!";
@ -680,13 +705,13 @@ public:
int offset = meta->offsets[i]; int offset = meta->offsets[i];
if (offset >= 0) { if (offset >= 0) {
try { try {
InterfaceWraps[i].Construct(_dataptrunsafe(offset), this); ComponentWraps[i].Construct(_dataptrunsafe(offset), this);
} catch (...) { } catch (...) {
while (i > 0) { while (i > 0) {
--i; --i;
offset = meta->offsets[--i]; offset = meta->offsets[--i];
if (offset >= 0) { if (offset >= 0) {
InterfaceWraps[i].Destruct(_dataptrunsafe(offset)); ComponentWraps[i].Destruct(_dataptrunsafe(offset));
} }
} }
throw; throw;
@ -695,38 +720,41 @@ public:
} }
} }
} }
void UpdateInterfaces(uint64 mask = 0) { Composer(const Composer &other) = delete;
Composer &operator=(const Composer &other) = delete;
~Composer() {
if (_data != zerodata()) {
const ComposerMetadata *meta = _meta();
for (int i = 0; i < meta->last; ++i) {
int offset = meta->offsets[i];
if (offset >= 0) {
ComponentWraps[i].Destruct(_dataptrunsafe(offset));
}
}
operator delete(_data);
}
}
void UpdateComponents(uint64 mask = 0) {
if (!_meta()->equals(mask)) { if (!_meta()->equals(mask)) {
Interfaces tmp(mask); Composer tmp(mask);
tmp.swap(*this); tmp.swap(*this);
if (_data != zerodata() && tmp._data != zerodata()) { if (_data != zerodata() && tmp._data != zerodata()) {
const InterfacesMetadata *meta = _meta(), *wasmeta = tmp._meta(); const ComposerMetadata *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) {
InterfaceWraps[i].Move(_dataptrunsafe(offset), tmp._dataptrunsafe(wasoffset)); ComponentWraps[i].Move(_dataptrunsafe(offset), tmp._dataptrunsafe(wasoffset));
} }
} }
} }
} }
} }
void AddInterfaces(uint64 mask = 0) { void AddComponents(uint64 mask = 0) {
UpdateInterfaces(_meta()->maskadd(mask)); UpdateComponents(_meta()->maskadd(mask));
} }
void RemoveInterfaces(uint64 mask = 0) { void RemoveComponents(uint64 mask = 0) {
UpdateInterfaces(_meta()->maskremove(mask)); UpdateComponents(_meta()->maskremove(mask));
}
~Interfaces() {
if (_data != zerodata()) {
const InterfacesMetadata *meta = _meta();
for (int i = 0; i < meta->last; ++i) {
int offset = meta->offsets[i];
if (offset >= 0) {
InterfaceWraps[i].Destruct(_dataptrunsafe(offset));
}
}
operator delete(_data);
}
} }
template <typename Type> template <typename Type>
@ -738,31 +766,28 @@ public:
return static_cast<const Type*>(_dataptr(_meta()->offsets[Type::Index()])); return static_cast<const Type*>(_dataptr(_meta()->offsets[Type::Index()]));
} }
template <typename Type> template <typename Type>
bool Is() const { bool Has() const {
return (_meta()->offsets[Type::Index()] >= 0); return (_meta()->offsets[Type::Index()] >= 0);
} }
private: private:
static const InterfacesMetadata *ZeroInterfacesMetadata; static const ComposerMetadata *ZeroComposerMetadata;
static void *zerodata() { static void *zerodata() {
return &ZeroInterfacesMetadata; return &ZeroComposerMetadata;
} }
void *_dataptrunsafe(int skip) const { void *_dataptrunsafe(int skip) const {
return (char*)_data + sizeof(const InterfacesMetadata*) + skip; return (char*)_data + sizeof(_meta()) + skip;
} }
void *_dataptr(int skip) const { void *_dataptr(int skip) const {
return (skip >= 0) ? _dataptrunsafe(skip) : 0; return (skip >= 0) ? _dataptrunsafe(skip) : 0;
} }
const InterfacesMetadata *&_meta() const { const ComposerMetadata *&_meta() const {
return *static_cast<const InterfacesMetadata**>(_data); return *static_cast<const ComposerMetadata**>(_data);
} }
void *_data; void *_data;
Interfaces(const Interfaces &other); void swap(Composer &other) {
Interfaces &operator=(const Interfaces &other);
void swap(Interfaces &other) {
std::swap(_data, other._data); std::swap(_data, other._data);
} }

View File

@ -1410,7 +1410,7 @@ void Window::notifySchedule(History *history, HistoryItem *item) {
haveSetting = false; haveSetting = false;
} }
int delay = item->Is<HistoryMessageForwarded>() ? 500 : 100, t = unixtime(); int delay = item->Has<HistoryMessageForwarded>() ? 500 : 100, t = unixtime();
uint64 ms = getms(true); uint64 ms = getms(true);
bool isOnline = main->lastWasOnline(), otherNotOld = ((cOtherOnline() * uint64(1000)) + Global::OnlineCloudTimeout() > t * uint64(1000)); bool isOnline = main->lastWasOnline(), otherNotOld = ((cOtherOnline() * uint64(1000)) + Global::OnlineCloudTimeout() > t * uint64(1000));
bool otherLaterThanMe = (cOtherOnline() * uint64(1000) + (ms - main->lastSetOnline()) > t * uint64(1000)); bool otherLaterThanMe = (cOtherOnline() * uint64(1000) + (ms - main->lastSetOnline()) > t * uint64(1000));
@ -1629,7 +1629,7 @@ void Window::notifyShowNext(NotifyWindow *remove) {
notifyWaitTimer.start(next - ms); notifyWaitTimer.start(next - ms);
break; break;
} else { } else {
HistoryItem *fwd = notifyItem->Is<HistoryMessageForwarded>() ? notifyItem : 0; // forwarded notify grouping HistoryItem *fwd = notifyItem->Has<HistoryMessageForwarded>() ? notifyItem : nullptr; // forwarded notify grouping
int32 fwdCount = 1; int32 fwdCount = 1;
uint64 ms = getms(true); uint64 ms = getms(true);
@ -1657,7 +1657,7 @@ void Window::notifyShowNext(NotifyWindow *remove) {
} while (history->hasNotification()); } while (history->hasNotification());
if (nextNotify) { if (nextNotify) {
if (fwd) { if (fwd) {
HistoryItem *nextFwd = nextNotify->Is<HistoryMessageForwarded>() ? nextNotify : 0; HistoryItem *nextFwd = nextNotify->Has<HistoryMessageForwarded>() ? nextNotify : nullptr;
if (nextFwd && fwd->author() == nextFwd->author() && qAbs(int64(nextFwd->date.toTime_t()) - int64(fwd->date.toTime_t())) < 2) { if (nextFwd && fwd->author() == nextFwd->author() && qAbs(int64(nextFwd->date.toTime_t()) - int64(fwd->date.toTime_t())) < 2) {
fwd = nextFwd; fwd = nextFwd;
++fwdCount; ++fwdCount;

View File

@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,9,34,3 FILEVERSION 0,9,34,4
PRODUCTVERSION 0,9,34,3 PRODUCTVERSION 0,9,34,4
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.9.34.3" VALUE "FileVersion", "0.9.34.4"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.9.34.3" VALUE "ProductVersion", "0.9.34.4"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -3,4 +3,4 @@ AppVersionStrMajor 0.9
AppVersionStrSmall 0.9.34 AppVersionStrSmall 0.9.34
AppVersionStr 0.9.34 AppVersionStr 0.9.34
DevChannel 0 DevChannel 0
BetaVersion 9034003 BetaVersion 9034004