/* This file is part of Telegram Desktop, the official desktop version of Telegram messaging app, see https://telegram.org Telegram Desktop 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/telegramdesktop/tdesktop/blob/master/LICENSE Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once #include "storage/storage_shared_media.h" #include "mtproto/sender.h" #include "base/weak_unique_ptr.h" base::optional SharedMediaOverviewType( Storage::SharedMediaType type); void SharedMediaShowOverview( Storage::SharedMediaType type, not_null history); class SharedMediaViewer; class SharedMediaSlice { public: using Key = Storage::SharedMediaKey; SharedMediaSlice( Key key, base::optional fullCount = base::none) : _key(key) , _fullCount(fullCount) { } base::optional fullCount() const { return _fullCount; } base::optional skippedBefore() const { return _skippedBefore; } base::optional skippedAfter() const { return _skippedAfter; } base::optional indexOf(MsgId msgId) const { auto it = _ids.find(msgId); if (it != _ids.end()) { return (it - _ids.begin()); } return base::none; } int size() const { return _ids.size(); } using iterator = base::flat_set::const_iterator; iterator begin() const { return _ids.begin(); } iterator end() const { return _ids.end(); } iterator cbegin() const { return begin(); } iterator cend() const { return end(); } base::optional distance(const Key &a, const Key &b) const { if (a.type != _key.type || b.type != _key.type || a.peerId != _key.peerId || b.peerId != _key.peerId) { return base::none; } auto i = _ids.find(a.messageId); auto j = _ids.find(b.messageId); if (i == _ids.end() || j == _ids.end()) { return base::none; } return j - i; } private: Key _key; base::flat_set _ids; MsgRange _range; base::optional _fullCount; base::optional _skippedBefore; base::optional _skippedAfter; friend class SharedMediaViewer; }; class SharedMediaViewer : private base::Subscriber, public base::enable_weak_from_this { public: using Type = Storage::SharedMediaType; using Key = Storage::SharedMediaKey; SharedMediaViewer( Key key, int limitBefore, int limitAfter); void start(); base::Observable updated; private: using InitialResult = Storage::SharedMediaResult; using SliceUpdate = Storage::SharedMediaSliceUpdate; using OneRemoved = Storage::SharedMediaRemoveOne; using AllRemoved = Storage::SharedMediaRemoveAll; void loadInitial(); enum class RequestDirection { Before, After, }; void requestMessages(RequestDirection direction); void applyStoredResult(InitialResult &&result); void applyUpdate(const SliceUpdate &update); void applyUpdate(const OneRemoved &update); void applyUpdate(const AllRemoved &update); void sliceToLimits(); void mergeSliceData( base::optional count, const base::flat_set &messageIds, base::optional skippedBefore = base::none, base::optional skippedAfter = base::none); Key _key; int _limitBefore = 0; int _limitAfter = 0; mtpRequestId _beforeRequestId = 0; mtpRequestId _afterRequestId = 0; SharedMediaSlice _data; }; // //class SharedMediaSliceMerged : // private MTP::Sender, // private base::Subscriber, // public base::enable_weak_from_this { //public: // class Data; // //private: // friend class Data; // using UniversalMsgId = MsgId; // //public: // using Type = Storage::SharedMediaType; // // SharedMediaSliceMerged( // Type type, // not_null history, // MsgId aroundId, // int limitBefore, // int limitAfter); // // bool hasOverview() const; // void showOverview() const; // bool moveTo(const SharedMediaSliceMerged &other); // // void load(); // // class Data { // public: // base::optional fullCount() const; // base::optional skippedBefore() const; // base::optional skippedAfter() const; // int size() const { // return _ids.size(); // } // // class iterator { // public: // FullMsgId operator*() const { // auto id = _data->_ids[_index]; // Assert(IsServerMsgId(id) // || (_data->_migrated != nullptr && IsServerMsgId(-id))); // return IsServerMsgId(id) // ? FullMsgId(_data->_history->channelId(), id) // : FullMsgId(_data->_migrated->channelId(), -id); // } // iterator &operator--() { // --_index; // return *this; // } // iterator operator--(int) { // auto result = *this; // --*this; // return result; // } // iterator &operator++() { // ++_index; // return *this; // } // iterator operator++(int) { // auto result = *this; // ++*this; // return result; // } // iterator &operator+=(int offset) { // _index += offset; // return *this; // } // iterator operator+(int offset) const { // auto result = *this; // return result += offset; // } // bool operator==(iterator other) const { // return (_data == other._data) && (_index == other._index); // } // bool operator!=(iterator other) const { // return !(*this == other); // } // bool operator<(iterator other) const { // return (_data < other._data) // || (_data == other._data && _index < other._index); // } // // private: // friend class Data; // // iterator(not_null data, int index) // : _data(data) // , _index(index) { // } // // not_null _data; // int _index = 0; // // }; // // iterator begin() const { // return iterator(this, 0); // } // iterator end() const { // iterator(this, _ids.size()); // } // iterator cbegin() const { // return begin(); // } // iterator cend() const { // return end(); // } // // private: // friend class iterator; // friend class SharedMediaSliceMerged; // // Data( // not_null history, // History *migrated, // base::optional historyCount = base::none, // base::optional migratedCount = base::none) // : _history(history) // , _migrated(migrated) // , _historyCount(historyCount) // , _migratedCount(migratedCount) { // if (!_migrated) { // _migratedCount = 0; // } // } // // not_null _history; // History *_migrated = nullptr; // std::vector _ids; // base::optional _historyCount; // base::optional _historySkippedBefore; // base::optional _historySkippedAfter; // base::optional _migratedCount; // base::optional _migratedSkippedBefore; // base::optional _migratedSkippedAfter; // // }; // base::Observable updated; // //private: // bool amAroundMigrated() const; // not_null aroundHistory() const; // MsgId aroundId() const; // // void applyStoredResult( // not_null peer, // Storage::SharedMediaResult &&result); // bool containsAroundId() const; // void clearAfterMove(); // // Type _type = Type::kCount; // not_null _history; // History *_migrated = nullptr; // UniversalMsgId _universalAroundId = 0; // int _limitBefore = 0; // int _limitAfter = 0; // Data _data; // //};