diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 93553758e..36351cc47 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -259,6 +259,8 @@ add_executable(Kepka WIN32 MACOSX_BUNDLE SourceFiles/data/data_abstract_structure.cpp SourceFiles/data/data_drafts.cpp + SourceFiles/data/data_game.cpp + SourceFiles/data/data_photo.cpp SourceFiles/dialogs/dialogs_indexed_list.cpp SourceFiles/dialogs/dialogs_inner_widget.cpp diff --git a/Telegram/SourceFiles/base/qthelp_regex.h b/Telegram/SourceFiles/base/qthelp_regex.h index 2bb90f4aa..2e34f9979 100644 --- a/Telegram/SourceFiles/base/qthelp_regex.h +++ b/Telegram/SourceFiles/base/qthelp_regex.h @@ -69,7 +69,10 @@ enum class RegExOption { InvertedGreediness = QRegularExpression::InvertedGreedinessOption, DontCapture = QRegularExpression::DontCaptureOption, UseUnicodeProperties = QRegularExpression::UseUnicodePropertiesOption, -#ifndef OS_MAC_OLD +#if (!defined(OS_MAC_OLD) && ((QT_VERSION < QT_VERSION_CHECK(5, 12, 0)) && (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)))) + /// @note These flags are introduced since Qt 5.4 and become deprecated in Qt 5.12, so we must + /// drop it conditionally. + /// See https://doc.qt.io/QT-5/qregularexpression.html#PatternOption-enum for details. OptimizeOnFirstUsage = QRegularExpression::OptimizeOnFirstUsageOption, DontAutomaticallyOptimize = QRegularExpression::DontAutomaticallyOptimizeOption, #endif // OS_MAC_OLD diff --git a/Telegram/SourceFiles/boxes/edit_participant_box.h b/Telegram/SourceFiles/boxes/edit_participant_box.h index 913140367..94481c855 100644 --- a/Telegram/SourceFiles/boxes/edit_participant_box.h +++ b/Telegram/SourceFiles/boxes/edit_participant_box.h @@ -23,6 +23,10 @@ #pragma once #include "boxes/abstract_box.h" +#include "core/basic_types.h" +#include "data/data_types.h" + +#include "structs.h" // temporarily. (ChannelData namespace Ui { class FlatLabel; diff --git a/Telegram/SourceFiles/boxes/passcode_box.h b/Telegram/SourceFiles/boxes/passcode_box.h index 214717fba..91ebcd655 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.h +++ b/Telegram/SourceFiles/boxes/passcode_box.h @@ -23,6 +23,7 @@ #pragma once #include "boxes/abstract_box.h" +#include "ui/text/text.h" namespace Ui { class InputField; diff --git a/Telegram/SourceFiles/boxes/photo_crop_box.h b/Telegram/SourceFiles/boxes/photo_crop_box.h index 6f9329ea1..cc6a6fef4 100644 --- a/Telegram/SourceFiles/boxes/photo_crop_box.h +++ b/Telegram/SourceFiles/boxes/photo_crop_box.h @@ -24,6 +24,8 @@ #include "boxes/abstract_box.h" +#include "structs.h" // temporarily, need PeerId. + class PhotoCropBox : public BoxContent { Q_OBJECT diff --git a/Telegram/SourceFiles/boxes/share_box.h b/Telegram/SourceFiles/boxes/share_box.h index d02948f85..2f294ff55 100644 --- a/Telegram/SourceFiles/boxes/share_box.h +++ b/Telegram/SourceFiles/boxes/share_box.h @@ -25,6 +25,9 @@ #include "base/observer.h" #include "boxes/abstract_box.h" #include "ui/effects/round_checkbox.h" +#include "ui/text/text.h" + +#include "structs.h" // temporarily: FullMsgId, CharData namespace Dialogs { class Row; diff --git a/Telegram/SourceFiles/boxes/username_box.h b/Telegram/SourceFiles/boxes/username_box.h index e50d735d2..c306c4ab7 100644 --- a/Telegram/SourceFiles/boxes/username_box.h +++ b/Telegram/SourceFiles/boxes/username_box.h @@ -23,6 +23,7 @@ #pragma once #include "boxes/abstract_box.h" +#include "ui/text/text.h" namespace Ui { class UsernameInput; diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h new file mode 100644 index 000000000..fcd1ae8da --- /dev/null +++ b/Telegram/SourceFiles/data/data_document.h @@ -0,0 +1,324 @@ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// It is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2019- Kepka Contributors, https://github.com/procxx +// +/// @file data/data_document.h Telegram Documents data_type. + +#pragma once + +#include +#include +#include +#include + +#include "data/data_types.h" +#include "ui/images.h" // StorageKey, ImagePtr, StorageImageLocation + +#include "scheme.h" + +class HistoryItem; + +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 +}; + + +using MediaKey = QPair; + +inline quint64 mediaMix32To64(qint32 a, qint32 b) { + return (quint64(*reinterpret_cast(&a)) << 32) | quint64(*reinterpret_cast(&b)); +} + +// Old method, should not be used anymore. +// inline MediaKey mediaKey(LocationType type, qint32 dc, const quint64 &id) { +// return MediaKey(mediaMix32To64(type, dc), id); +//} +// New method when version was introduced, type is not relevant anymore (all files are Documents). +inline MediaKey mediaKey(LocationType type, qint32 dc, const quint64 &id, qint32 version) { + return (version > 0) ? MediaKey(mediaMix32To64(version, dc), id) : MediaKey(mediaMix32To64(type, dc), id); +} + +inline StorageKey mediaKey(const MTPDfileLocation &location) { + return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v); +} + +struct DocumentAdditionalData { + virtual ~DocumentAdditionalData() = default; +}; + +struct StickerData : public DocumentAdditionalData { + ImagePtr img; + QString alt; + + MTPInputStickerSet set = MTP_inputStickerSetEmpty(); + bool setInstalled() const; + + StorageImageLocation loc; // doc thumb location +}; + +struct SongData : public DocumentAdditionalData { + qint32 duration = 0; + QString title, performer; +}; + +typedef QVector VoiceWaveform; // [0] == -1 -- counting, [0] == -2 -- could not count +struct VoiceData : public DocumentAdditionalData { + ~VoiceData(); + + int duration = 0; + VoiceWaveform waveform; + char wavemax = 0; +}; + +VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit); +QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform); + +// 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, +}; + +enum FileStatus { + FileDownloadFailed = -2, + FileUploadFailed = -1, + FileUploading = 0, + FileReady = 1, +}; + +namespace Serialize { +class Document; +} // namespace Serialize + +/// @brief Any document object in chat. +class DocumentData { +public: + static DocumentData *create(DocumentId id); + static DocumentData *create(DocumentId id, qint32 dc, quint64 accessHash, qint32 version, + const QVector &attributes); + static DocumentData *create(DocumentId id, const QString &url, const QVector &attributes); + + void setattributes(const QVector &attributes); + + void automaticLoad(const HistoryItem *item); // auto load sticker or video + void automaticLoadSettingsChanged(); + + enum FilePathResolveType { + FilePathResolveCached, + FilePathResolveChecked, + FilePathResolveSaveFromData, + FilePathResolveSaveFromDataSilent, + }; + bool loaded(FilePathResolveType type = FilePathResolveCached) const; + bool loading() const; + QString loadingFilePath() const; + bool displayLoading() const; + void save(const QString &toFile, ActionOnLoad action = ActionOnLoadNone, const FullMsgId &actionMsgId = FullMsgId(), + LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal, bool autoLoading = false); + void cancel(); + double progress() const; + qint32 loadOffset() const; + bool uploading() const; + + QByteArray data() const; + const FileLocation &location(bool check = false) const; + void setLocation(const FileLocation &loc); + + QString filepath(FilePathResolveType type = FilePathResolveCached, bool forceSavingAs = false) const; + + bool saveToCache() const; + + void performActionOnLoad(); + + void forget(); + ImagePtr makeReplyPreview(); + + StickerData *sticker() { + return (type == StickerDocument) ? static_cast(_additional.get()) : nullptr; + } + void checkSticker() { + StickerData *s = sticker(); + if (!s) return; + + automaticLoad(nullptr); + if (s->img->isNull() && loaded()) { + if (_data.isEmpty()) { + const FileLocation &loc(location(true)); + if (loc.accessEnable()) { + s->img = ImagePtr(loc.name()); + loc.accessDisable(); + } + } else { + s->img = ImagePtr(_data); + } + } + } + SongData *song() { + return (type == SongDocument) ? static_cast(_additional.get()) : nullptr; + } + const SongData *song() const { + return const_cast(this)->song(); + } + VoiceData *voice() { + return (type == VoiceDocument) ? static_cast(_additional.get()) : nullptr; + } + const VoiceData *voice() const { + return const_cast(this)->voice(); + } + bool isRoundVideo() const { + return (type == RoundVideoDocument); + } + bool isAnimation() const { + return (type == AnimatedDocument) || isRoundVideo() || hasMimeType(qstr("image/gif")); + } + bool isGifv() const { + return (type == AnimatedDocument) && hasMimeType(qstr("video/mp4")); + } + bool isTheme() const { + return _filename.endsWith(qstr(".tdesktop-theme"), Qt::CaseInsensitive) || + _filename.endsWith(qstr(".tdesktop-palette"), Qt::CaseInsensitive); + } + bool tryPlaySong() const { + return (song() != nullptr) || _mimeString.startsWith(qstr("audio/"), Qt::CaseInsensitive); + } + bool isMusic() const { + if (auto s = song()) { + return (s->duration > 0); + } + return false; + } + bool isVideo() const { + return (type == VideoDocument); + } + qint32 duration() const { + return (isAnimation() || isVideo()) ? _duration : -1; + } + bool isImage() const { + return !isAnimation() && !isVideo() && (_duration > 0); + } + void recountIsImage(); + void setData(const QByteArray &data) { + _data = data; + } + + bool setRemoteVersion(qint32 version); // Returns true if version has changed. + void setRemoteLocation(qint32 dc, quint64 access); + void setContentUrl(const QString &url); + bool hasRemoteLocation() const { + return (_dc != 0 && _access != 0); + } + bool isValid() const { + return hasRemoteLocation() || !_url.isEmpty(); + } + MTPInputDocument mtpInput() const { + if (_access) { + return MTP_inputDocument(MTP_long(id), MTP_long(_access)); + } + return MTP_inputDocumentEmpty(); + } + + // When we have some client-side generated document + // (for example for displaying an external inline bot result) + // and it has downloaded data, we can collect that data from it + // to (this) received from the server "same" document. + void collectLocalData(DocumentData *local); + + QString filename() const { + return _filename; + } + QString mimeString() const { + return _mimeString; + } + bool hasMimeType(QLatin1String mime) const { + return !_mimeString.compare(mime, Qt::CaseInsensitive); + } + void setMimeString(const QString &mime) { + _mimeString = mime; + } + + + ~DocumentData(); + + DocumentId id = 0; + DocumentType type = FileDocument; + QSize dimensions; + qint32 date = 0; + ImagePtr thumb, replyPreview; + qint32 size = 0; + + FileStatus status = FileReady; + qint32 uploadOffset = 0; + + qint32 md5[8]; + + MediaKey mediaKey() const { + return ::mediaKey(locationType(), _dc, id, _version); + } + + static QString ComposeNameString(const QString &filename, const QString &songTitle, const QString &songPerformer); + QString composeNameString() const { + if (auto songData = song()) { + return ComposeNameString(_filename, songData->title, songData->performer); + } + return ComposeNameString(_filename, QString(), QString()); + } + +private: + DocumentData(DocumentId id, qint32 dc, quint64 accessHash, qint32 version, const QString &url, + const QVector &attributes); + + friend class Serialize::Document; + + LocationType locationType() const { + return voice() ? AudioFileLocation : (isVideo() ? VideoFileLocation : DocumentFileLocation); + } + + // Two types of location: from MTProto by dc+access+version or from web by url + qint32 _dc = 0; + quint64 _access = 0; + qint32 _version = 0; + QString _url; + QString _filename; + QString _mimeString; + + + FileLocation _location; + QByteArray _data; + std::unique_ptr _additional; + qint32 _duration = -1; + + ActionOnLoad _actionOnLoad = ActionOnLoadNone; + FullMsgId _actionOnLoadMsgId; + mutable FileLoader *_loader = nullptr; + + void notifyLayoutChanged() const; + + void destroyLoaderDelayed(mtpFileLoader *newValue = nullptr) const; +}; diff --git a/Telegram/SourceFiles/data/data_game.cpp b/Telegram/SourceFiles/data/data_game.cpp new file mode 100644 index 000000000..ad8dab296 --- /dev/null +++ b/Telegram/SourceFiles/data/data_game.cpp @@ -0,0 +1,43 @@ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// It is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// + +#include "data_game.h" +#include "data/data_photo.h" +#include "data/data_document.h" + +GameData::GameData(const GameId &id, const quint64 &accessHash, const QString &shortName, const QString &title, + const QString &description, PhotoData *photo, DocumentData *document) + : id(id) + , accessHash(accessHash) + , shortName(shortName) + , title(title) + , description(description) + , photo(photo) + , document(document) {} + +void GameData::forget() { + if (document) document->forget(); + if (photo) photo->forget(); +} + + + diff --git a/Telegram/SourceFiles/data/data_game.h b/Telegram/SourceFiles/data/data_game.h new file mode 100644 index 000000000..83835aac9 --- /dev/null +++ b/Telegram/SourceFiles/data/data_game.h @@ -0,0 +1,46 @@ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// It is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2019- Kepka Contributors, https://github.com/procxx +// +/// @file data/data_game.h Data_type for Telegram Games. + +#pragma once + +#include "data/data_types.h" + +class PhotoData; +class DocumentData; + +struct GameData { + GameData(const GameId &id) + : id(id) {} + GameData(const GameId &id, const quint64 &accessHash, const QString &shortName, const QString &title, + const QString &description, PhotoData *photo, DocumentData *document); + + void forget(); + + GameId id = 0; + quint64 accessHash = 0; + QString shortName; + QString title; + QString description; + PhotoData *photo = nullptr; + DocumentData *document = nullptr; +}; diff --git a/Telegram/SourceFiles/data/data_photo.cpp b/Telegram/SourceFiles/data/data_photo.cpp new file mode 100644 index 000000000..0e47c4b2d --- /dev/null +++ b/Telegram/SourceFiles/data/data_photo.cpp @@ -0,0 +1,134 @@ +#include "data/data_photo.h" +#include "messenger.h" // Messenger:: +#include "app.h" // App:: +#include "facades.h" // Notify::historyItemLayoutChanged +#include "history/history_media.h" // HistoryMedia definition +#include "history/history_media_types.h" // HistoryPhoto +#include "mainwidget.h" // MainWidget + +PhotoData::PhotoData(const PhotoId &id, const quint64 &access, qint32 date, const ImagePtr &thumb, + const ImagePtr &medium, const ImagePtr &full) + : id(id) + , access(access) + , date(date) + , thumb(thumb) + , medium(medium) + , full(full) {} + +void PhotoData::automaticLoad(const HistoryItem *item) { + full->automaticLoad(item); +} + +void PhotoData::automaticLoadSettingsChanged() { + full->automaticLoadSettingsChanged(); +} + +void PhotoData::download() { + full->loadEvenCancelled(); + notifyLayoutChanged(); +} + +bool PhotoData::loaded() const { + bool wasLoading = loading(); + if (full->loaded()) { + if (wasLoading) { + notifyLayoutChanged(); + } + return true; + } + return false; +} + +bool PhotoData::loading() const { + return full->loading(); +} + +bool PhotoData::displayLoading() const { + return full->loading() ? full->displayLoading() : uploading(); +} + +void PhotoData::cancel() { + full->cancel(); + notifyLayoutChanged(); +} + +void PhotoData::notifyLayoutChanged() const { + auto &items = App::photoItems(); + auto i = items.constFind(const_cast(this)); + if (i != items.cend()) { + for_const (auto item, i.value()) { Notify::historyItemLayoutChanged(item); } + } +} + +double PhotoData::progress() const { + if (uploading()) { + if (uploadingData->size > 0) { + return double(uploadingData->offset) / uploadingData->size; + } + return 0; + } + return full->progress(); +} + +qint32 PhotoData::loadOffset() const { + return full->loadOffset(); +} + +bool PhotoData::uploading() const { + return !!uploadingData; +} + +void PhotoData::forget() { + thumb->forget(); + replyPreview->forget(); + medium->forget(); + full->forget(); +} + +ImagePtr PhotoData::makeReplyPreview() { + if (replyPreview->isNull() && !thumb->isNull()) { + if (thumb->loaded()) { + int w = thumb->width(), h = thumb->height(); + if (w <= 0) w = 1; + if (h <= 0) h = 1; + replyPreview = + ImagePtr(w > h ? thumb->pix(w * st::msgReplyBarSize.height() / h, st::msgReplyBarSize.height()) : + thumb->pix(st::msgReplyBarSize.height()), + "PNG"); + } else { + thumb->load(); + } + } + return replyPreview; +} + +void PhotoOpenClickHandler::onClickImpl() const { + Messenger::Instance().showPhoto(this, App::hoveredLinkItem() ? App::hoveredLinkItem() : App::contextItem()); +} + +void PhotoSaveClickHandler::onClickImpl() const { + auto data = photo(); + if (!data->date) return; + + data->download(); +} + +void PhotoCancelClickHandler::onClickImpl() const { + auto data = photo(); + if (!data->date) return; + + if (data->uploading()) { + if (auto item = + App::hoveredLinkItem() ? App::hoveredLinkItem() : (App::contextItem() ? App::contextItem() : nullptr)) { + if (auto media = item->getMedia()) { + if (media->type() == MediaTypePhoto && static_cast(media)->photo() == data) { + App::contextItem(item); + App::main()->cancelUploadLayer(); + } + } + } + } else { + data->cancel(); + } +} + diff --git a/Telegram/SourceFiles/data/data_photo.h b/Telegram/SourceFiles/data/data_photo.h new file mode 100644 index 000000000..c445f8206 --- /dev/null +++ b/Telegram/SourceFiles/data/data_photo.h @@ -0,0 +1,111 @@ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// It is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx +// +#pragma once +#include // qint64, quint64 +#include "core/click_handler.h" // LeftButtonClickHandler +#include "ui/images.h" // ImagePtr + +using PhotoId = quint64; + +class PhotoData { +public: + PhotoData(const PhotoId &id, const quint64 &access = 0, qint32 date = 0, const ImagePtr &thumb = ImagePtr(), + const ImagePtr &medium = ImagePtr(), const ImagePtr &full = ImagePtr()); + + void automaticLoad(const HistoryItem *item); + void automaticLoadSettingsChanged(); + + void download(); + bool loaded() const; + bool loading() const; + bool displayLoading() const; + void cancel(); + double progress() const; + qint32 loadOffset() const; + bool uploading() const; + + void forget(); + ImagePtr makeReplyPreview(); + + PhotoId id; + quint64 access; + qint32 date; + ImagePtr thumb, replyPreview; + ImagePtr medium; + ImagePtr full; + + PeerData *peer = nullptr; // for chat and channel photos connection + // geo, caption + + struct UploadingData { + UploadingData(int size) + : size(size) {} + int offset = 0; + int size = 0; + }; + std::unique_ptr uploadingData; + +private: + void notifyLayoutChanged() const; +}; + +class PhotoClickHandler : public LeftButtonClickHandler { +public: + PhotoClickHandler(not_null photo, PeerData *peer = nullptr) + : _photo(photo) + , _peer(peer) {} + not_null photo() const { + return _photo; + } + PeerData *peer() const { + return _peer; + } + +private: + not_null _photo; + PeerData *_peer; +}; + +class PhotoOpenClickHandler : public PhotoClickHandler { +public: + using PhotoClickHandler::PhotoClickHandler; + +protected: + void onClickImpl() const override; +}; + +class PhotoSaveClickHandler : public PhotoClickHandler { +public: + using PhotoClickHandler::PhotoClickHandler; + +protected: + void onClickImpl() const override; +}; + +class PhotoCancelClickHandler : public PhotoClickHandler { +public: + using PhotoClickHandler::PhotoClickHandler; + +protected: + void onClickImpl() const override; +}; diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h new file mode 100644 index 000000000..cbe614cf6 --- /dev/null +++ b/Telegram/SourceFiles/data/data_types.h @@ -0,0 +1,95 @@ +// +// This file is part of Kepka, +// an unofficial desktop version of Telegram messaging app, +// see https://github.com/procxx/kepka +// +// Kepka is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// It is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// In addition, as a special exception, the copyright holders give permission +// to link the code of portions of this program with the OpenSSL library. +// +// Full license: https://github.com/procxx/kepka/blob/master/LICENSE +// Copyright (c) 2019- Kepka Contributors, https://github.com/procxx +// +/// @file data/data_types.h Common types, functions for data_types. +#pragma once + +#include +#include +#include "core/utils.h" // TimeMs and stuff + +using VideoId = quint64; +using AudioId = quint64; +using DocumentId = quint64; +using WebPageId = quint64; +using GameId = quint64; + +using PeerId = quint64; + +using MediaKey = QPair; + +enum ActionOnLoad { ActionOnLoadNone, ActionOnLoadOpen, ActionOnLoadOpenWith, ActionOnLoadPlayInline }; + +typedef qint32 UserId; +typedef qint32 ChatId; +typedef qint32 ChannelId; +constexpr ChannelId NoChannel = 0; + +typedef qint32 MsgId; + +/// @defgroup data_types.Constants +/// @{ + +constexpr const MsgId StartClientMsgId = -0x7FFFFFFF; +constexpr const MsgId EndClientMsgId = -0x40000000; +constexpr const MsgId ShowAtTheEndMsgId = -0x40000000; +constexpr const MsgId SwitchAtTopMsgId = -0x3FFFFFFF; +constexpr const MsgId ShowAtProfileMsgId = -0x3FFFFFFE; +constexpr const MsgId ShowAndStartBotMsgId = -0x3FFFFFD; +constexpr const MsgId ShowAtGameShareMsgId = -0x3FFFFFC; +constexpr const MsgId ServerMaxMsgId = 0x3FFFFFFF; +constexpr const MsgId ShowAtUnreadMsgId = 0; + +/// @} + +struct FullMsgId { + FullMsgId() = default; + FullMsgId(ChannelId channel, MsgId msg) + : channel(channel) + , msg(msg) {} + ChannelId channel = NoChannel; + MsgId msg = 0; +}; + +/// @brief Represents user continuous action. +struct SendAction { + enum class Type { + Typing, + RecordVideo, + UploadVideo, + RecordVoice, + UploadVoice, + RecordRound, + UploadRound, + UploadPhoto, + UploadFile, + ChooseLocation, + ChooseContact, + PlayGame, + }; + SendAction(Type type, TimeMs until, int progress = 0) + : type(type) + , until(until) + , progress(progress) {} + Type type; + TimeMs until; + int progress; +}; diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 6bbf6a8cb..ab9c1764d 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -28,6 +28,10 @@ #include "dialogs/dialogs_common.h" // For Dialogs::Mode #include "ui/animation.h" // For BasicAnimation #include "ui/effects/send_action_animations.h" // For SendActionAnimation +#include "ui/text/text.h" +#include "data/data_photo.h" +#include "data/data_game.h" +#include "structs.h" void HistoryInit(); diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 4faff6427..31d2e4206 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -24,9 +24,9 @@ #include "base/flags.h" #include "base/runtime_composer.h" +#include "core/basic_types.h" #include "core/click_handler.h" #include "history/history.h" -#include "structs.h" #include "ui/animation.h" #include "ui/text/text.h" @@ -40,6 +40,7 @@ struct RippleAnimation; } // namespace style class HistoryItem; +class History; class HistoryElement { public: diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp index 9d8f894c8..d6e17a0b4 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp @@ -22,7 +22,9 @@ // #include "inline_bots/inline_bot_result.h" +#include "app.h" #include "core/file_utilities.h" +#include "data/data_game.h" #include "inline_bots/inline_bot_layout_item.h" #include "inline_bots/inline_bot_send_data.h" #include "mainwidget.h" @@ -188,7 +190,9 @@ std::unique_ptr Result::create(quint64 queryId, const MTPBotInlineResult } } break; - default: { badAttachment = true; } break; + default: { + badAttachment = true; + } break; } if (badAttachment || !result->sendData || !result->sendData->isValid()) { diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.h b/Telegram/SourceFiles/inline_bots/inline_bot_result.h index 31eee198b..73855d475 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.h @@ -23,11 +23,17 @@ #pragma once #include "core/basic_types.h" -#include "structs.h" +#include "data/data_types.h" +#include "ui/images.h" +#include "scheme.h" class FileLoader; class History; class LocationCoords; +class DocumentData; +class PhotoData; + +struct GameData; namespace InlineBots { diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp index 13e8366d6..c704b895b 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp @@ -20,8 +20,9 @@ // Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org // Copyright (c) 2017- Kepka Contributors, https://github.com/procxx // -#include "inline_bots/inline_bot_send_data.h" #include "app.h" +#include "data/data_game.h" +#include "inline_bots/inline_bot_send_data.h" #include "inline_bots/inline_bot_result.h" #include "lang/lang_keys.h" #include "storage/localstorage.h" diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h index 51b7d8058..7f7a11078 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h @@ -23,10 +23,11 @@ #pragma once #include "core/basic_types.h" +#include "data/data_types.h" #include "history/history_location_manager.h" #include "mtproto/type_utils.h" -#include "structs.h" +struct GameData; class History; namespace InlineBots { diff --git a/Telegram/SourceFiles/lang/lang_instance.cpp b/Telegram/SourceFiles/lang/lang_instance.cpp index 5ca033295..ec385cd2f 100644 --- a/Telegram/SourceFiles/lang/lang_instance.cpp +++ b/Telegram/SourceFiles/lang/lang_instance.cpp @@ -273,7 +273,7 @@ void Instance::fillFromSerialized(const QByteArray &data) { qint32 version = 0; QString customFilePathAbsolute, customFilePathRelative; QByteArray customFileContent; - qint32 nonDefaultValuesCount = 0; + quint32 nonDefaultValuesCount = 0; stream >> id >> version; stream >> customFilePathAbsolute >> customFilePathRelative >> customFileContent; stream >> nonDefaultValuesCount; @@ -297,7 +297,7 @@ void Instance::fillFromSerialized(const QByteArray &data) { std::vector nonDefaultStrings; nonDefaultStrings.reserve(2 * nonDefaultValuesCount); - for (auto i = 0; i != nonDefaultValuesCount; ++i) { + for (size_t i = 0; i != nonDefaultValuesCount; ++i) { QByteArray key, value; stream >> key >> value; if (stream.status() != QDataStream::Ok) { @@ -315,7 +315,7 @@ void Instance::fillFromSerialized(const QByteArray &data) { _customFilePathRelative = customFilePathRelative; _customFileContent = customFileContent; LOG(("Lang Info: Loaded cached, keys: %1").arg(nonDefaultValuesCount)); - for (auto i = 0, count = nonDefaultValuesCount * 2; i != count; i += 2) { + for (size_t i = 0, count = nonDefaultValuesCount * 2; i != count; i += 2) { applyValue(nonDefaultStrings[i], nonDefaultStrings[i + 1]); } updatePluralRules(); diff --git a/Telegram/SourceFiles/layerwidget.h b/Telegram/SourceFiles/layerwidget.h index 868455b94..dee038308 100644 --- a/Telegram/SourceFiles/layerwidget.h +++ b/Telegram/SourceFiles/layerwidget.h @@ -24,10 +24,12 @@ #include -#include "structs.h" +// #include "structs.h" #include "ui/animation.h" #include "ui/twidget.h" +class PhotoData; + class BoxContent; namespace Window { diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index 61451911f..13a28b28a 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -23,6 +23,7 @@ #pragma once #include "core/single_timer.h" +#include "core/click_handler.h" #include "platform/platform_main_window.h" #include "platform/platform_specific.h" #include @@ -32,9 +33,12 @@ #include #include #include +#include #include "layerwidget.h" + #include "ui/twidget.h" +#include "ui/text/text_entity.h" class PasscodeWidget; class MainWidget; diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 0c58896d8..76e9696b4 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -27,6 +27,7 @@ #include "auth_session.h" #include "boxes/confirm_box.h" #include "core/file_utilities.h" +#include "data/data_document.h" #include "history/history_media_types.h" #include "inline_bots/inline_bot_layout_item.h" #include "lang/lang_keys.h" @@ -1156,132 +1157,6 @@ bool PtsWaiter::check(ChannelData *channel, qint32 pts, return !count; } -PhotoData::PhotoData(const PhotoId &id, const quint64 &access, qint32 date, const ImagePtr &thumb, - const ImagePtr &medium, const ImagePtr &full) - : id(id) - , access(access) - , date(date) - , thumb(thumb) - , medium(medium) - , full(full) {} - -void PhotoData::automaticLoad(const HistoryItem *item) { - full->automaticLoad(item); -} - -void PhotoData::automaticLoadSettingsChanged() { - full->automaticLoadSettingsChanged(); -} - -void PhotoData::download() { - full->loadEvenCancelled(); - notifyLayoutChanged(); -} - -bool PhotoData::loaded() const { - bool wasLoading = loading(); - if (full->loaded()) { - if (wasLoading) { - notifyLayoutChanged(); - } - return true; - } - return false; -} - -bool PhotoData::loading() const { - return full->loading(); -} - -bool PhotoData::displayLoading() const { - return full->loading() ? full->displayLoading() : uploading(); -} - -void PhotoData::cancel() { - full->cancel(); - notifyLayoutChanged(); -} - -void PhotoData::notifyLayoutChanged() const { - auto &items = App::photoItems(); - auto i = items.constFind(const_cast(this)); - if (i != items.cend()) { - for_const (auto item, i.value()) { Notify::historyItemLayoutChanged(item); } - } -} - -double PhotoData::progress() const { - if (uploading()) { - if (uploadingData->size > 0) { - return double(uploadingData->offset) / uploadingData->size; - } - return 0; - } - return full->progress(); -} - -qint32 PhotoData::loadOffset() const { - return full->loadOffset(); -} - -bool PhotoData::uploading() const { - return !!uploadingData; -} - -void PhotoData::forget() { - thumb->forget(); - replyPreview->forget(); - medium->forget(); - full->forget(); -} - -ImagePtr PhotoData::makeReplyPreview() { - if (replyPreview->isNull() && !thumb->isNull()) { - if (thumb->loaded()) { - int w = thumb->width(), h = thumb->height(); - if (w <= 0) w = 1; - if (h <= 0) h = 1; - replyPreview = - ImagePtr(w > h ? thumb->pix(w * st::msgReplyBarSize.height() / h, st::msgReplyBarSize.height()) : - thumb->pix(st::msgReplyBarSize.height()), - "PNG"); - } else { - thumb->load(); - } - } - return replyPreview; -} - -void PhotoOpenClickHandler::onClickImpl() const { - Messenger::Instance().showPhoto(this, App::hoveredLinkItem() ? App::hoveredLinkItem() : App::contextItem()); -} - -void PhotoSaveClickHandler::onClickImpl() const { - auto data = photo(); - if (!data->date) return; - - data->download(); -} - -void PhotoCancelClickHandler::onClickImpl() const { - auto data = photo(); - if (!data->date) return; - - if (data->uploading()) { - if (auto item = - App::hoveredLinkItem() ? App::hoveredLinkItem() : (App::contextItem() ? App::contextItem() : nullptr)) { - if (auto media = item->getMedia()) { - if (media->type() == MediaTypePhoto && static_cast(media)->photo() == data) { - App::contextItem(item); - App::main()->cancelUploadLayer(); - } - } - } - } else { - data->cancel(); - } -} - QString joinList(const QStringList &list, const QString &sep) { QString result; if (list.isEmpty()) return result; @@ -2239,16 +2114,6 @@ WebPageData::WebPageData(const WebPageId &id, WebPageType type, const QString &u , document(document) , pendingTill(pendingTill) {} -GameData::GameData(const GameId &id, const quint64 &accessHash, const QString &shortName, const QString &title, - const QString &description, PhotoData *photo, DocumentData *document) - : id(id) - , accessHash(accessHash) - , shortName(shortName) - , title(title) - , description(description) - , photo(photo) - , document(document) {} - MsgId clientMsgId() { static MsgId currentClientMsgId = StartClientMsgId; Assert(currentClientMsgId < EndClientMsgId); diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 38b51fc3f..0b8667b80 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -31,49 +31,9 @@ #include "ui/images.h" #include "ui/text/text.h" #include "ui/twidget.h" - -using MediaKey = QPair; - -inline quint64 mediaMix32To64(qint32 a, qint32 b) { - return (quint64(*reinterpret_cast(&a)) << 32) | quint64(*reinterpret_cast(&b)); -} - -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 -}; - -// Old method, should not be used anymore. -// inline MediaKey mediaKey(LocationType type, qint32 dc, const quint64 &id) { -// return MediaKey(mediaMix32To64(type, dc), id); -//} -// New method when version was introduced, type is not relevant anymore (all files are Documents). -inline MediaKey mediaKey(LocationType type, qint32 dc, const quint64 &id, qint32 version) { - return (version > 0) ? MediaKey(mediaMix32To64(version, dc), id) : MediaKey(mediaMix32To64(type, dc), id); -} - -inline StorageKey mediaKey(const MTPDfileLocation &location) { - return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v); -} - -typedef qint32 UserId; -typedef qint32 ChatId; -typedef qint32 ChannelId; -static const ChannelId NoChannel = 0; - -typedef qint32 MsgId; -struct FullMsgId { - FullMsgId() = default; - FullMsgId(ChannelId channel, MsgId msg) - : channel(channel) - , msg(msg) {} - ChannelId channel = NoChannel; - MsgId msg = 0; -}; +#include "data/data_types.h" +#include "data/data_photo.h" +#include "data/data_document.h" typedef quint64 PeerId; static const quint64 PeerIdMask = 0xFFFFFFFFULL; @@ -177,12 +137,10 @@ inline TimeId dateFromMessage(const MTPmessage &msg) { return 0; } -using PhotoId = quint64; using VideoId = quint64; using AudioId = quint64; using DocumentId = quint64; using WebPageId = quint64; -using GameId = quint64; static const WebPageId CancelledWebPageId = 0xFFFFFFFFFFFFFFFFULL; inline bool operator==(const FullMsgId &a, const FullMsgId &b) { @@ -197,18 +155,9 @@ inline bool operator<(const FullMsgId &a, const FullMsgId &b) { return a.channel < b.channel; } -constexpr const MsgId StartClientMsgId = -0x7FFFFFFF; -constexpr const MsgId EndClientMsgId = -0x40000000; inline constexpr bool isClientMsgId(MsgId id) { return id >= StartClientMsgId && id < EndClientMsgId; } -constexpr const MsgId ShowAtTheEndMsgId = -0x40000000; -constexpr const MsgId SwitchAtTopMsgId = -0x3FFFFFFF; -constexpr const MsgId ShowAtProfileMsgId = -0x3FFFFFFE; -constexpr const MsgId ShowAndStartBotMsgId = -0x3FFFFFD; -constexpr const MsgId ShowAtGameShareMsgId = -0x3FFFFFC; -constexpr const MsgId ServerMaxMsgId = 0x3FFFFFFF; -constexpr const MsgId ShowAtUnreadMsgId = 0; struct NotifySettings { NotifySettings() @@ -1114,137 +1063,7 @@ inline bool PeerData::canWrite() const { (isChat() ? asChat()->canWrite() : (isUser() ? asUser()->canWrite() : false)); } -enum ActionOnLoad { ActionOnLoadNone, ActionOnLoadOpen, ActionOnLoadOpenWith, ActionOnLoadPlayInline }; - typedef QMap PreparedPhotoThumbs; -class PhotoData { -public: - PhotoData(const PhotoId &id, const quint64 &access = 0, qint32 date = 0, const ImagePtr &thumb = ImagePtr(), - const ImagePtr &medium = ImagePtr(), const ImagePtr &full = ImagePtr()); - - void automaticLoad(const HistoryItem *item); - void automaticLoadSettingsChanged(); - - void download(); - bool loaded() const; - bool loading() const; - bool displayLoading() const; - void cancel(); - double progress() const; - qint32 loadOffset() const; - bool uploading() const; - - void forget(); - ImagePtr makeReplyPreview(); - - PhotoId id; - quint64 access; - qint32 date; - ImagePtr thumb, replyPreview; - ImagePtr medium; - ImagePtr full; - - PeerData *peer = nullptr; // for chat and channel photos connection - // geo, caption - - struct UploadingData { - UploadingData(int size) - : size(size) {} - int offset = 0; - int size = 0; - }; - std::unique_ptr uploadingData; - -private: - void notifyLayoutChanged() const; -}; - -class PhotoClickHandler : public LeftButtonClickHandler { -public: - PhotoClickHandler(not_null photo, PeerData *peer = nullptr) - : _photo(photo) - , _peer(peer) {} - not_null photo() const { - return _photo; - } - PeerData *peer() const { - return _peer; - } - -private: - not_null _photo; - PeerData *_peer; -}; - -class PhotoOpenClickHandler : public PhotoClickHandler { -public: - using PhotoClickHandler::PhotoClickHandler; - -protected: - void onClickImpl() const override; -}; - -class PhotoSaveClickHandler : public PhotoClickHandler { -public: - using PhotoClickHandler::PhotoClickHandler; - -protected: - void onClickImpl() const override; -}; - -class PhotoCancelClickHandler : public PhotoClickHandler { -public: - using PhotoClickHandler::PhotoClickHandler; - -protected: - void onClickImpl() const override; -}; - -enum FileStatus { - FileDownloadFailed = -2, - FileUploadFailed = -1, - FileUploading = 0, - 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, -}; - -struct DocumentAdditionalData { - virtual ~DocumentAdditionalData() = default; -}; - -struct StickerData : public DocumentAdditionalData { - ImagePtr img; - QString alt; - - MTPInputStickerSet set = MTP_inputStickerSetEmpty(); - bool setInstalled() const; - - StorageImageLocation loc; // doc thumb location -}; - -struct SongData : public DocumentAdditionalData { - qint32 duration = 0; - QString title, performer; -}; - -typedef QVector VoiceWaveform; // [0] == -1 -- counting, [0] == -2 -- could not count -struct VoiceData : public DocumentAdditionalData { - ~VoiceData(); - - int duration = 0; - VoiceWaveform waveform; - char wavemax = 0; -}; bool fileIsImage(const QString &name, const QString &mime); @@ -1252,214 +1071,6 @@ namespace Serialize { class Document; } // namespace Serialize -class DocumentData { -public: - static DocumentData *create(DocumentId id); - static DocumentData *create(DocumentId id, qint32 dc, quint64 accessHash, qint32 version, - const QVector &attributes); - static DocumentData *create(DocumentId id, const QString &url, const QVector &attributes); - - void setattributes(const QVector &attributes); - - void automaticLoad(const HistoryItem *item); // auto load sticker or video - void automaticLoadSettingsChanged(); - - enum FilePathResolveType { - FilePathResolveCached, - FilePathResolveChecked, - FilePathResolveSaveFromData, - FilePathResolveSaveFromDataSilent, - }; - bool loaded(FilePathResolveType type = FilePathResolveCached) const; - bool loading() const; - QString loadingFilePath() const; - bool displayLoading() const; - void save(const QString &toFile, ActionOnLoad action = ActionOnLoadNone, const FullMsgId &actionMsgId = FullMsgId(), - LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal, bool autoLoading = false); - void cancel(); - double progress() const; - qint32 loadOffset() const; - bool uploading() const; - - QByteArray data() const; - const FileLocation &location(bool check = false) const; - void setLocation(const FileLocation &loc); - - QString filepath(FilePathResolveType type = FilePathResolveCached, bool forceSavingAs = false) const; - - bool saveToCache() const; - - void performActionOnLoad(); - - void forget(); - ImagePtr makeReplyPreview(); - - StickerData *sticker() { - return (type == StickerDocument) ? static_cast(_additional.get()) : nullptr; - } - void checkSticker() { - StickerData *s = sticker(); - if (!s) return; - - automaticLoad(nullptr); - if (s->img->isNull() && loaded()) { - if (_data.isEmpty()) { - const FileLocation &loc(location(true)); - if (loc.accessEnable()) { - s->img = ImagePtr(loc.name()); - loc.accessDisable(); - } - } else { - s->img = ImagePtr(_data); - } - } - } - SongData *song() { - return (type == SongDocument) ? static_cast(_additional.get()) : nullptr; - } - const SongData *song() const { - return const_cast(this)->song(); - } - VoiceData *voice() { - return (type == VoiceDocument) ? static_cast(_additional.get()) : nullptr; - } - const VoiceData *voice() const { - return const_cast(this)->voice(); - } - bool isRoundVideo() const { - return (type == RoundVideoDocument); - } - bool isAnimation() const { - return (type == AnimatedDocument) || isRoundVideo() || hasMimeType(qstr("image/gif")); - } - bool isGifv() const { - return (type == AnimatedDocument) && hasMimeType(qstr("video/mp4")); - } - bool isTheme() const { - return _filename.endsWith(qstr(".tdesktop-theme"), Qt::CaseInsensitive) || - _filename.endsWith(qstr(".tdesktop-palette"), Qt::CaseInsensitive); - } - bool tryPlaySong() const { - return (song() != nullptr) || _mimeString.startsWith(qstr("audio/"), Qt::CaseInsensitive); - } - bool isMusic() const { - if (auto s = song()) { - return (s->duration > 0); - } - return false; - } - bool isVideo() const { - return (type == VideoDocument); - } - qint32 duration() const { - return (isAnimation() || isVideo()) ? _duration : -1; - } - bool isImage() const { - return !isAnimation() && !isVideo() && (_duration > 0); - } - void recountIsImage(); - void setData(const QByteArray &data) { - _data = data; - } - - bool setRemoteVersion(qint32 version); // Returns true if version has changed. - void setRemoteLocation(qint32 dc, quint64 access); - void setContentUrl(const QString &url); - bool hasRemoteLocation() const { - return (_dc != 0 && _access != 0); - } - bool isValid() const { - return hasRemoteLocation() || !_url.isEmpty(); - } - MTPInputDocument mtpInput() const { - if (_access) { - return MTP_inputDocument(MTP_long(id), MTP_long(_access)); - } - return MTP_inputDocumentEmpty(); - } - - // When we have some client-side generated document - // (for example for displaying an external inline bot result) - // and it has downloaded data, we can collect that data from it - // to (this) received from the server "same" document. - void collectLocalData(DocumentData *local); - - QString filename() const { - return _filename; - } - QString mimeString() const { - return _mimeString; - } - bool hasMimeType(QLatin1String mime) const { - return !_mimeString.compare(mime, Qt::CaseInsensitive); - } - void setMimeString(const QString &mime) { - _mimeString = mime; - } - - - ~DocumentData(); - - DocumentId id = 0; - DocumentType type = FileDocument; - QSize dimensions; - qint32 date = 0; - ImagePtr thumb, replyPreview; - qint32 size = 0; - - FileStatus status = FileReady; - qint32 uploadOffset = 0; - - qint32 md5[8]; - - MediaKey mediaKey() const { - return ::mediaKey(locationType(), _dc, id, _version); - } - - static QString ComposeNameString(const QString &filename, const QString &songTitle, const QString &songPerformer); - QString composeNameString() const { - if (auto songData = song()) { - return ComposeNameString(_filename, songData->title, songData->performer); - } - return ComposeNameString(_filename, QString(), QString()); - } - -private: - DocumentData(DocumentId id, qint32 dc, quint64 accessHash, qint32 version, const QString &url, - const QVector &attributes); - - friend class Serialize::Document; - - LocationType locationType() const { - return voice() ? AudioFileLocation : (isVideo() ? VideoFileLocation : DocumentFileLocation); - } - - // Two types of location: from MTProto by dc+access+version or from web by url - qint32 _dc = 0; - quint64 _access = 0; - qint32 _version = 0; - QString _url; - QString _filename; - QString _mimeString; - - - FileLocation _location; - QByteArray _data; - std::unique_ptr _additional; - qint32 _duration = -1; - - ActionOnLoad _actionOnLoad = ActionOnLoadNone; - FullMsgId _actionOnLoadMsgId; - mutable FileLoader *_loader = nullptr; - - void notifyLayoutChanged() const; - - void destroyLoaderDelayed(mtpFileLoader *newValue = nullptr) const; -}; - -VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit); -QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform); - class AudioMsgId { public: enum class Type { @@ -1617,23 +1228,6 @@ struct WebPageData { qint32 pendingTill; }; -struct GameData { - GameData(const GameId &id, const quint64 &accessHash = 0, const QString &shortName = QString(), - const QString &title = QString(), const QString &description = QString(), PhotoData *photo = nullptr, - DocumentData *doc = nullptr); - - void forget() { - if (document) document->forget(); - if (photo) photo->forget(); - } - - GameId id; - quint64 accessHash; - QString shortName, title, description; - PhotoData *photo; - DocumentData *document; -}; - QString saveFileName(const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir = QDir()); MsgId clientMsgId(); @@ -1671,27 +1265,3 @@ struct MessageCursor { inline bool operator==(const MessageCursor &a, const MessageCursor &b) { return (a.position == b.position) && (a.anchor == b.anchor) && (a.scroll == b.scroll); } - -struct SendAction { - enum class Type { - Typing, - RecordVideo, - UploadVideo, - RecordVoice, - UploadVoice, - RecordRound, - UploadRound, - UploadPhoto, - UploadFile, - ChooseLocation, - ChooseContact, - PlayGame, - }; - SendAction(Type type, TimeMs until, int progress = 0) - : type(type) - , until(until) - , progress(progress) {} - Type type; - TimeMs until; - int progress; -}; diff --git a/Telegram/SourceFiles/ui/effects/send_action_animations.h b/Telegram/SourceFiles/ui/effects/send_action_animations.h index a4c41f685..a00211ded 100644 --- a/Telegram/SourceFiles/ui/effects/send_action_animations.h +++ b/Telegram/SourceFiles/ui/effects/send_action_animations.h @@ -22,7 +22,8 @@ // #pragma once -#include "structs.h" +#include "data/data_types.h" +#include "ui/twidget.h" namespace Ui {