2017-09-26 11:49:16 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
2018-01-03 10:23:14 +00:00
|
|
|
the official desktop application for the Telegram messaging service.
|
2017-09-26 11:49:16 +00:00
|
|
|
|
2018-01-03 10:23:14 +00:00
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
2017-09-26 11:49:16 +00:00
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
|
2018-01-14 16:02:25 +00:00
|
|
|
#include "base/value_ordering.h"
|
2018-07-13 21:25:47 +00:00
|
|
|
#include "ui/text/text.h" // For QFIXED_MAX
|
2021-04-01 21:04:10 +00:00
|
|
|
#include "data/data_peer_id.h"
|
2018-01-14 16:02:25 +00:00
|
|
|
|
2020-06-09 09:36:40 +00:00
|
|
|
class HistoryItem;
|
|
|
|
using HistoryItemsList = std::vector<not_null<HistoryItem*>>;
|
|
|
|
|
|
|
|
class StorageImageLocation;
|
|
|
|
class WebFileLocation;
|
|
|
|
struct GeoPointLocation;
|
|
|
|
|
2018-08-27 11:35:58 +00:00
|
|
|
namespace Storage {
|
|
|
|
namespace Cache {
|
|
|
|
struct Key;
|
|
|
|
} // namespace Cache
|
|
|
|
} // namespace Storage
|
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
namespace Ui {
|
|
|
|
class InputField;
|
|
|
|
} // namespace Ui
|
|
|
|
|
2020-06-09 09:36:40 +00:00
|
|
|
namespace Main {
|
|
|
|
class Session;
|
|
|
|
} // namespace Main
|
|
|
|
|
2019-01-25 14:37:28 +00:00
|
|
|
namespace Images {
|
|
|
|
enum class Option;
|
|
|
|
using Options = base::flags<Option>;
|
|
|
|
} // namespace Images
|
|
|
|
|
2017-12-25 14:17:00 +00:00
|
|
|
namespace Data {
|
|
|
|
|
|
|
|
struct UploadState {
|
|
|
|
UploadState(int size) : size(size) {
|
|
|
|
}
|
|
|
|
int offset = 0;
|
|
|
|
int size = 0;
|
|
|
|
bool waitingForAlbum = false;
|
|
|
|
};
|
|
|
|
|
2018-08-27 11:35:58 +00:00
|
|
|
Storage::Cache::Key DocumentCacheKey(int32 dcId, uint64 id);
|
2018-10-25 08:12:56 +00:00
|
|
|
Storage::Cache::Key DocumentThumbCacheKey(int32 dcId, uint64 id);
|
2018-08-27 11:35:58 +00:00
|
|
|
Storage::Cache::Key WebDocumentCacheKey(const WebFileLocation &location);
|
|
|
|
Storage::Cache::Key UrlCacheKey(const QString &location);
|
2018-10-08 18:14:05 +00:00
|
|
|
Storage::Cache::Key GeoPointCacheKey(const GeoPointLocation &location);
|
2018-08-27 11:35:58 +00:00
|
|
|
|
2018-08-28 21:09:55 +00:00
|
|
|
constexpr auto kImageCacheTag = uint8(0x01);
|
|
|
|
constexpr auto kStickerCacheTag = uint8(0x02);
|
|
|
|
constexpr auto kVoiceMessageCacheTag = uint8(0x03);
|
|
|
|
constexpr auto kVideoMessageCacheTag = uint8(0x04);
|
|
|
|
constexpr auto kAnimationCacheTag = uint8(0x05);
|
|
|
|
|
2019-01-25 14:37:28 +00:00
|
|
|
struct FileOrigin;
|
|
|
|
|
2017-12-25 14:17:00 +00:00
|
|
|
} // namespace Data
|
|
|
|
|
2018-01-14 16:02:25 +00:00
|
|
|
struct MessageGroupId {
|
2021-04-01 21:04:10 +00:00
|
|
|
PeerId peer = 0;
|
2019-05-31 21:51:57 +00:00
|
|
|
uint64 value = 0;
|
|
|
|
|
|
|
|
MessageGroupId() = default;
|
2021-04-01 21:04:10 +00:00
|
|
|
static MessageGroupId FromRaw(PeerId peer, uint64 value) {
|
2019-05-31 21:51:57 +00:00
|
|
|
auto result = MessageGroupId();
|
|
|
|
result.peer = peer;
|
|
|
|
result.value = value;
|
|
|
|
return result;
|
2018-01-14 16:02:25 +00:00
|
|
|
}
|
|
|
|
|
2019-04-02 10:38:53 +00:00
|
|
|
bool empty() const {
|
2019-05-31 21:51:57 +00:00
|
|
|
return !value;
|
2019-04-02 10:38:53 +00:00
|
|
|
}
|
2018-01-14 16:02:25 +00:00
|
|
|
explicit operator bool() const {
|
2019-04-02 10:38:53 +00:00
|
|
|
return !empty();
|
2018-01-14 16:02:25 +00:00
|
|
|
}
|
2019-05-31 21:51:57 +00:00
|
|
|
uint64 raw() const {
|
|
|
|
return value;
|
2018-01-14 16:02:25 +00:00
|
|
|
}
|
|
|
|
|
2019-05-31 21:51:57 +00:00
|
|
|
friend inline std::pair<uint64, uint64> value_ordering_helper(MessageGroupId value) {
|
2021-04-01 21:04:10 +00:00
|
|
|
return std::make_pair(value.value, value.peer.value);
|
2018-01-14 16:02:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2017-09-26 11:49:16 +00:00
|
|
|
class PeerData;
|
|
|
|
class UserData;
|
|
|
|
class ChatData;
|
|
|
|
class ChannelData;
|
2019-01-04 11:09:48 +00:00
|
|
|
class BotCommand;
|
|
|
|
struct BotInfo;
|
|
|
|
|
|
|
|
namespace Data {
|
2019-04-15 11:54:03 +00:00
|
|
|
class Folder;
|
2019-01-04 11:09:48 +00:00
|
|
|
} // namespace Data
|
2017-09-26 11:49:16 +00:00
|
|
|
|
2019-04-15 11:54:03 +00:00
|
|
|
using FolderId = int32;
|
2020-02-07 09:43:12 +00:00
|
|
|
using FilterId = int32;
|
2017-09-26 11:49:16 +00:00
|
|
|
using MsgId = int32;
|
|
|
|
constexpr auto StartClientMsgId = MsgId(-0x7FFFFFFF);
|
|
|
|
constexpr auto EndClientMsgId = MsgId(-0x40000000);
|
|
|
|
constexpr auto ShowAtTheEndMsgId = MsgId(-0x40000000);
|
|
|
|
constexpr auto SwitchAtTopMsgId = MsgId(-0x3FFFFFFF);
|
|
|
|
constexpr auto ShowAtProfileMsgId = MsgId(-0x3FFFFFFE);
|
2021-02-15 17:37:22 +00:00
|
|
|
constexpr auto ShowAndStartBotMsgId = MsgId(-0x3FFFFFFD);
|
|
|
|
constexpr auto ShowAtGameShareMsgId = MsgId(-0x3FFFFFFC);
|
|
|
|
constexpr auto ShowForChooseMessagesMsgId = MsgId(-0x3FFFFFFB);
|
2017-09-26 11:49:16 +00:00
|
|
|
constexpr auto ServerMaxMsgId = MsgId(0x3FFFFFFF);
|
|
|
|
constexpr auto ShowAtUnreadMsgId = MsgId(0);
|
|
|
|
constexpr inline bool IsClientMsgId(MsgId id) {
|
|
|
|
return (id >= StartClientMsgId && id < EndClientMsgId);
|
|
|
|
}
|
|
|
|
constexpr inline bool IsServerMsgId(MsgId id) {
|
|
|
|
return (id > 0 && id < ServerMaxMsgId);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct MsgRange {
|
|
|
|
MsgRange() = default;
|
|
|
|
MsgRange(MsgId from, MsgId till) : from(from), till(till) {
|
|
|
|
}
|
|
|
|
|
|
|
|
MsgId from = 0;
|
|
|
|
MsgId till = 0;
|
|
|
|
};
|
|
|
|
inline bool operator==(const MsgRange &a, const MsgRange &b) {
|
|
|
|
return (a.from == b.from) && (a.till == b.till);
|
|
|
|
}
|
|
|
|
inline bool operator!=(const MsgRange &a, const MsgRange &b) {
|
|
|
|
return !(a == b);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct FullMsgId {
|
2018-01-09 17:08:31 +00:00
|
|
|
constexpr FullMsgId() = default;
|
2021-04-01 21:04:10 +00:00
|
|
|
constexpr FullMsgId(ChannelId channel, MsgId msg)
|
|
|
|
: channel(channel), msg(msg) {
|
2017-09-26 11:49:16 +00:00
|
|
|
}
|
2018-01-09 17:08:31 +00:00
|
|
|
|
2017-09-26 11:49:16 +00:00
|
|
|
explicit operator bool() const {
|
|
|
|
return msg != 0;
|
|
|
|
}
|
2018-01-09 17:08:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
inline constexpr bool operator<(const FullMsgId &other) const {
|
|
|
|
if (channel < other.channel) {
|
|
|
|
return true;
|
|
|
|
} else if (channel > other.channel) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return msg < other.msg;
|
|
|
|
}
|
|
|
|
inline constexpr bool operator>(const FullMsgId &other) const {
|
|
|
|
return other < *this;
|
|
|
|
}
|
|
|
|
inline constexpr bool operator<=(const FullMsgId &other) const {
|
|
|
|
return !(other < *this);
|
|
|
|
}
|
|
|
|
inline constexpr bool operator>=(const FullMsgId &other) const {
|
|
|
|
return !(*this < other);
|
|
|
|
}
|
|
|
|
inline constexpr bool operator==(const FullMsgId &other) const {
|
|
|
|
return (channel == other.channel) && (msg == other.msg);
|
|
|
|
}
|
|
|
|
inline constexpr bool operator!=(const FullMsgId &other) const {
|
|
|
|
return !(*this == other);
|
|
|
|
}
|
|
|
|
|
2017-09-26 11:49:16 +00:00
|
|
|
ChannelId channel = NoChannel;
|
|
|
|
MsgId msg = 0;
|
2018-01-09 17:08:31 +00:00
|
|
|
|
2017-09-26 11:49:16 +00:00
|
|
|
};
|
|
|
|
|
2018-07-09 18:13:48 +00:00
|
|
|
Q_DECLARE_METATYPE(FullMsgId);
|
|
|
|
|
2017-12-06 10:13:38 +00:00
|
|
|
using MessageIdsList = std::vector<FullMsgId>;
|
|
|
|
|
2018-12-17 08:16:06 +00:00
|
|
|
PeerId PeerFromMessage(const MTPmessage &message);
|
|
|
|
MTPDmessage::Flags FlagsFromMessage(const MTPmessage &message);
|
|
|
|
MsgId IdFromMessage(const MTPmessage &message);
|
|
|
|
TimeId DateFromMessage(const MTPmessage &message);
|
2017-09-26 11:49:16 +00:00
|
|
|
|
|
|
|
class DocumentData;
|
|
|
|
class PhotoData;
|
|
|
|
struct WebPageData;
|
|
|
|
struct GameData;
|
2018-12-18 05:43:11 +00:00
|
|
|
struct PollData;
|
2017-09-26 11:49:16 +00:00
|
|
|
|
|
|
|
class AudioMsgId;
|
|
|
|
class PhotoClickHandler;
|
|
|
|
class PhotoOpenClickHandler;
|
|
|
|
class PhotoSaveClickHandler;
|
|
|
|
class PhotoCancelClickHandler;
|
|
|
|
class DocumentClickHandler;
|
|
|
|
class DocumentSaveClickHandler;
|
|
|
|
class DocumentOpenClickHandler;
|
|
|
|
class DocumentCancelClickHandler;
|
2019-01-29 16:26:19 +00:00
|
|
|
class DocumentWrappedClickHandler;
|
2017-09-26 11:49:16 +00:00
|
|
|
class VoiceSeekClickHandler;
|
|
|
|
|
|
|
|
using PhotoId = uint64;
|
|
|
|
using VideoId = uint64;
|
|
|
|
using AudioId = uint64;
|
|
|
|
using DocumentId = uint64;
|
|
|
|
using WebPageId = uint64;
|
|
|
|
using GameId = uint64;
|
2018-12-18 05:43:11 +00:00
|
|
|
using PollId = uint64;
|
2019-01-16 12:25:29 +00:00
|
|
|
using WallPaperId = uint64;
|
2017-09-26 11:49:16 +00:00
|
|
|
constexpr auto CancelledWebPageId = WebPageId(0xFFFFFFFFFFFFFFFFULL);
|
|
|
|
|
2020-08-26 13:28:56 +00:00
|
|
|
struct PreparedPhotoThumb {
|
|
|
|
QImage image;
|
|
|
|
QByteArray bytes;
|
|
|
|
};
|
|
|
|
using PreparedPhotoThumbs = base::flat_map<char, PreparedPhotoThumb>;
|
2017-09-26 11:49:16 +00:00
|
|
|
|
|
|
|
// [0] == -1 -- counting, [0] == -2 -- could not count
|
2018-03-09 20:48:47 +00:00
|
|
|
using VoiceWaveform = QVector<signed char>;
|
2017-09-26 11:49:16 +00:00
|
|
|
|
|
|
|
enum LocationType {
|
|
|
|
UnknownFileLocation = 0,
|
|
|
|
// 1, 2, etc are used as "version" value in mediaKey() method.
|
|
|
|
|
|
|
|
DocumentFileLocation = 0x4e45abe9, // mtpc_inputDocumentFileLocation
|
|
|
|
AudioFileLocation = 0x74dc404d, // mtpc_inputAudioFileLocation
|
|
|
|
VideoFileLocation = 0x3d0364ec, // mtpc_inputVideoFileLocation
|
2018-03-25 11:37:57 +00:00
|
|
|
SecureFileLocation = 0xcbc7ee28, // mtpc_inputSecureFileLocation
|
2017-09-26 11:49:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum FileStatus {
|
|
|
|
FileDownloadFailed = -2,
|
|
|
|
FileUploadFailed = -1,
|
|
|
|
FileReady = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Don't change the values. This type is used for serialization.
|
|
|
|
enum DocumentType {
|
|
|
|
FileDocument = 0,
|
|
|
|
VideoDocument = 1,
|
|
|
|
SongDocument = 2,
|
|
|
|
StickerDocument = 3,
|
|
|
|
AnimatedDocument = 4,
|
|
|
|
VoiceDocument = 5,
|
|
|
|
RoundVideoDocument = 6,
|
2019-01-16 12:25:29 +00:00
|
|
|
WallPaperDocument = 7,
|
2017-09-26 11:49:16 +00:00
|
|
|
};
|
|
|
|
|
2020-07-15 07:49:54 +00:00
|
|
|
inline constexpr auto kStickerSideSize = 512;
|
2021-02-16 15:23:16 +00:00
|
|
|
[[nodiscard]] bool GoodStickerDimensions(int width, int height);
|
2020-07-15 07:49:54 +00:00
|
|
|
|
2017-09-26 11:49:16 +00:00
|
|
|
using MediaKey = QPair<uint64, uint64>;
|
|
|
|
|
|
|
|
class AudioMsgId {
|
|
|
|
public:
|
|
|
|
enum class Type {
|
|
|
|
Unknown,
|
|
|
|
Voice,
|
|
|
|
Song,
|
|
|
|
Video,
|
|
|
|
};
|
|
|
|
|
|
|
|
AudioMsgId() = default;
|
|
|
|
AudioMsgId(
|
2019-03-01 12:22:47 +00:00
|
|
|
not_null<DocumentData*> audio,
|
|
|
|
FullMsgId msgId,
|
2019-02-28 21:03:25 +00:00
|
|
|
uint32 externalPlayId = 0)
|
2017-09-26 11:49:16 +00:00
|
|
|
: _audio(audio)
|
|
|
|
, _contextId(msgId)
|
2019-02-28 21:03:25 +00:00
|
|
|
, _externalPlayId(externalPlayId) {
|
2017-09-26 11:49:16 +00:00
|
|
|
setTypeFromAudio();
|
|
|
|
}
|
2019-02-28 21:03:25 +00:00
|
|
|
|
|
|
|
[[nodiscard]] static uint32 CreateExternalPlayId();
|
2019-02-13 18:10:18 +00:00
|
|
|
[[nodiscard]] static AudioMsgId ForVideo();
|
2017-09-26 11:49:16 +00:00
|
|
|
|
2019-03-01 12:22:47 +00:00
|
|
|
[[nodiscard]] Type type() const {
|
2017-09-26 11:49:16 +00:00
|
|
|
return _type;
|
|
|
|
}
|
2019-03-01 12:22:47 +00:00
|
|
|
[[nodiscard]] DocumentData *audio() const {
|
2017-09-26 11:49:16 +00:00
|
|
|
return _audio;
|
|
|
|
}
|
2019-03-01 12:22:47 +00:00
|
|
|
[[nodiscard]] FullMsgId contextId() const {
|
2017-09-26 11:49:16 +00:00
|
|
|
return _contextId;
|
|
|
|
}
|
2019-03-01 12:22:47 +00:00
|
|
|
[[nodiscard]] uint32 externalPlayId() const {
|
2019-02-28 21:03:25 +00:00
|
|
|
return _externalPlayId;
|
2017-09-26 11:49:16 +00:00
|
|
|
}
|
2019-03-01 12:22:47 +00:00
|
|
|
[[nodiscard]] explicit operator bool() const {
|
|
|
|
return (_audio != nullptr) || (_externalPlayId != 0);
|
2017-09-26 11:49:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void setTypeFromAudio();
|
|
|
|
|
|
|
|
DocumentData *_audio = nullptr;
|
|
|
|
Type _type = Type::Unknown;
|
|
|
|
FullMsgId _contextId;
|
2019-02-28 21:03:25 +00:00
|
|
|
uint32 _externalPlayId = 0;
|
2017-09-26 11:49:16 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
inline bool operator<(const AudioMsgId &a, const AudioMsgId &b) {
|
|
|
|
if (quintptr(a.audio()) < quintptr(b.audio())) {
|
|
|
|
return true;
|
|
|
|
} else if (quintptr(b.audio()) < quintptr(a.audio())) {
|
|
|
|
return false;
|
|
|
|
} else if (a.contextId() < b.contextId()) {
|
|
|
|
return true;
|
|
|
|
} else if (b.contextId() < a.contextId()) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-02-28 21:03:25 +00:00
|
|
|
return (a.externalPlayId() < b.externalPlayId());
|
2017-09-26 11:49:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator==(const AudioMsgId &a, const AudioMsgId &b) {
|
|
|
|
return (a.audio() == b.audio())
|
|
|
|
&& (a.contextId() == b.contextId())
|
2019-02-28 21:03:25 +00:00
|
|
|
&& (a.externalPlayId() == b.externalPlayId());
|
2017-09-26 11:49:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator!=(const AudioMsgId &a, const AudioMsgId &b) {
|
|
|
|
return !(a == b);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct MessageCursor {
|
|
|
|
MessageCursor() = default;
|
|
|
|
MessageCursor(int position, int anchor, int scroll)
|
2018-05-21 21:31:46 +00:00
|
|
|
: position(position)
|
|
|
|
, anchor(anchor)
|
|
|
|
, scroll(scroll) {
|
2017-09-26 11:49:16 +00:00
|
|
|
}
|
2018-05-21 21:31:46 +00:00
|
|
|
MessageCursor(not_null<const Ui::InputField*> field) {
|
|
|
|
fillFrom(field);
|
2017-09-26 11:49:16 +00:00
|
|
|
}
|
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
void fillFrom(not_null<const Ui::InputField*> field);
|
|
|
|
void applyTo(not_null<Ui::InputField*> field);
|
2017-09-26 11:49:16 +00:00
|
|
|
|
|
|
|
int position = 0;
|
|
|
|
int anchor = 0;
|
|
|
|
int scroll = QFIXED_MAX;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
inline bool operator==(
|
|
|
|
const MessageCursor &a,
|
|
|
|
const MessageCursor &b) {
|
|
|
|
return (a.position == b.position)
|
|
|
|
&& (a.anchor == b.anchor)
|
|
|
|
&& (a.scroll == b.scroll);
|
|
|
|
}
|
|
|
|
|
2020-11-17 15:20:22 +00:00
|
|
|
inline bool operator!=(
|
|
|
|
const MessageCursor &a,
|
|
|
|
const MessageCursor &b) {
|
|
|
|
return !(a == b);
|
|
|
|
}
|
|
|
|
|
2017-12-18 13:13:41 +00:00
|
|
|
class FileClickHandler : public LeftButtonClickHandler {
|
|
|
|
public:
|
2020-06-09 09:36:40 +00:00
|
|
|
FileClickHandler(
|
|
|
|
not_null<Main::Session*> session,
|
|
|
|
FullMsgId context)
|
|
|
|
: _session(session)
|
|
|
|
, _context(context) {
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] Main::Session &session() const {
|
|
|
|
return *_session;
|
2017-12-18 13:13:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void setMessageId(FullMsgId context) {
|
|
|
|
_context = context;
|
|
|
|
}
|
|
|
|
|
2020-05-04 13:38:49 +00:00
|
|
|
[[nodiscard]] FullMsgId context() const {
|
2017-12-18 13:13:41 +00:00
|
|
|
return _context;
|
|
|
|
}
|
|
|
|
|
2017-12-25 14:17:00 +00:00
|
|
|
protected:
|
|
|
|
HistoryItem *getActionItem() const;
|
|
|
|
|
2017-12-18 13:13:41 +00:00
|
|
|
private:
|
2020-06-09 09:36:40 +00:00
|
|
|
const not_null<Main::Session*> _session;
|
2017-12-18 13:13:41 +00:00
|
|
|
FullMsgId _context;
|
|
|
|
|
|
|
|
};
|