mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-20 06:21:00 +00:00
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:
parent
a299c1f9e8
commit
599ede9a0b
@ -663,9 +663,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
"lng_stickers_count" = "{count:Loading...|# sticker|# stickers}";
|
||||
|
||||
"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_audio" = "Audio";
|
||||
"lng_in_dlg_audio" = "Voice message";
|
||||
"lng_in_dlg_file" = "File";
|
||||
"lng_in_dlg_sticker" = "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_users_typing" = "{user} and {second_user} 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_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_send_action_record_audio" = "recording audio";
|
||||
"lng_user_action_record_audio" = "{user} is recording an audio";
|
||||
"lng_send_action_upload_audio" = "sending audio";
|
||||
"lng_user_action_upload_audio" = "{user} is sending an audio";
|
||||
"lng_send_action_upload_photo" = "sending photo";
|
||||
"lng_send_action_record_audio" = "recording a voice message";
|
||||
"lng_user_action_record_audio" = "{user} is recording a voice message";
|
||||
"lng_send_action_upload_audio" = "sending a voice message";
|
||||
"lng_user_action_upload_audio" = "{user} is sending a voice message";
|
||||
"lng_send_action_upload_photo" = "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_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_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_unread_bar" = "{count:_not_used_|# unread message|# unread messages}";
|
||||
|
||||
"lng_maps_point" = "Location";
|
||||
"lng_save_photo" = "Save image";
|
||||
"lng_save_video" = "Save video";
|
||||
"lng_save_audio" = "Save audio";
|
||||
"lng_save_video" = "Save video file";
|
||||
"lng_save_audio_file" = "Save audio file";
|
||||
"lng_save_audio" = "Save voice message";
|
||||
"lng_save_file" = "Save file";
|
||||
"lng_save_downloaded" = "{ready} / {total} {mb}";
|
||||
"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_show_in_folder" = "Show in Folder";
|
||||
"lng_context_show_in_finder" = "Show in Finder";
|
||||
"lng_context_save_video" = "Save Video As...";
|
||||
"lng_context_save_audio" = "Save Audio As...";
|
||||
"lng_context_save_video" = "Save Video File 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_add" = "Add Stickers";
|
||||
"lng_context_save_file" = "Save File As...";
|
||||
|
@ -478,7 +478,13 @@ namespace App {
|
||||
|
||||
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()) {
|
||||
case mtpc_userStatusEmpty: data->onlineTill = 0; break;
|
||||
case mtpc_userStatusRecently:
|
||||
@ -655,7 +661,13 @@ namespace App {
|
||||
}
|
||||
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 (emitPeerUpdated) {
|
||||
App::main()->peerUpdated(data);
|
||||
@ -1000,7 +1012,7 @@ namespace App {
|
||||
}
|
||||
|
||||
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 (DocumentData *doc = media->getDocument()) {
|
||||
if (doc->isGifv()) {
|
||||
@ -1394,41 +1406,16 @@ namespace App {
|
||||
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() {
|
||||
return user(MTP::authedId());
|
||||
}
|
||||
|
||||
PeerData *peer(const PeerId &id) {
|
||||
PeersData::const_iterator i = peersData.constFind(id);
|
||||
PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) {
|
||||
if (!id) return nullptr;
|
||||
|
||||
auto i = peersData.constFind(id);
|
||||
if (i == peersData.cend()) {
|
||||
PeerData *newData = 0;
|
||||
PeerData *newData = nullptr;
|
||||
if (peerIsUser(id)) {
|
||||
newData = new UserData(id);
|
||||
} else if (peerIsChat(id)) {
|
||||
@ -1436,33 +1423,26 @@ namespace App {
|
||||
} else if (peerIsChannel(id)) {
|
||||
newData = new ChannelData(id);
|
||||
}
|
||||
if (!newData) return 0;
|
||||
t_assert(newData != nullptr);
|
||||
|
||||
newData->input = MTPinputPeer(MTP_inputPeerEmpty());
|
||||
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();
|
||||
}
|
||||
|
||||
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() {
|
||||
return ::self;
|
||||
}
|
||||
|
@ -110,21 +110,47 @@ namespace App {
|
||||
WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = 0);
|
||||
WebPageData *feedWebPage(const MTPWebPage &webpage);
|
||||
|
||||
PeerData *peerLoaded(const PeerId &id);
|
||||
UserData *userLoaded(const PeerId &id);
|
||||
ChatData *chatLoaded(const PeerId &id);
|
||||
ChannelData *channelLoaded(const PeerId &id);
|
||||
UserData *userLoaded(int32 user);
|
||||
ChatData *chatLoaded(int32 chat);
|
||||
ChannelData *channelLoaded(int32 channel);
|
||||
PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded);
|
||||
inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
|
||||
return asUser(peer(id, restriction));
|
||||
}
|
||||
inline ChatData *chat(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
|
||||
return asChat(peer(id, restriction));
|
||||
}
|
||||
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();
|
||||
PeerData *peerByName(const QString &username);
|
||||
QString peerName(const PeerData *peer, bool forDialogs = false);
|
||||
|
@ -224,18 +224,15 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) {
|
||||
App::feedUsers(d.vusers);
|
||||
|
||||
const QVector<MTPImportedContact> &v(d.vimported.c_vector().v);
|
||||
int32 uid = 0;
|
||||
UserData *user = nullptr;
|
||||
if (!v.isEmpty()) {
|
||||
const MTPDimportedContact &c(v.front().c_importedContact());
|
||||
if (c.vclient_id.v != _contactId) return;
|
||||
|
||||
uid = c.vuser_id.v;
|
||||
if (uid && !App::userLoaded(uid)) {
|
||||
uid = 0;
|
||||
}
|
||||
user = App::userLoaded(c.vuser_id.v);
|
||||
}
|
||||
if (uid) {
|
||||
Notify::userIsContactChanged(App::userLoaded(peerFromUser(uid)), true);
|
||||
if (user) {
|
||||
Notify::userIsContactChanged(user, true);
|
||||
Ui::hideLayer();
|
||||
} else {
|
||||
_save.hide();
|
||||
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
static const int32 AppVersion = 9034;
|
||||
static const wchar_t *AppVersionStr = L"0.9.34";
|
||||
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 *AppName = L"Telegram Desktop";
|
||||
|
@ -2534,20 +2534,32 @@ Text::Text(style::font font, const QString &text, const TextParseOptions &option
|
||||
}
|
||||
}
|
||||
|
||||
Text::Text(const Text &other) :
|
||||
_minResizeWidth(other._minResizeWidth), _maxWidth(other._maxWidth),
|
||||
_minHeight(other._minHeight),
|
||||
_text(other._text),
|
||||
_font(other._font),
|
||||
_blocks(other._blocks.size()),
|
||||
_links(other._links),
|
||||
_startDir(other._startDir)
|
||||
{
|
||||
Text::Text(const Text &other)
|
||||
: _minResizeWidth(other._minResizeWidth)
|
||||
, _maxWidth(other._maxWidth)
|
||||
, _minHeight(other._minHeight)
|
||||
, _text(other._text)
|
||||
, _font(other._font)
|
||||
, _blocks(other._blocks.size())
|
||||
, _links(other._links)
|
||||
, _startDir(other._startDir) {
|
||||
for (int32 i = 0, l = _blocks.size(); i < l; ++i) {
|
||||
_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) {
|
||||
_minResizeWidth = other._minResizeWidth;
|
||||
_maxWidth = other._maxWidth;
|
||||
@ -2563,10 +2575,23 @@ Text &Text::operator=(const Text &other) {
|
||||
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) {
|
||||
if (!_textStyle) _initDefault();
|
||||
_font = font;
|
||||
clean();
|
||||
clear();
|
||||
{
|
||||
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) {
|
||||
if (!_textStyle) _initDefault();
|
||||
_font = font;
|
||||
clean();
|
||||
clear();
|
||||
{
|
||||
// QString newText; // utf16 of the text for emoji
|
||||
// newText.reserve(8 * text.size());
|
||||
@ -3216,10 +3241,14 @@ EntitiesInText Text::originalEntities() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
void Text::clean() {
|
||||
void Text::clear() {
|
||||
for (TextBlocks::iterator i = _blocks.begin(), e = _blocks.end(); i != e; ++i) {
|
||||
delete *i;
|
||||
}
|
||||
clearFields();
|
||||
}
|
||||
|
||||
void Text::clearFields() {
|
||||
_blocks.clear();
|
||||
_links.clear();
|
||||
_maxWidth = _minHeight = 0;
|
||||
|
@ -598,7 +598,9 @@ public:
|
||||
Text(int32 minResizeWidth = QFIXED_MAX);
|
||||
Text(style::font font, const QString &text, const TextParseOptions &options = _defaultOptions, int32 minResizeWidth = QFIXED_MAX, bool richText = false);
|
||||
Text(const Text &other);
|
||||
Text(Text &&other);
|
||||
Text &operator=(const Text &other);
|
||||
Text &operator=(Text &&other);
|
||||
|
||||
int32 countWidth(int32 width) const;
|
||||
int32 countHeight(int32 width) const;
|
||||
@ -686,15 +688,19 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
void clean();
|
||||
void clear();
|
||||
~Text() {
|
||||
clean();
|
||||
clear();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
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;
|
||||
int32 _minHeight;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -936,7 +936,6 @@ protected:
|
||||
|
||||
};
|
||||
|
||||
class HistoryReply; // dynamic_cast optimize
|
||||
class HistoryMessage; // dynamic_cast optimize
|
||||
|
||||
enum HistoryCursorState {
|
||||
@ -962,43 +961,104 @@ enum HistoryItemType {
|
||||
HistoryItemJoined
|
||||
};
|
||||
|
||||
struct HistoryMessageVia : public BasicInterface<HistoryMessageVia> {
|
||||
HistoryMessageVia(Interfaces *);
|
||||
struct HistoryMessageVia : public BaseComponent<HistoryMessageVia> {
|
||||
HistoryMessageVia(Composer*) {
|
||||
}
|
||||
void create(int32 userId);
|
||||
void resize(int32 availw) const;
|
||||
|
||||
UserData *_bot;
|
||||
UserData *_bot = nullptr;
|
||||
mutable QString _text;
|
||||
mutable int32 _width, _maxWidth;
|
||||
mutable int _width = 0;
|
||||
mutable int _maxWidth = 0;
|
||||
TextLinkPtr _lnk;
|
||||
};
|
||||
|
||||
struct HistoryMessageViews : public BasicInterface<HistoryMessageViews> {
|
||||
HistoryMessageViews(Interfaces *);
|
||||
struct HistoryMessageViews : public BaseComponent<HistoryMessageViews> {
|
||||
HistoryMessageViews(Composer*) {
|
||||
}
|
||||
|
||||
QString _viewsText;
|
||||
int32 _views, _viewsWidth;
|
||||
int _views = 0;
|
||||
int _viewsWidth = 0;
|
||||
};
|
||||
|
||||
struct HistoryMessageSigned : public BasicInterface<HistoryMessageSigned> {
|
||||
HistoryMessageSigned(Interfaces *);
|
||||
struct HistoryMessageSigned : public BaseComponent<HistoryMessageSigned> {
|
||||
HistoryMessageSigned(Composer*) {
|
||||
}
|
||||
|
||||
void create(UserData *from, const QDateTime &date);
|
||||
int32 maxWidth() const;
|
||||
int maxWidth() const;
|
||||
|
||||
Text _signature;
|
||||
};
|
||||
|
||||
struct HistoryMessageForwarded : public BasicInterface<HistoryMessageForwarded> {
|
||||
HistoryMessageForwarded(Interfaces *);
|
||||
struct HistoryMessageForwarded : public BaseComponent<HistoryMessageForwarded> {
|
||||
HistoryMessageForwarded(Composer*) {
|
||||
}
|
||||
void create(const HistoryMessageVia *via) const;
|
||||
bool display(bool hasVia) const;
|
||||
|
||||
PeerData *_authorOriginal, *_fromOriginal;
|
||||
MsgId _originalId;
|
||||
mutable Text _text;
|
||||
PeerData *_authorOriginal = nullptr;
|
||||
PeerData *_fromOriginal = nullptr;
|
||||
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> {
|
||||
public:
|
||||
HistoryDependentItemCallback(FullMsgId dependent) : _dependent(dependent) {
|
||||
@ -1012,28 +1072,30 @@ private:
|
||||
|
||||
// any HistoryItem can have this Interface for
|
||||
// displaying the day mark above the message
|
||||
struct HistoryMessageDate : public BasicInterface<HistoryMessageDate> {
|
||||
HistoryMessageDate(Interfaces *);
|
||||
struct HistoryMessageDate : public BaseComponent<HistoryMessageDate> {
|
||||
HistoryMessageDate(Composer*) {
|
||||
}
|
||||
void init(const QDateTime &date);
|
||||
|
||||
int height() const;
|
||||
void paint(Painter &p, int y, int w) const;
|
||||
|
||||
QString _text;
|
||||
int _width;
|
||||
int _width = 0;
|
||||
};
|
||||
|
||||
// any HistoryItem can have this Interface for
|
||||
// displaying the unread messages bar above the message
|
||||
struct HistoryMessageUnreadBar : public BasicInterface<HistoryMessageUnreadBar> {
|
||||
HistoryMessageUnreadBar(Interfaces *);
|
||||
struct HistoryMessageUnreadBar : public BaseComponent<HistoryMessageUnreadBar> {
|
||||
HistoryMessageUnreadBar(Composer*) {
|
||||
}
|
||||
void init(int count);
|
||||
|
||||
int height() const;
|
||||
void paint(Painter &p, int y, int w) const;
|
||||
|
||||
QString _text;
|
||||
int _width;
|
||||
int _width = 0;
|
||||
|
||||
// if unread bar is freezed the new messages do not
|
||||
// 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
|
||||
// we've seen the bar and new messages are marked as read
|
||||
// as soon as they are added to the chat history
|
||||
bool _freezed;
|
||||
bool _freezed = false;
|
||||
};
|
||||
|
||||
class HistoryMedia;
|
||||
class HistoryItem : public HistoryElem, public Interfaces {
|
||||
class HistoryItem : public HistoryElem, public Composer {
|
||||
public:
|
||||
|
||||
HistoryItem(const HistoryItem &) = delete;
|
||||
@ -1075,8 +1137,11 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual UserData *viaBot() const {
|
||||
return 0;
|
||||
UserData *viaBot() const {
|
||||
if (const HistoryMessageVia *via = Get<HistoryMessageVia>()) {
|
||||
return via->_bot;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
History *history() const {
|
||||
@ -1165,6 +1230,9 @@ public:
|
||||
bool isSilent() const {
|
||||
return _flags & MTPDmessage::Flag::f_silent;
|
||||
}
|
||||
bool hasOutLayout() const {
|
||||
return out() && !isPost();
|
||||
}
|
||||
virtual int32 viewsCount() const {
|
||||
return hasViews() ? 1 : -1;
|
||||
}
|
||||
@ -1315,10 +1383,10 @@ public:
|
||||
virtual const HistoryMessage *toHistoryMessage() const { // dynamic_cast optimize
|
||||
return 0;
|
||||
}
|
||||
virtual HistoryReply *toHistoryReply() { // dynamic_cast optimize
|
||||
return 0;
|
||||
}
|
||||
virtual const HistoryReply *toHistoryReply() const { // dynamic_cast optimize
|
||||
MsgId replyToId() const {
|
||||
if (auto *reply = Get<HistoryMessageReply>()) {
|
||||
return reply->replyToId();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1433,7 +1501,7 @@ protected:
|
||||
|
||||
// this should be used only in previousItemChanged()
|
||||
// to add required bits to the Interfaces mask
|
||||
// after that always use Is<HistoryMessageDate>()
|
||||
// after that always use Has<HistoryMessageDate>()
|
||||
bool displayDate() const {
|
||||
if (HistoryItem *prev = previous()) {
|
||||
return prev->date.date().day() != date.date().day();
|
||||
@ -1750,7 +1818,7 @@ public:
|
||||
return _caption.original();
|
||||
}
|
||||
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 {
|
||||
return _caption.isEmpty();
|
||||
@ -1819,7 +1887,7 @@ public:
|
||||
return _caption.original();
|
||||
}
|
||||
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 {
|
||||
return _caption.isEmpty();
|
||||
@ -1850,25 +1918,25 @@ private:
|
||||
|
||||
};
|
||||
|
||||
struct HistoryDocumentThumbed : public BasicInterface<HistoryDocumentThumbed> {
|
||||
HistoryDocumentThumbed(Interfaces *interfaces) : _thumbw(0), _linkw(0) {
|
||||
struct HistoryDocumentThumbed : public BaseComponent<HistoryDocumentThumbed> {
|
||||
HistoryDocumentThumbed(Composer*) {
|
||||
}
|
||||
TextLinkPtr _linksavel, _linkcancell;
|
||||
int32 _thumbw;
|
||||
int _thumbw = 0;
|
||||
|
||||
mutable int32 _linkw;
|
||||
mutable int _linkw = 0;
|
||||
mutable QString _link;
|
||||
};
|
||||
struct HistoryDocumentCaptioned : public BasicInterface<HistoryDocumentCaptioned> {
|
||||
HistoryDocumentCaptioned(Interfaces *interfaces) : _caption(st::msgFileMinWidth - st::msgPadding.left() - st::msgPadding.right()) {
|
||||
struct HistoryDocumentCaptioned : public BaseComponent<HistoryDocumentCaptioned> {
|
||||
HistoryDocumentCaptioned(Composer*) : _caption(st::msgFileMinWidth - st::msgPadding.left() - st::msgPadding.right()) {
|
||||
}
|
||||
Text _caption;
|
||||
};
|
||||
struct HistoryDocumentNamed : public BasicInterface<HistoryDocumentNamed> {
|
||||
HistoryDocumentNamed(Interfaces *interfaces) : _namew(0) {
|
||||
struct HistoryDocumentNamed : public BaseComponent<HistoryDocumentNamed> {
|
||||
HistoryDocumentNamed(Composer*) {
|
||||
}
|
||||
QString _name;
|
||||
int32 _namew;
|
||||
int _namew = 0;
|
||||
};
|
||||
class HistoryDocument;
|
||||
struct HistoryDocumentVoicePlayback {
|
||||
@ -1878,18 +1946,22 @@ struct HistoryDocumentVoicePlayback {
|
||||
anim::fvalue a_progress;
|
||||
Animation _a_progress;
|
||||
};
|
||||
struct HistoryDocumentVoice : public BasicInterface<HistoryDocumentVoice> {
|
||||
HistoryDocumentVoice(Interfaces *that) : _playback(0) {
|
||||
struct HistoryDocumentVoice : public BaseComponent<HistoryDocumentVoice> {
|
||||
HistoryDocumentVoice(Composer*) {
|
||||
}
|
||||
HistoryDocumentVoice &operator=(HistoryDocumentVoice &&other) {
|
||||
std::swap(_playback, other._playback);
|
||||
return *this;
|
||||
}
|
||||
~HistoryDocumentVoice() {
|
||||
deleteAndMark(_playback);
|
||||
}
|
||||
void ensurePlayback(const HistoryDocument *interfaces) const;
|
||||
void checkPlaybackFinished() const;
|
||||
mutable HistoryDocumentVoicePlayback *_playback;
|
||||
mutable HistoryDocumentVoicePlayback *_playback = nullptr;
|
||||
};
|
||||
|
||||
class HistoryDocument : public HistoryFileMedia, public Interfaces {
|
||||
class HistoryDocument : public HistoryFileMedia, public Composer {
|
||||
public:
|
||||
|
||||
HistoryDocument(DocumentData *document, const QString &caption, const HistoryItem *parent);
|
||||
@ -2021,7 +2093,7 @@ public:
|
||||
return _caption.original();
|
||||
}
|
||||
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 {
|
||||
return _caption.isEmpty();
|
||||
@ -2327,7 +2399,7 @@ public:
|
||||
}
|
||||
|
||||
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 {
|
||||
return true;
|
||||
@ -2365,14 +2437,14 @@ public:
|
||||
static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *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) {
|
||||
return _create(history, msgId, flags, viaBotId, date, from, msg, 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, 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) {
|
||||
return _create(history, msgId, flags, viaBotId, date, from, doc, 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, 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) {
|
||||
return _create(history, msgId, flags, viaBotId, date, from, photo, 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, replyTo, viaBotId, date, from, photo, caption);
|
||||
}
|
||||
|
||||
void initTime();
|
||||
@ -2380,13 +2452,6 @@ public:
|
||||
void initMediaFromDocument(DocumentData *doc, const QString &caption);
|
||||
void fromNameUpdated(int32 width) const;
|
||||
|
||||
virtual UserData *viaBot() const override {
|
||||
if (const HistoryMessageVia *via = Get<HistoryMessageVia>()) {
|
||||
return via->_bot;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 plainMaxWidth() const;
|
||||
void countPositionAndSize(int32 &left, int32 &width) const;
|
||||
|
||||
@ -2403,7 +2468,7 @@ public:
|
||||
if (!hasFromName()) 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 {
|
||||
return _media && _media->uploading();
|
||||
@ -2414,7 +2479,7 @@ public:
|
||||
void setId(MsgId newId) 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;
|
||||
|
||||
@ -2422,7 +2487,6 @@ public:
|
||||
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;
|
||||
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;
|
||||
uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const override {
|
||||
@ -2491,6 +2555,16 @@ public:
|
||||
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
|
||||
return this;
|
||||
}
|
||||
@ -2509,23 +2583,26 @@ protected:
|
||||
|
||||
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, 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, 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, const QString &msg, const EntitiesInText &entities); // local message
|
||||
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, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption); // local photo
|
||||
friend class HistoryItemInstantiated<HistoryMessage>;
|
||||
|
||||
void initDimensions() 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 {
|
||||
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;
|
||||
}
|
||||
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) };
|
||||
|
||||
@ -2536,79 +2613,8 @@ protected:
|
||||
QString _timeText;
|
||||
int _timeWidth = 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;
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
@ -2627,7 +2633,7 @@ inline MTPDmessage::Flags newForwardedFlags(PeerData *p, int32 from, HistoryMess
|
||||
if (from) {
|
||||
result |= MTPDmessage::Flag::f_from_id;
|
||||
}
|
||||
if (fwd->Is<HistoryMessageVia>()) {
|
||||
if (fwd->Has<HistoryMessageVia>()) {
|
||||
result |= MTPDmessage::Flag::f_via_bot_id;
|
||||
}
|
||||
if (!p->isChannel()) {
|
||||
@ -2642,21 +2648,22 @@ inline MTPDmessage::Flags newForwardedFlags(PeerData *p, int32 from, HistoryMess
|
||||
return result;
|
||||
}
|
||||
|
||||
struct HistoryServicePinned : public BasicInterface<HistoryServicePinned> {
|
||||
HistoryServicePinned(Interfaces *);
|
||||
struct HistoryServicePinned : public BaseComponent<HistoryServicePinned> {
|
||||
HistoryServicePinned(Composer*) {
|
||||
}
|
||||
|
||||
MsgId msgId;
|
||||
HistoryItem *msg;
|
||||
MsgId msgId = 0;
|
||||
HistoryItem *msg = nullptr;
|
||||
TextLinkPtr lnk;
|
||||
};
|
||||
|
||||
class HistoryServiceMessage : public HistoryItem, private HistoryItemInstantiated<HistoryServiceMessage> {
|
||||
class HistoryService : public HistoryItem, private HistoryItemInstantiated<HistoryService> {
|
||||
public:
|
||||
|
||||
static HistoryServiceMessage *create(History *history, const MTPDmessageService &msg) {
|
||||
static HistoryService *create(History *history, const MTPDmessageService &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);
|
||||
}
|
||||
|
||||
@ -2710,13 +2717,13 @@ public:
|
||||
|
||||
void setServiceText(const QString &text);
|
||||
|
||||
~HistoryServiceMessage();
|
||||
~HistoryService();
|
||||
|
||||
protected:
|
||||
|
||||
HistoryServiceMessage(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);
|
||||
friend class HistoryItemInstantiated<HistoryServiceMessage>;
|
||||
HistoryService(History *history, const MTPDmessageService &msg);
|
||||
HistoryService(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags = 0, HistoryMedia *media = 0, int32 from = 0);
|
||||
friend class HistoryItemInstantiated<HistoryService>;
|
||||
|
||||
void initDimensions() override;
|
||||
int resizeGetHeight_(int width) override;
|
||||
@ -2731,7 +2738,7 @@ protected:
|
||||
int32 _textWidth, _textHeight;
|
||||
};
|
||||
|
||||
class HistoryGroup : public HistoryServiceMessage, private HistoryItemInstantiated<HistoryGroup> {
|
||||
class HistoryGroup : public HistoryService, private HistoryItemInstantiated<HistoryGroup> {
|
||||
public:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
static HistoryJoined *create(History *history, const QDateTime &date, UserData *from, MTPDmessage::Flags flags) {
|
||||
|
@ -948,7 +948,8 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data());
|
||||
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
|
||||
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 (isUponSelected > 0) {
|
||||
_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()) {
|
||||
_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) {
|
||||
@ -5996,7 +5997,7 @@ void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, bool silent, const M
|
||||
uint64 randomId = rand_value<uint64>();
|
||||
App::historyRegRandom(randomId, newId);
|
||||
History *hist = item->history();
|
||||
MsgId replyTo = item->toHistoryReply() ? item->toHistoryReply()->replyToId() : 0;
|
||||
MsgId replyTo = item->replyToId();
|
||||
MTPmessages_SendMedia::Flags sendFlags = 0;
|
||||
if (replyTo) {
|
||||
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>();
|
||||
App::historyRegRandom(randomId, newId);
|
||||
History *hist = item->history();
|
||||
MsgId replyTo = item->toHistoryReply() ? item->toHistoryReply()->replyToId() : 0;
|
||||
MsgId replyTo = item->replyToId();
|
||||
MTPmessages_SendMedia::Flags sendFlags = 0;
|
||||
if (replyTo) {
|
||||
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>();
|
||||
App::historyRegRandom(randomId, newId);
|
||||
History *hist = item->history();
|
||||
MsgId replyTo = item->toHistoryReply() ? item->toHistoryReply()->replyToId() : 0;
|
||||
MsgId replyTo = item->replyToId();
|
||||
MTPmessages_SendMedia::Flags sendFlags = 0;
|
||||
if (replyTo) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||
@ -6986,7 +6987,7 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
|
||||
} else if (_pinnedBar->msgId != pinnedMsgId) {
|
||||
_pinnedBar->msgId = pinnedMsgId;
|
||||
_pinnedBar->msg = 0;
|
||||
_pinnedBar->text.clean();
|
||||
_pinnedBar->text.clear();
|
||||
updatePinnedBar();
|
||||
update();
|
||||
}
|
||||
|
@ -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)
|
||||
, _text(month ? langMonthFull(date) : langDayOfMonthFull(date)) {
|
||||
AddComponents(OverviewItemInfo::Bit());
|
||||
}
|
||||
|
||||
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)
|
||||
, _link(new PhotoLink(photo))
|
||||
, _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)
|
||||
, _duration(formatDurationText(_data->duration()))
|
||||
, _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)
|
||||
, _namel(new DocumentOpenLink(_data)) {
|
||||
AddComponents(OverviewItemInfo::Bit());
|
||||
|
||||
t_assert(_data->voice() != 0);
|
||||
|
||||
setLinks(new DocumentOpenLink(_data), new DocumentOpenLink(_data), new DocumentCancelLink(_data));
|
||||
@ -741,7 +744,7 @@ bool LayoutOverviewVoice::updateStatusText() const {
|
||||
return showPause;
|
||||
}
|
||||
|
||||
LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent) : LayoutAbstractFileItem(OverviewItemInfo::Bit(), parent)
|
||||
LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent) : LayoutAbstractFileItem(parent)
|
||||
, _data(document)
|
||||
, _msgl(new MessageLink(parent))
|
||||
, _namel(new DocumentOpenLink(_data))
|
||||
@ -751,6 +754,8 @@ LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryIt
|
||||
, _namew(st::semiboldFont->width(_name))
|
||||
, _datew(st::normalFont->width(_date))
|
||||
, _colorIndex(documentColorIndex(_data, _ext)) {
|
||||
AddComponents(OverviewItemInfo::Bit());
|
||||
|
||||
setLinks(new DocumentOpenLink(_data), new DocumentSaveLink(_data), new DocumentCancelLink(_data));
|
||||
|
||||
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();
|
||||
EntitiesInText entities = _parent->originalEntities();
|
||||
|
||||
@ -1319,7 +1326,7 @@ LayoutOverviewLink::Link::Link(const QString &url, const QString &text)
|
||||
, lnk(linkFromUrl(url)) {
|
||||
}
|
||||
|
||||
LayoutInlineItem::LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo) : LayoutItem(0)
|
||||
LayoutInlineItem::LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo) : LayoutItem()
|
||||
, _result(result)
|
||||
, _doc(doc)
|
||||
, _photo(photo)
|
||||
|
@ -101,10 +101,11 @@ public:
|
||||
};
|
||||
|
||||
class LayoutMediaItem;
|
||||
class LayoutItem : public Interfaces {
|
||||
class LayoutItem : public Composer {
|
||||
public:
|
||||
LayoutItem(uint64 i_mask) : Interfaces(i_mask), _maxw(0), _minh(0) {
|
||||
LayoutItem() {
|
||||
}
|
||||
LayoutItem &operator=(const LayoutItem &) = delete;
|
||||
|
||||
int32 maxWidth() const {
|
||||
return _maxw;
|
||||
@ -167,14 +168,16 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
int32 _width, _height, _maxw, _minh;
|
||||
LayoutItem &operator=(const LayoutItem &);
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
int _maxw = 0;
|
||||
int _minh = 0;
|
||||
|
||||
};
|
||||
|
||||
class LayoutMediaItem : public LayoutItem {
|
||||
public:
|
||||
LayoutMediaItem(uint64 i_mask, HistoryItem *parent) : LayoutItem(i_mask), _parent(parent) {
|
||||
LayoutMediaItem(HistoryItem *parent) : _parent(parent) {
|
||||
}
|
||||
|
||||
virtual LayoutMediaItem *toLayoutMediaItem() {
|
||||
@ -194,7 +197,7 @@ protected:
|
||||
|
||||
class LayoutRadialProgressItem : public LayoutMediaItem {
|
||||
public:
|
||||
LayoutRadialProgressItem(uint64 i_mask, HistoryItem *parent) : LayoutMediaItem(i_mask, parent)
|
||||
LayoutRadialProgressItem(HistoryItem *parent) : LayoutMediaItem(parent)
|
||||
, _radial(0)
|
||||
, a_iconOver(0, 0)
|
||||
, _a_iconOver(animation(this, &LayoutRadialProgressItem::step_iconOver)) {
|
||||
@ -240,7 +243,7 @@ private:
|
||||
|
||||
class LayoutAbstractFileItem : public LayoutRadialProgressItem {
|
||||
public:
|
||||
LayoutAbstractFileItem(uint64 i_mask, HistoryItem *parent) : LayoutRadialProgressItem(i_mask, parent) {
|
||||
LayoutAbstractFileItem(HistoryItem *parent) : LayoutRadialProgressItem(parent) {
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -268,19 +271,19 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class OverviewItemInfo : public BasicInterface<OverviewItemInfo> {
|
||||
class OverviewItemInfo : public BaseComponent<OverviewItemInfo> {
|
||||
public:
|
||||
OverviewItemInfo(Interfaces *) : _top(0) {
|
||||
OverviewItemInfo(Composer*) {
|
||||
}
|
||||
int32 top() const {
|
||||
int top() const {
|
||||
return _top;
|
||||
}
|
||||
void setTop(int32 top) {
|
||||
void setTop(int top) {
|
||||
_top = top;
|
||||
}
|
||||
|
||||
private:
|
||||
int32 _top;
|
||||
int _top = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -3550,7 +3550,7 @@ namespace Local {
|
||||
return result;
|
||||
}
|
||||
|
||||
void _writePeer(QDataStream &stream, PeerData *peer, int32 fileVersion = AppVersion) {
|
||||
void _writePeer(QDataStream &stream, PeerData *peer) {
|
||||
stream << quint64(peer->id) << quint64(peer->photoId);
|
||||
_writeStorageImageLocation(stream, peer->photoLoc);
|
||||
if (peer->isUser()) {
|
||||
@ -3560,7 +3560,7 @@ namespace Local {
|
||||
if (AppVersion >= 9012) {
|
||||
stream << qint32(user->flags);
|
||||
}
|
||||
if (AppVersion >= 9016 || fileVersion >= 9016) {
|
||||
if (AppVersion >= 9016) {
|
||||
stream << (user->botInfo ? user->botInfo->inlinePlaceholder : QString());
|
||||
}
|
||||
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 *result = 0;
|
||||
quint64 peerId = 0, photoId = 0;
|
||||
from.stream >> peerId >> photoId;
|
||||
|
||||
StorageImageLocation photoLoc(_readStorageImageLocation(from));
|
||||
|
||||
result = App::peerLoaded(peerId);
|
||||
bool wasLoaded = (result && result->loaded);
|
||||
|
||||
PeerData *result = App::peerLoaded(peerId);
|
||||
bool wasLoaded = (result != nullptr);
|
||||
if (!wasLoaded) {
|
||||
result = App::peer(peerId);
|
||||
result->loaded = true;
|
||||
result->loadedStatus = PeerData::FullLoaded;
|
||||
}
|
||||
if (result->isUser()) {
|
||||
UserData *user = result->asUser();
|
||||
@ -3737,7 +3735,7 @@ namespace Local {
|
||||
}
|
||||
data.stream << quint32(botsCnt);
|
||||
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);
|
||||
file.writeEncrypted(data);
|
||||
|
@ -4099,17 +4099,17 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
|
||||
|
||||
case mtpc_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" : ""));
|
||||
return getDifference();
|
||||
}
|
||||
if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_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" : ""));
|
||||
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" : ""));
|
||||
return getDifference();
|
||||
}
|
||||
@ -4133,18 +4133,18 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
|
||||
case mtpc_updateShortChatMessage: {
|
||||
const MTPDupdateShortChatMessage &d(updates.c_updateShortChatMessage());
|
||||
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" : ""));
|
||||
if (noFrom && App::api()) App::api()->requestFullPeer(App::chatLoaded(d.vchat_id.v));
|
||||
return getDifference();
|
||||
}
|
||||
if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_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" : ""));
|
||||
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" : ""));
|
||||
return getDifference();
|
||||
}
|
||||
@ -4357,9 +4357,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||
case mtpc_updateChatUserTyping: {
|
||||
const MTPDupdateChatUserTyping &d(update.c_updateChatUserTyping());
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
UserData *user = (d.vuser_id.v == MTP::authedId()) ? 0 : App::userLoaded(d.vuser_id.v);
|
||||
|
@ -1267,8 +1267,9 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
_contextMenuLnk = textlnkOver();
|
||||
PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_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 lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false;
|
||||
bool lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false;
|
||||
if (lnkPhoto || lnkDocument) {
|
||||
_menu = new PopupMenu();
|
||||
if (App::hoveredLinkItem()) {
|
||||
@ -1282,7 +1283,7 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
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(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) {
|
||||
|
@ -35,8 +35,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "localstorage.h"
|
||||
|
||||
namespace {
|
||||
int32 peerColorIndex(const PeerId &peer) {
|
||||
int32 myId(MTP::authedId()), peerId(peerToBareInt(peer));
|
||||
int peerColorIndex(const PeerId &peer) {
|
||||
UserId myId(MTP::authedId()), peerId(peerToBareInt(peer));
|
||||
QByteArray both(qsl("%1%2").arg(peerId).arg(myId).toUtf8());
|
||||
if (both.size() > 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] = {
|
||||
style::color(st::color1),
|
||||
style::color(st::color2),
|
||||
@ -61,7 +61,7 @@ style::color peerColor(int32 index) {
|
||||
return peerColors[index];
|
||||
}
|
||||
|
||||
ImagePtr userDefPhoto(int32 index) {
|
||||
ImagePtr userDefPhoto(int index) {
|
||||
static const ImagePtr userDefPhotos[UserColorsCount] = {
|
||||
ImagePtr(qsl(":/ava/art/usercolor1.png"), "PNG"),
|
||||
ImagePtr(qsl(":/ava/art/usercolor2.png"), "PNG"),
|
||||
@ -75,7 +75,7 @@ ImagePtr userDefPhoto(int32 index) {
|
||||
return userDefPhotos[index];
|
||||
}
|
||||
|
||||
ImagePtr chatDefPhoto(int32 index) {
|
||||
ImagePtr chatDefPhoto(int index) {
|
||||
static const ImagePtr chatDefPhotos[4] = {
|
||||
ImagePtr(qsl(":/ava/art/chatcolor1.png"), "PNG"),
|
||||
ImagePtr(qsl(":/ava/art/chatcolor2.png"), "PNG"),
|
||||
@ -85,7 +85,7 @@ ImagePtr chatDefPhoto(int32 index) {
|
||||
return chatDefPhotos[index];
|
||||
}
|
||||
|
||||
ImagePtr channelDefPhoto(int32 index) {
|
||||
ImagePtr channelDefPhoto(int index) {
|
||||
static const ImagePtr channelDefPhotos[4] = {
|
||||
ImagePtr(qsl(":/ava/art/channelcolor1.png"), "PNG"),
|
||||
ImagePtr(qsl(":/ava/art/channelcolor2.png"), "PNG"),
|
||||
@ -100,7 +100,7 @@ NotifySettingsPtr globalNotifyAllPtr = UnknownNotifySettings, globalNotifyUsersP
|
||||
|
||||
PeerData::PeerData(const PeerId &id) : id(id)
|
||||
, lnk(new PeerLink(this))
|
||||
, loaded(false)
|
||||
, loadedStatus(NotLoaded)
|
||||
, colorIndex(peerColorIndex(id))
|
||||
, color(peerColor(colorIndex))
|
||||
, photoId(UnknownPeerPhotoId)
|
||||
@ -279,7 +279,7 @@ void UserData::setPhone(const QString &newPhone) {
|
||||
phone = newPhone;
|
||||
}
|
||||
|
||||
void UserData::setBotInfoVersion(int32 version) {
|
||||
void UserData::setBotInfoVersion(int version) {
|
||||
if (version < 0) {
|
||||
if (botInfo) {
|
||||
if (!botInfo->commands.isEmpty()) {
|
||||
@ -850,7 +850,7 @@ QString documentSaveFilename(const DocumentData *data, bool forceSavingAs = fals
|
||||
} else {
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,21 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
typedef int32 UserId;
|
||||
typedef int32 ChatId;
|
||||
typedef int32 ChannelId;
|
||||
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;
|
||||
static const uint64 PeerIdMask = 0xFFFFFFFFULL;
|
||||
static const uint64 PeerIdTypeMask = 0x300000000ULL;
|
||||
@ -38,10 +50,10 @@ inline bool peerIsChat(const PeerId &id) {
|
||||
inline bool peerIsChannel(const PeerId &id) {
|
||||
return (id & PeerIdTypeMask) == PeerIdChannelShift;
|
||||
}
|
||||
inline PeerId peerFromUser(int32 user_id) {
|
||||
inline PeerId peerFromUser(UserId 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));
|
||||
}
|
||||
inline PeerId peerFromChannel(ChannelId channel_id) {
|
||||
@ -59,10 +71,10 @@ inline PeerId peerFromChannel(const MTPint &channel_id) {
|
||||
inline int32 peerToBareInt(const PeerId &id) {
|
||||
return int32(uint32(id & PeerIdMask));
|
||||
}
|
||||
inline int32 peerToUser(const PeerId &id) {
|
||||
inline UserId peerToUser(const PeerId &id) {
|
||||
return peerIsUser(id) ? peerToBareInt(id) : 0;
|
||||
}
|
||||
inline int32 peerToChat(const PeerId &id) {
|
||||
inline ChatId peerToChat(const PeerId &id) {
|
||||
return peerIsChat(id) ? peerToBareInt(id) : 0;
|
||||
}
|
||||
inline ChannelId peerToChannel(const PeerId &id) {
|
||||
@ -112,7 +124,7 @@ inline MTPDmessage::Flags flagsFromMessage(const MTPmessage &msg) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
inline int32 idFromMessage(const MTPmessage &msg) {
|
||||
inline MsgId idFromMessage(const MTPmessage &msg) {
|
||||
switch (msg.type()) {
|
||||
case mtpc_messageEmpty: return msg.c_messageEmpty().vid.v;
|
||||
case mtpc_message: return msg.c_message().vid.v;
|
||||
@ -120,7 +132,7 @@ inline int32 idFromMessage(const MTPmessage &msg) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
inline int32 dateFromMessage(const MTPmessage &msg) {
|
||||
inline TimeId dateFromMessage(const MTPmessage &msg) {
|
||||
switch (msg.type()) {
|
||||
case mtpc_message: return msg.c_message().vdate.v;
|
||||
case mtpc_messageService: return msg.c_messageService().vdate.v;
|
||||
@ -135,15 +147,6 @@ typedef uint64 DocumentId;
|
||||
typedef uint64 WebPageId;
|
||||
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) {
|
||||
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") {
|
||||
}
|
||||
MTPDpeerNotifySettings::Flags flags;
|
||||
int32 mute;
|
||||
TimeId mute;
|
||||
string sound;
|
||||
bool previews() const {
|
||||
return flags & MTPDpeerNotifySettings::Flag::f_show_previews;
|
||||
@ -184,9 +187,9 @@ static const NotifySettingsPtr EmptyNotifySettings = NotifySettingsPtr(1);
|
||||
extern NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats;
|
||||
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) {
|
||||
int32 t = unixtime();
|
||||
TimeId t = unixtime();
|
||||
if (settings->mute > t) {
|
||||
if (changeIn) *changeIn = settings->mute - t + 1;
|
||||
return true;
|
||||
@ -196,12 +199,12 @@ inline bool isNotifyMuted(NotifySettingsPtr settings, int32 *changeIn = 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const int32 UserColorsCount = 8;
|
||||
static const int UserColorsCount = 8;
|
||||
|
||||
style::color peerColor(int32 index);
|
||||
ImagePtr userDefPhoto(int32 index);
|
||||
ImagePtr chatDefPhoto(int32 index);
|
||||
ImagePtr channelDefPhoto(int32 index);
|
||||
style::color peerColor(int index);
|
||||
ImagePtr userDefPhoto(int index);
|
||||
ImagePtr chatDefPhoto(int index);
|
||||
ImagePtr channelDefPhoto(int index);
|
||||
|
||||
static const PhotoId UnknownPeerPhotoId = 0xFFFFFFFFFFFFFFFFULL;
|
||||
|
||||
@ -276,10 +279,15 @@ public:
|
||||
typedef QSet<QChar> NameFirstChars;
|
||||
NameFirstChars chars;
|
||||
|
||||
bool loaded;
|
||||
enum LoadedStatus {
|
||||
NotLoaded = 0x00,
|
||||
MinimalLoaded = 0x01,
|
||||
FullLoaded = 0x02,
|
||||
};
|
||||
LoadedStatus loadedStatus;
|
||||
MTPinputPeer input;
|
||||
|
||||
int32 colorIndex;
|
||||
int colorIndex;
|
||||
style::color color;
|
||||
|
||||
void setUserpic(ImagePtr userpic);
|
||||
@ -297,7 +305,7 @@ public:
|
||||
PhotoId photoId;
|
||||
StorageImageLocation photoLoc;
|
||||
|
||||
int32 nameVersion;
|
||||
int nameVersion;
|
||||
|
||||
NotifySettingsPtr notify;
|
||||
|
||||
@ -358,7 +366,7 @@ struct BotInfo {
|
||||
}
|
||||
bool inited;
|
||||
bool readsAllHistory, cantJoinGroups;
|
||||
int32 version;
|
||||
int version;
|
||||
QString description, inlinePlaceholder;
|
||||
QList<BotCommand> commands;
|
||||
Text text; // description
|
||||
@ -382,7 +390,7 @@ public:
|
||||
void setPhoto(const MTPUserProfilePhoto &photo);
|
||||
void setName(const QString &first, const QString &last, const QString &phoneName, const QString &username);
|
||||
void setPhone(const QString &newPhone);
|
||||
void setBotInfoVersion(int32 version);
|
||||
void setBotInfoVersion(int version);
|
||||
void setBotInfo(const MTPBotInfo &info);
|
||||
|
||||
void setNameOrPhone(const QString &newNameOrPhone);
|
||||
@ -407,13 +415,13 @@ public:
|
||||
QString phone;
|
||||
QString nameOrPhone;
|
||||
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
|
||||
UserBlockedStatus blocked = UserBlockUnknown;
|
||||
|
||||
typedef QList<PhotoData*> Photos;
|
||||
Photos photos;
|
||||
int32 photosCount = -1; // -1 not loaded, 0 all loaded
|
||||
int photosCount = -1; // -1 not loaded, 0 all loaded
|
||||
|
||||
QString about;
|
||||
|
||||
@ -462,10 +470,10 @@ public:
|
||||
|
||||
ChannelData *migrateToPtr;
|
||||
|
||||
int32 count;
|
||||
int32 date;
|
||||
int32 version;
|
||||
int32 creator;
|
||||
int count;
|
||||
TimeId date;
|
||||
int version;
|
||||
UserId creator;
|
||||
|
||||
MTPDchat::Flags flags;
|
||||
bool isForbidden;
|
||||
@ -499,7 +507,7 @@ public:
|
||||
bool isMigrated() const {
|
||||
return flags & MTPDchat::Flag::f_migrated_to;
|
||||
}
|
||||
typedef QMap<UserData*, int32> Participants;
|
||||
typedef QMap<UserData*, int> Participants;
|
||||
Participants participants;
|
||||
typedef OrderedSet<UserData*> InvitedByMe;
|
||||
InvitedByMe invitedByMe;
|
||||
@ -753,29 +761,59 @@ private:
|
||||
|
||||
};
|
||||
|
||||
inline bool isUser(const PeerData *peer) {
|
||||
return peer ? peer->isUser() : false;
|
||||
}
|
||||
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 {
|
||||
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() {
|
||||
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 {
|
||||
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() {
|
||||
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 {
|
||||
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 {
|
||||
return (isMegagroup() && asChannel()->amIn()) ? asChannel()->mgInfo->migrateFromPtr : 0;
|
||||
return (isMegagroup() && asChannel()->amIn()) ? asChannel()->mgInfo->migrateFromPtr : nullptr;
|
||||
}
|
||||
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 {
|
||||
return migrateTo() ? migrateTo()->dialogName() : ((isUser() && !asUser()->phoneText.isEmpty()) ? asUser()->phoneText : nameText);
|
||||
@ -998,11 +1036,14 @@ public:
|
||||
SongData *song() {
|
||||
return (type == SongDocument) ? static_cast<SongData*>(_additional) : 0;
|
||||
}
|
||||
const SongData *song() const {
|
||||
return (type == SongDocument) ? static_cast<const SongData*>(_additional) : 0;
|
||||
}
|
||||
VoiceData *voice() {
|
||||
return (type == VoiceDocument) ? static_cast<VoiceData*>(_additional) : 0;
|
||||
}
|
||||
const VoiceData *voice() const {
|
||||
return (type == VoiceDocument) ? static_cast<VoiceData*>(_additional) : 0;
|
||||
return (type == VoiceDocument) ? static_cast<const VoiceData*>(_additional) : 0;
|
||||
}
|
||||
bool isAnimation() const {
|
||||
return (type == AnimatedDocument) || !mime.compare(qstr("image/gif"), Qt::CaseInsensitive);
|
||||
|
@ -120,8 +120,8 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
int32 myunixtime() {
|
||||
return (int32)time(NULL);
|
||||
TimeId myunixtime() {
|
||||
return (TimeId)time(NULL);
|
||||
}
|
||||
|
||||
void unixtimeInit() {
|
||||
@ -149,19 +149,19 @@ void unixtimeSet(int32 serverTime, bool force) {
|
||||
_initMsgIdConstants();
|
||||
}
|
||||
|
||||
int32 unixtime() {
|
||||
int32 result = myunixtime();
|
||||
TimeId unixtime() {
|
||||
TimeId result = myunixtime();
|
||||
|
||||
QReadLocker locker(&unixtimeLock);
|
||||
return result + unixtimeDelta;
|
||||
}
|
||||
|
||||
int32 fromServerTime(const MTPint &serverTime) {
|
||||
TimeId fromServerTime(const MTPint &serverTime) {
|
||||
QReadLocker locker(&unixtimeLock);
|
||||
return serverTime.v - unixtimeDelta;
|
||||
}
|
||||
|
||||
MTPint toServerTime(const int32 &clientTime) {
|
||||
MTPint toServerTime(const TimeId &clientTime) {
|
||||
QReadLocker locker(&unixtimeLock);
|
||||
return MTP_int(clientTime + unixtimeDelta);
|
||||
}
|
||||
@ -1034,35 +1034,32 @@ MimeType mimeTypeForData(const QByteArray &data) {
|
||||
return MimeType(QMimeDatabase().mimeTypeForData(data));
|
||||
}
|
||||
|
||||
class InterfacesMetadatasMap : public QMap<uint64, InterfacesMetadata*> {
|
||||
public:
|
||||
~InterfacesMetadatasMap() {
|
||||
for (const_iterator i = cbegin(), e = cend(); i != e; ++i) {
|
||||
delete i.value();
|
||||
struct ComposerMetadatasMap {
|
||||
QMap<uint64, ComposerMetadata*> data;
|
||||
~ComposerMetadatasMap() {
|
||||
for_const (const ComposerMetadata *p, data) {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const InterfacesMetadata *GetInterfacesMetadata(uint64 mask) {
|
||||
typedef QMap<uint64, InterfacesMetadata*> InterfacesMetadatasMap;
|
||||
static InterfacesMetadatasMap InterfacesMetadatas;
|
||||
static QMutex InterfacesMetadatasMutex;
|
||||
const ComposerMetadata *GetComposerMetadata(uint64 mask) {
|
||||
static ComposerMetadatasMap ComposerMetadatas;
|
||||
static QMutex ComposerMetadatasMutex;
|
||||
|
||||
QMutexLocker lock(&InterfacesMetadatasMutex);
|
||||
InterfacesMetadatasMap::const_iterator i = InterfacesMetadatas.constFind(mask);
|
||||
if (i == InterfacesMetadatas.cend()) {
|
||||
InterfacesMetadata *meta = new InterfacesMetadata(mask);
|
||||
if (!meta) { // terminate if we can't allocate memory
|
||||
throw "Can't allocate memory!";
|
||||
}
|
||||
QMutexLocker lock(&ComposerMetadatasMutex);
|
||||
auto i = ComposerMetadatas.data.constFind(mask);
|
||||
if (i == ComposerMetadatas.data.cend()) {
|
||||
ComposerMetadata *meta = new ComposerMetadata(mask);
|
||||
t_assert(meta != nullptr);
|
||||
|
||||
i = InterfacesMetadatas.insert(mask, meta);
|
||||
i = ComposerMetadatas.data.insert(mask, meta);
|
||||
}
|
||||
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;
|
||||
|
@ -104,6 +104,30 @@ using std::string;
|
||||
using std::exception;
|
||||
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"
|
||||
|
||||
static volatile int *t_assert_nullptr = 0;
|
||||
@ -140,12 +164,12 @@ private:
|
||||
};
|
||||
|
||||
class MTPint;
|
||||
|
||||
int32 myunixtime();
|
||||
typedef int32 TimeId;
|
||||
TimeId myunixtime();
|
||||
void unixtimeInit();
|
||||
void unixtimeSet(int32 servertime, bool force = false);
|
||||
int32 unixtime();
|
||||
int32 fromServerTime(const MTPint &serverTime);
|
||||
void unixtimeSet(TimeId servertime, bool force = false);
|
||||
TimeId unixtime();
|
||||
TimeId fromServerTime(const MTPint &serverTime);
|
||||
uint64 msgid();
|
||||
int32 reqid();
|
||||
|
||||
@ -541,24 +565,26 @@ inline void destroyImplementation(I *&ptr) {
|
||||
deleteAndMark(ptr);
|
||||
}
|
||||
|
||||
class Interfaces;
|
||||
typedef void(*InterfaceConstruct)(void *location, Interfaces *interfaces);
|
||||
typedef void(*InterfaceDestruct)(void *location);
|
||||
typedef void(*InterfaceMove)(void *location, void *waslocation);
|
||||
class Composer;
|
||||
typedef void(*ComponentConstruct)(void *location, Composer *composer);
|
||||
typedef void(*ComponentDestruct)(void *location);
|
||||
typedef void(*ComponentMove)(void *location, void *waslocation);
|
||||
|
||||
struct InterfaceWrapStruct {
|
||||
InterfaceWrapStruct() : Size(0), Construct(0), Destruct(0) {
|
||||
struct ComponentWrapStruct {
|
||||
// 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)
|
||||
, Construct(construct)
|
||||
, Destruct(destruct)
|
||||
, Move(move) {
|
||||
}
|
||||
int Size;
|
||||
InterfaceConstruct Construct;
|
||||
InterfaceDestruct Destruct;
|
||||
InterfaceMove Move;
|
||||
ComponentConstruct Construct;
|
||||
ComponentDestruct Destruct;
|
||||
ComponentMove Move;
|
||||
};
|
||||
|
||||
template <int Value, int Denominator>
|
||||
@ -567,36 +593,43 @@ struct CeilDivideMinimumOne {
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct InterfaceWrapTemplate {
|
||||
struct ComponentWrapTemplate {
|
||||
static const int Size = CeilDivideMinimumOne<sizeof(Type), sizeof(uint64)>::Result * sizeof(uint64);
|
||||
static void Construct(void *location, Interfaces *interfaces) {
|
||||
new (location) Type(interfaces);
|
||||
static void Construct(void *location, Composer *composer) {
|
||||
new (location) Type(composer);
|
||||
}
|
||||
static void Destruct(void *location) {
|
||||
((Type*)location)->~Type();
|
||||
}
|
||||
static void Move(void *location, void *waslocation) {
|
||||
*(Type*)location = *(Type*)waslocation;
|
||||
*(Type*)location = std11::move(*(Type*)waslocation);
|
||||
}
|
||||
};
|
||||
|
||||
extern InterfaceWrapStruct InterfaceWraps[64];
|
||||
extern QAtomicInt InterfaceIndexLast;
|
||||
extern ComponentWrapStruct ComponentWraps[64];
|
||||
extern QAtomicInt ComponentIndexLast;
|
||||
|
||||
template <typename Type>
|
||||
class BasicInterface {
|
||||
class BaseComponent {
|
||||
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 QAtomicInt _index(0);
|
||||
if (int index = _index.loadAcquire()) {
|
||||
return index - 1;
|
||||
}
|
||||
while (true) {
|
||||
int last = InterfaceIndexLast.loadAcquire();
|
||||
if (InterfaceIndexLast.testAndSetOrdered(last, last + 1)) {
|
||||
int last = ComponentIndexLast.loadAcquire();
|
||||
if (ComponentIndexLast.testAndSetOrdered(last, last + 1)) {
|
||||
t_assert(last < 64);
|
||||
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;
|
||||
}
|
||||
@ -609,22 +642,14 @@ public:
|
||||
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class BasicInterfaceWithPointer : public BasicInterface<Type> {
|
||||
public:
|
||||
BasicInterfaceWithPointer(Interfaces *interfaces) : interfaces(interfaces) {
|
||||
}
|
||||
Interfaces *interfaces = 0;
|
||||
};
|
||||
|
||||
class InterfacesMetadata {
|
||||
class ComposerMetadata {
|
||||
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) {
|
||||
uint64 m = (1 << i);
|
||||
if (_mask & m) {
|
||||
int s = InterfaceWraps[i].Size;
|
||||
int s = ComponentWraps[i].Size;
|
||||
if (s) {
|
||||
offsets[i] = size;
|
||||
size += s;
|
||||
@ -660,15 +685,15 @@ private:
|
||||
|
||||
};
|
||||
|
||||
const InterfacesMetadata *GetInterfacesMetadata(uint64 mask);
|
||||
const ComposerMetadata *GetComposerMetadata(uint64 mask);
|
||||
|
||||
class Interfaces {
|
||||
class Composer {
|
||||
public:
|
||||
|
||||
Interfaces(uint64 mask = 0) : _data(zerodata()) {
|
||||
Composer(uint64 mask = 0) : _data(zerodata()) {
|
||||
if (mask) {
|
||||
const InterfacesMetadata *meta = GetInterfacesMetadata(mask);
|
||||
int32 size = sizeof(const InterfacesMetadata *) + meta->size;
|
||||
const ComposerMetadata *meta = GetComposerMetadata(mask);
|
||||
int size = sizeof(meta) + meta->size;
|
||||
void *data = operator new(size);
|
||||
if (!data) { // terminate if we can't allocate memory
|
||||
throw "Can't allocate memory!";
|
||||
@ -680,13 +705,13 @@ public:
|
||||
int offset = meta->offsets[i];
|
||||
if (offset >= 0) {
|
||||
try {
|
||||
InterfaceWraps[i].Construct(_dataptrunsafe(offset), this);
|
||||
ComponentWraps[i].Construct(_dataptrunsafe(offset), this);
|
||||
} catch (...) {
|
||||
while (i > 0) {
|
||||
--i;
|
||||
offset = meta->offsets[--i];
|
||||
if (offset >= 0) {
|
||||
InterfaceWraps[i].Destruct(_dataptrunsafe(offset));
|
||||
ComponentWraps[i].Destruct(_dataptrunsafe(offset));
|
||||
}
|
||||
}
|
||||
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)) {
|
||||
Interfaces tmp(mask);
|
||||
Composer tmp(mask);
|
||||
tmp.swap(*this);
|
||||
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) {
|
||||
int offset = meta->offsets[i], wasoffset = wasmeta->offsets[i];
|
||||
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) {
|
||||
UpdateInterfaces(_meta()->maskadd(mask));
|
||||
void AddComponents(uint64 mask = 0) {
|
||||
UpdateComponents(_meta()->maskadd(mask));
|
||||
}
|
||||
void RemoveInterfaces(uint64 mask = 0) {
|
||||
UpdateInterfaces(_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);
|
||||
}
|
||||
void RemoveComponents(uint64 mask = 0) {
|
||||
UpdateComponents(_meta()->maskremove(mask));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
@ -738,31 +766,28 @@ public:
|
||||
return static_cast<const Type*>(_dataptr(_meta()->offsets[Type::Index()]));
|
||||
}
|
||||
template <typename Type>
|
||||
bool Is() const {
|
||||
bool Has() const {
|
||||
return (_meta()->offsets[Type::Index()] >= 0);
|
||||
}
|
||||
|
||||
private:
|
||||
static const InterfacesMetadata *ZeroInterfacesMetadata;
|
||||
static const ComposerMetadata *ZeroComposerMetadata;
|
||||
static void *zerodata() {
|
||||
return &ZeroInterfacesMetadata;
|
||||
return &ZeroComposerMetadata;
|
||||
}
|
||||
|
||||
void *_dataptrunsafe(int skip) const {
|
||||
return (char*)_data + sizeof(const InterfacesMetadata*) + skip;
|
||||
return (char*)_data + sizeof(_meta()) + skip;
|
||||
}
|
||||
void *_dataptr(int skip) const {
|
||||
return (skip >= 0) ? _dataptrunsafe(skip) : 0;
|
||||
}
|
||||
const InterfacesMetadata *&_meta() const {
|
||||
return *static_cast<const InterfacesMetadata**>(_data);
|
||||
const ComposerMetadata *&_meta() const {
|
||||
return *static_cast<const ComposerMetadata**>(_data);
|
||||
}
|
||||
void *_data;
|
||||
|
||||
Interfaces(const Interfaces &other);
|
||||
Interfaces &operator=(const Interfaces &other);
|
||||
|
||||
void swap(Interfaces &other) {
|
||||
void swap(Composer &other) {
|
||||
std::swap(_data, other._data);
|
||||
}
|
||||
|
||||
|
@ -1410,7 +1410,7 @@ void Window::notifySchedule(History *history, HistoryItem *item) {
|
||||
haveSetting = false;
|
||||
}
|
||||
|
||||
int delay = item->Is<HistoryMessageForwarded>() ? 500 : 100, t = unixtime();
|
||||
int delay = item->Has<HistoryMessageForwarded>() ? 500 : 100, t = unixtime();
|
||||
uint64 ms = getms(true);
|
||||
bool isOnline = main->lastWasOnline(), otherNotOld = ((cOtherOnline() * uint64(1000)) + Global::OnlineCloudTimeout() > 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);
|
||||
break;
|
||||
} else {
|
||||
HistoryItem *fwd = notifyItem->Is<HistoryMessageForwarded>() ? notifyItem : 0; // forwarded notify grouping
|
||||
HistoryItem *fwd = notifyItem->Has<HistoryMessageForwarded>() ? notifyItem : nullptr; // forwarded notify grouping
|
||||
int32 fwdCount = 1;
|
||||
|
||||
uint64 ms = getms(true);
|
||||
@ -1657,7 +1657,7 @@ void Window::notifyShowNext(NotifyWindow *remove) {
|
||||
} while (history->hasNotification());
|
||||
if (nextNotify) {
|
||||
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) {
|
||||
fwd = nextFwd;
|
||||
++fwdCount;
|
||||
|
@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,9,34,3
|
||||
PRODUCTVERSION 0,9,34,3
|
||||
FILEVERSION 0,9,34,4
|
||||
PRODUCTVERSION 0,9,34,4
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -51,10 +51,10 @@ BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "FileVersion", "0.9.34.3"
|
||||
VALUE "FileVersion", "0.9.34.4"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "0.9.34.3"
|
||||
VALUE "ProductVersion", "0.9.34.4"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -3,4 +3,4 @@ AppVersionStrMajor 0.9
|
||||
AppVersionStrSmall 0.9.34
|
||||
AppVersionStr 0.9.34
|
||||
DevChannel 0
|
||||
BetaVersion 9034003
|
||||
BetaVersion 9034004
|
||||
|
Loading…
Reference in New Issue
Block a user