Implement story album management.
This commit is contained in:
@@ -477,6 +477,19 @@ Story *Stories::parseAndApply(
|
||||
return nullptr;
|
||||
}
|
||||
const auto id = data.vid().v;
|
||||
auto albumInfo = (Albums*)nullptr;
|
||||
auto list = std::optional<base::flat_set<int>>();
|
||||
if (const auto albums = data.valbums()) {
|
||||
list.emplace();
|
||||
if (!albums->v.empty()) {
|
||||
albumInfo = &_albums[peer->id];
|
||||
list->reserve(albums->v.size());
|
||||
for (const auto &albumId : albums->v) {
|
||||
albumInfo->sets[albumId.v].albumKnownInArchive.emplace(id);
|
||||
list->emplace(albumId.v);
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto fullId = FullStoryId{ peer->id, id };
|
||||
auto &stories = _stories[peer->id];
|
||||
const auto i = stories.find(id);
|
||||
@@ -484,6 +497,21 @@ Story *Stories::parseAndApply(
|
||||
const auto result = i->second.get();
|
||||
const auto mediaChanged = (result->media() != *media);
|
||||
result->applyChanges(*media, data, now);
|
||||
if (list) {
|
||||
const auto &was = result->albumIds();
|
||||
if (*list != was) {
|
||||
if (!albumInfo && !was.empty()) {
|
||||
albumInfo = &_albums[peer->id];
|
||||
}
|
||||
for (const auto wasId : result->albumIds()) {
|
||||
if (!list->contains(wasId)) {
|
||||
albumInfo->sets[wasId].albumKnownInArchive.remove(id);
|
||||
}
|
||||
}
|
||||
result->setAlbumIds(*base::take(list));
|
||||
}
|
||||
}
|
||||
|
||||
const auto j = _pollingSettings.find(result);
|
||||
if (j != end(_pollingSettings)) {
|
||||
maybeSchedulePolling(result, j->second, now);
|
||||
@@ -508,6 +536,9 @@ Story *Stories::parseAndApply(
|
||||
data,
|
||||
now
|
||||
)).first->second.get();
|
||||
if (list) {
|
||||
result->setAlbumIds(*base::take(list));
|
||||
}
|
||||
|
||||
if (const auto archive = lookupArchive(peer)) {
|
||||
const auto added = archive->ids.list.emplace(id).second;
|
||||
@@ -827,6 +858,7 @@ void Stories::applyDeleted(not_null<PeerData*> peer, StoryId id) {
|
||||
removeDependencyStory(story.get());
|
||||
const auto removeFromAlbum = [&](int albumId) {
|
||||
if (const auto set = albumIdsSet(peerId, albumId, true)) {
|
||||
set->albumKnownInArchive.remove(id);
|
||||
if (set->ids.list.remove(id)) {
|
||||
if (set->total > 0) {
|
||||
--set->total;
|
||||
@@ -1669,9 +1701,18 @@ bool Stories::albumIdsLoaded(PeerId peerId, int albumId) const {
|
||||
}
|
||||
|
||||
void Stories::albumIdsLoadMore(PeerId peerId, int albumId) {
|
||||
albumIdsLoadMore(peerId, albumId, false);
|
||||
}
|
||||
|
||||
void Stories::albumIdsLoadMore(PeerId peerId, int albumId, bool reload) {
|
||||
Expects(!reload || albumId > 0);
|
||||
|
||||
const auto peer = _owner->peer(peerId);
|
||||
const auto set = albumIdsSet(peerId, albumId);
|
||||
if (!set || set->requestId || set->loaded) {
|
||||
if (set && reload) {
|
||||
_owner->session().api().request(base::take(set->requestId)).cancel();
|
||||
}
|
||||
if (!set || set->requestId || (!reload && set->loaded)) {
|
||||
return;
|
||||
}
|
||||
const auto api = &_owner->session().api();
|
||||
@@ -1681,6 +1722,11 @@ void Stories::albumIdsLoadMore(PeerId peerId, int albumId) {
|
||||
return;
|
||||
}
|
||||
set->requestId = 0;
|
||||
if (reload) {
|
||||
set->ids.list.clear();
|
||||
set->ids.pinnedToTop.clear();
|
||||
set->lastId = StoryId();
|
||||
}
|
||||
const auto &data = result.data();
|
||||
const auto now = base::unixtime::now();
|
||||
auto pinnedToTopIds = data.vpinned_to_top().value_or_empty();
|
||||
@@ -1734,11 +1780,28 @@ void Stories::albumIdsLoadMore(PeerId peerId, int albumId) {
|
||||
: api->request(MTPstories_GetAlbumStories(
|
||||
peer->input,
|
||||
MTP_int(albumId),
|
||||
MTP_int(set->lastId),
|
||||
MTP_int(set->lastId ? kSavedPerPage : kSavedFirstPerPage)
|
||||
MTP_int(reload ? 0 : set->ids.list.size()),
|
||||
MTP_int((reload || set->ids.list.empty())
|
||||
? kSavedFirstPerPage
|
||||
: kSavedPerPage)
|
||||
)).done(done).fail(fail).send();
|
||||
}
|
||||
|
||||
const base::flat_set<StoryId> &Stories::albumKnownInArchive(
|
||||
PeerId peerId,
|
||||
int albumId) const {
|
||||
static const auto empty = base::flat_set<StoryId>();
|
||||
|
||||
const auto i = _albums.find(peerId);
|
||||
if (i == end(_albums)) {
|
||||
return empty;
|
||||
}
|
||||
const auto j = i->second.sets.find(albumId);
|
||||
return (j != end(i->second.sets))
|
||||
? j->second.albumKnownInArchive
|
||||
: empty;
|
||||
}
|
||||
|
||||
auto Stories::albumsListValue(PeerId peerId)
|
||||
-> rpl::producer<std::vector<Data::StoryAlbum>> {
|
||||
auto &albums = _albums[peerId];
|
||||
@@ -1839,6 +1902,33 @@ void Stories::albumRename(
|
||||
}
|
||||
|
||||
void Stories::notifyAlbumUpdate(StoryAlbumUpdate &&update) {
|
||||
const auto peerId = update.peer->id;
|
||||
const auto i = _albums.find(peerId);
|
||||
if (i != end(_albums)) {
|
||||
const auto albumId = update.albumId;
|
||||
const auto j = i->second.sets.find(albumId);
|
||||
if (j != end(i->second.sets)) {
|
||||
for (const auto &id : update.added) {
|
||||
j->second.albumKnownInArchive.emplace(id);
|
||||
if (const auto story = lookup({ peerId, id })) {
|
||||
auto now = (*story)->albumIds();
|
||||
if (now.emplace(albumId).second) {
|
||||
(*story)->setAlbumIds(std::move(now));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &id : update.removed) {
|
||||
j->second.albumKnownInArchive.remove(id);
|
||||
if (const auto story = lookup({ peerId, id })) {
|
||||
auto now = (*story)->albumIds();
|
||||
if (now.remove(albumId)) {
|
||||
(*story)->setAlbumIds(std::move(now));
|
||||
}
|
||||
}
|
||||
}
|
||||
albumIdsLoadMore(peerId, albumId, true);
|
||||
}
|
||||
}
|
||||
_albumUpdates.fire(std::move(update));
|
||||
}
|
||||
|
||||
|
||||
@@ -213,10 +213,13 @@ public:
|
||||
PeerId peerId,
|
||||
int albumId) const;
|
||||
[[nodiscard]] rpl::producer<StoryAlbumIdsKey> albumIdsChanged() const;
|
||||
[[nodiscard]] int albumIdsCount(PeerId peerIdl, int albumId) const;
|
||||
[[nodiscard]] int albumIdsCount(PeerId peerId, int albumId) const;
|
||||
[[nodiscard]] bool albumIdsCountKnown(PeerId peerId, int albumId) const;
|
||||
[[nodiscard]] bool albumIdsLoaded(PeerId peerId, int albumId) const;
|
||||
void albumIdsLoadMore(PeerId peerId, int albumId);
|
||||
[[nodiscard]] const base::flat_set<StoryId> &albumKnownInArchive(
|
||||
PeerId peerId,
|
||||
int albumId) const;
|
||||
|
||||
[[nodiscard]] auto albumsListValue(PeerId peerId)
|
||||
-> rpl::producer<std::vector<Data::StoryAlbum>>;
|
||||
@@ -286,6 +289,7 @@ public:
|
||||
private:
|
||||
struct Set {
|
||||
StoriesIds ids;
|
||||
base::flat_set<StoryId> albumKnownInArchive;
|
||||
int total = -1;
|
||||
StoryId lastId = 0;
|
||||
bool loaded = false;
|
||||
@@ -307,6 +311,7 @@ private:
|
||||
DirectRequest,
|
||||
};
|
||||
|
||||
void albumIdsLoadMore(PeerId peerId, int albumId, bool reload);
|
||||
void parseAndApply(const MTPPeerStories &stories, ParseSource source);
|
||||
[[nodiscard]] Story *parseAndApply(
|
||||
not_null<PeerData*> peer,
|
||||
|
||||
@@ -899,10 +899,14 @@ StoryId Story::repostSourceId() const {
|
||||
return _repostSourceId;
|
||||
}
|
||||
|
||||
const std::vector<int> &Story::albumIds() const {
|
||||
const base::flat_set<int> &Story::albumIds() const {
|
||||
return _albumIds;
|
||||
}
|
||||
|
||||
void Story::setAlbumIds(base::flat_set<int> ids) {
|
||||
_albumIds = std::move(ids);
|
||||
}
|
||||
|
||||
PeerData *Story::fromPeer() const {
|
||||
return _fromPeer;
|
||||
}
|
||||
|
||||
@@ -237,7 +237,8 @@ public:
|
||||
[[nodiscard]] QString repostSourceName() const;
|
||||
[[nodiscard]] StoryId repostSourceId() const;
|
||||
|
||||
[[nodiscard]] const std::vector<int> &albumIds() const;
|
||||
[[nodiscard]] const base::flat_set<int> &albumIds() const;
|
||||
void setAlbumIds(base::flat_set<int> ids);
|
||||
|
||||
[[nodiscard]] PeerData *fromPeer() const;
|
||||
|
||||
@@ -267,7 +268,7 @@ private:
|
||||
PeerData * const _repostSourcePeer = nullptr;
|
||||
const QString _repostSourceName;
|
||||
const StoryId _repostSourceId = 0;
|
||||
std::vector<int> _albumIds;
|
||||
base::flat_set<int> _albumIds;
|
||||
PeerData * const _fromPeer = nullptr;
|
||||
Data::ReactionId _sentReactionId;
|
||||
StoryMedia _media;
|
||||
|
||||
@@ -16,8 +16,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "history/history.h"
|
||||
@@ -34,7 +35,8 @@ using namespace Media;
|
||||
} // namespace
|
||||
|
||||
Provider::Provider(not_null<AbstractController*> controller)
|
||||
: _controller(controller) {
|
||||
: _controller(controller)
|
||||
, _storiesAddToAlbumId(_controller->storiesAddToAlbumId()) {
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
for (auto &layout : _layouts) {
|
||||
@@ -485,6 +487,9 @@ void Provider::applyDragSelection(
|
||||
return;
|
||||
}
|
||||
const auto search = !_queryWords.isEmpty();
|
||||
const auto selectLimit = _storiesAddToAlbumId
|
||||
? _controller->session().appConfig().storiesAlbumLimit()
|
||||
: MaxSelectedItems;
|
||||
auto chosen = base::flat_set<not_null<const HistoryItem*>>();
|
||||
chosen.reserve(till - from);
|
||||
for (auto i = from; i != till; ++i) {
|
||||
@@ -496,7 +501,8 @@ void Provider::applyDragSelection(
|
||||
ChangeItemSelection(
|
||||
selected,
|
||||
item,
|
||||
computeSelectionData(item, FullSelection));
|
||||
computeSelectionData(item, FullSelection),
|
||||
selectLimit);
|
||||
}
|
||||
if (selected.size() != chosen.size()) {
|
||||
for (auto i = begin(selected); i != end(selected);) {
|
||||
|
||||
@@ -129,6 +129,7 @@ private:
|
||||
std::optional<int> _fullCount;
|
||||
base::flat_set<not_null<const HistoryItem*>> _downloading;
|
||||
base::flat_set<not_null<const HistoryItem*>> _downloaded;
|
||||
int _storiesAddToAlbumId = 0;
|
||||
|
||||
std::vector<Element> _addPostponed;
|
||||
|
||||
|
||||
@@ -477,7 +477,11 @@ Key ContentMemento::key() const {
|
||||
} else if (const auto self = settingsSelf()) {
|
||||
return Settings::Tag{ self };
|
||||
} else if (const auto stories = storiesPeer()) {
|
||||
return Stories::Tag{ stories, storiesAlbumId() };
|
||||
return Stories::Tag{
|
||||
stories,
|
||||
storiesAlbumId(),
|
||||
storiesAddToAlbumId(),
|
||||
};
|
||||
} else if (statisticsTag().peer) {
|
||||
return statisticsTag();
|
||||
} else if (const auto starref = starrefPeer()) {
|
||||
@@ -521,7 +525,8 @@ ContentMemento::ContentMemento(Downloads::Tag downloads) {
|
||||
|
||||
ContentMemento::ContentMemento(Stories::Tag stories)
|
||||
: _storiesPeer(stories.peer)
|
||||
, _storiesAlbumId(stories.albumId) {
|
||||
, _storiesAlbumId(stories.albumId)
|
||||
, _storiesAddToAlbumId(stories.addingToAlbumId) {
|
||||
}
|
||||
|
||||
ContentMemento::ContentMemento(Statistics::Tag statistics)
|
||||
|
||||
@@ -250,6 +250,9 @@ public:
|
||||
[[nodiscard]] int storiesAlbumId() const {
|
||||
return _storiesAlbumId;
|
||||
}
|
||||
[[nodiscard]] int storiesAddToAlbumId() const {
|
||||
return _storiesAddToAlbumId;
|
||||
}
|
||||
[[nodiscard]] Statistics::Tag statisticsTag() const {
|
||||
return _statisticsTag;
|
||||
}
|
||||
@@ -315,6 +318,7 @@ private:
|
||||
UserData * const _settingsSelf = nullptr;
|
||||
PeerData * const _storiesPeer = nullptr;
|
||||
int _storiesAlbumId = 0;
|
||||
int _storiesAddToAlbumId = 0;
|
||||
Statistics::Tag _statisticsTag;
|
||||
PeerData * const _starrefPeer = nullptr;
|
||||
BotStarRef::Type _starrefType = {};
|
||||
|
||||
@@ -125,6 +125,13 @@ int Key::storiesAlbumId() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Key::storiesAddToAlbumId() const {
|
||||
if (const auto tag = std::get_if<Stories::Tag>(&_value)) {
|
||||
return tag->addingToAlbumId;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Statistics::Tag Key::statisticsTag() const {
|
||||
if (const auto tag = std::get_if<Statistics::Tag>(&_value)) {
|
||||
return *tag;
|
||||
|
||||
@@ -90,22 +90,24 @@ public:
|
||||
Data::ReactionId selected,
|
||||
FullMsgId contextId);
|
||||
|
||||
PeerData *peer() const;
|
||||
Data::ForumTopic *topic() const;
|
||||
Data::SavedSublist *sublist() const;
|
||||
UserData *settingsSelf() const;
|
||||
bool isDownloads() const;
|
||||
bool isGlobalMedia() const;
|
||||
PeerData *storiesPeer() const;
|
||||
int storiesAlbumId() const;
|
||||
Statistics::Tag statisticsTag() const;
|
||||
PeerData *starrefPeer() const;
|
||||
BotStarRef::Type starrefType() const;
|
||||
PollData *poll() const;
|
||||
FullMsgId pollContextId() const;
|
||||
std::shared_ptr<Api::WhoReadList> reactionsWhoReadIds() const;
|
||||
Data::ReactionId reactionsSelected() const;
|
||||
FullMsgId reactionsContextId() const;
|
||||
[[nodiscard]] PeerData *peer() const;
|
||||
[[nodiscard]] Data::ForumTopic *topic() const;
|
||||
[[nodiscard]] Data::SavedSublist *sublist() const;
|
||||
[[nodiscard]] UserData *settingsSelf() const;
|
||||
[[nodiscard]] bool isDownloads() const;
|
||||
[[nodiscard]] bool isGlobalMedia() const;
|
||||
[[nodiscard]] PeerData *storiesPeer() const;
|
||||
[[nodiscard]] int storiesAlbumId() const;
|
||||
[[nodiscard]] int storiesAddToAlbumId() const;
|
||||
[[nodiscard]] Statistics::Tag statisticsTag() const;
|
||||
[[nodiscard]] PeerData *starrefPeer() const;
|
||||
[[nodiscard]] BotStarRef::Type starrefType() const;
|
||||
[[nodiscard]] PollData *poll() const;
|
||||
[[nodiscard]] FullMsgId pollContextId() const;
|
||||
[[nodiscard]] auto reactionsWhoReadIds() const
|
||||
-> std::shared_ptr<Api::WhoReadList>;
|
||||
[[nodiscard]] Data::ReactionId reactionsSelected() const;
|
||||
[[nodiscard]] FullMsgId reactionsContextId() const;
|
||||
|
||||
private:
|
||||
struct PollKey {
|
||||
@@ -229,6 +231,9 @@ public:
|
||||
[[nodiscard]] int storiesAlbumId() const {
|
||||
return key().storiesAlbumId();
|
||||
}
|
||||
[[nodiscard]] int storiesAddToAlbumId() const {
|
||||
return key().storiesAddToAlbumId();
|
||||
}
|
||||
[[nodiscard]] Statistics::Tag statisticsTag() const {
|
||||
return key().statisticsTag();
|
||||
}
|
||||
|
||||
@@ -312,7 +312,9 @@ void WrapWidget::forceContentRepaint() {
|
||||
}
|
||||
|
||||
void WrapWidget::setupTop() {
|
||||
if (HasCustomTopBar(_controller.get()) || wrap() == Wrap::Search) {
|
||||
if (HasCustomTopBar(_controller.get())
|
||||
|| wrap() == Wrap::Search
|
||||
|| wrap() == Wrap::StoryAlbumEdit) {
|
||||
_topBar.destroy();
|
||||
return;
|
||||
}
|
||||
@@ -696,7 +698,13 @@ rpl::producer<int> WrapWidget::desiredHeightForContent() const {
|
||||
}
|
||||
|
||||
rpl::producer<SelectedItems> WrapWidget::selectedListValue() const {
|
||||
return _selectedLists.events() | rpl::flatten_latest();
|
||||
auto current = _content
|
||||
? _content->selectedListValue()
|
||||
: nullptr;
|
||||
return _selectedLists.events_starting_with(current
|
||||
? std::move(current)
|
||||
: rpl::single(SelectedItems(Storage::SharedMediaType::Photo))
|
||||
) | rpl::flatten_latest();
|
||||
}
|
||||
|
||||
object_ptr<ContentWidget> WrapWidget::createContent(
|
||||
|
||||
@@ -53,6 +53,7 @@ enum class Wrap {
|
||||
Narrow,
|
||||
Side,
|
||||
Search,
|
||||
StoryAlbumEdit,
|
||||
};
|
||||
|
||||
struct SelectedItem {
|
||||
@@ -143,6 +144,8 @@ public:
|
||||
return _removeRequests.events();
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<SelectedItems> selectedListValue() const;
|
||||
|
||||
void replaceSwipeHandler(Ui::Controls::SwipeHandlerArgs *incompleteArgs);
|
||||
|
||||
~WrapWidget();
|
||||
@@ -206,7 +209,6 @@ private:
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<ContentMemento*> memento);
|
||||
|
||||
rpl::producer<SelectedItems> selectedListValue() const;
|
||||
bool requireTopBarSearch() const;
|
||||
|
||||
void addTopBarMenuButton();
|
||||
|
||||
@@ -31,7 +31,11 @@ UniversalMsgId GetUniversalId(not_null<const BaseLayout*> layout) {
|
||||
bool ChangeItemSelection(
|
||||
ListSelectedMap &selected,
|
||||
not_null<const HistoryItem*> item,
|
||||
ListItemSelectionData selectionData) {
|
||||
ListItemSelectionData selectionData,
|
||||
int limit) {
|
||||
if (!limit) {
|
||||
limit = MaxSelectedItems;
|
||||
}
|
||||
const auto changeExisting = [&](auto it) {
|
||||
if (it == selected.cend()) {
|
||||
return false;
|
||||
@@ -41,7 +45,7 @@ bool ChangeItemSelection(
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (selected.size() < MaxSelectedItems) {
|
||||
if (selected.size() < limit) {
|
||||
const auto &[i, ok] = selected.try_emplace(item, selectionData);
|
||||
if (ok) {
|
||||
return true;
|
||||
|
||||
@@ -90,7 +90,8 @@ using UniversalMsgId = MsgId;
|
||||
bool ChangeItemSelection(
|
||||
ListSelectedMap &selected,
|
||||
not_null<const HistoryItem*> item,
|
||||
ListItemSelectionData selectionData);
|
||||
ListItemSelectionData selectionData,
|
||||
int limit = 0);
|
||||
|
||||
class ListSectionDelegate {
|
||||
public:
|
||||
|
||||
@@ -47,8 +47,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/inactive_press.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
@@ -148,9 +149,10 @@ ListWidget::ListWidget(
|
||||
, _controller(controller)
|
||||
, _provider(MakeProvider(_controller))
|
||||
, _dateBadge(std::make_unique<DateBadge>(
|
||||
_provider->type(),
|
||||
[=] { scrollDateCheck(); },
|
||||
[=] { scrollDateHide(); })) {
|
||||
_provider->type(),
|
||||
[=] { scrollDateCheck(); },
|
||||
[=] { scrollDateHide(); }))
|
||||
, _storiesAddToAlbumId(controller->storiesAddToAlbumId()) {
|
||||
start();
|
||||
}
|
||||
|
||||
@@ -184,6 +186,7 @@ void ListWidget::start() {
|
||||
_provider->setSearchQuery(std::move(query));
|
||||
}, lifetime());
|
||||
} else if (_controller->storiesPeer()) {
|
||||
setupStoriesTrackIds();
|
||||
trackSession(&session());
|
||||
restart();
|
||||
} else {
|
||||
@@ -260,6 +263,41 @@ void ListWidget::setupSelectRestriction() {
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void ListWidget::setupStoriesTrackIds() {
|
||||
if (!_storiesAddToAlbumId) {
|
||||
return;
|
||||
}
|
||||
const auto peerId = _controller->storiesPeer()->id;
|
||||
const auto stories = &session().data().stories();
|
||||
constexpr auto kArchive = Data::kStoriesAlbumIdArchive;
|
||||
const auto key = Data::StoryAlbumIdsKey{ peerId, kArchive };
|
||||
rpl::single(rpl::empty) | rpl::then(
|
||||
stories->albumIdsChanged() | rpl::filter(
|
||||
rpl::mappers::_1 == key
|
||||
) | rpl::to_empty
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto albumId = _storiesAddToAlbumId;
|
||||
const auto &ids = stories->albumKnownInArchive(peerId, albumId);
|
||||
if (_storiesInAlbum != ids) {
|
||||
for (const auto id : ids) {
|
||||
if (_storiesInAlbum.emplace(id).second) {
|
||||
_storyMsgsToMarkSelected.emplace(StoryIdToMsgId(id));
|
||||
}
|
||||
}
|
||||
if (_storiesInAlbum.size() > ids.size()) {
|
||||
for (auto i = begin(_storiesInAlbum); i != end(_storiesInAlbum);) {
|
||||
if (ids.contains(*i)) {
|
||||
++i;
|
||||
} else {
|
||||
_storyMsgsToMarkSelected.remove(StoryIdToMsgId(*i));
|
||||
i = _storiesInAlbum.erase(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
rpl::producer<int> ListWidget::scrollToRequests() const {
|
||||
return _scrollToRequests.events();
|
||||
}
|
||||
@@ -544,6 +582,37 @@ void ListWidget::trackSession(not_null<Main::Session*> session) {
|
||||
}, lifetime);
|
||||
}
|
||||
|
||||
void ListWidget::markStoryMsgsSelected() {
|
||||
const auto now = int(_storyMsgsToMarkSelected.size());
|
||||
const auto guard = gsl::finally([&] {
|
||||
if (now != int(_storyMsgsToMarkSelected.size())) {
|
||||
pushSelectedItems();
|
||||
}
|
||||
});
|
||||
const auto &appConfig = _controller->session().appConfig();
|
||||
const auto selectLimit = appConfig.storiesAlbumLimit();
|
||||
const auto selection = FullSelection;
|
||||
for (const auto §ion : _sections) {
|
||||
for (const auto &entry : section.items()) {
|
||||
const auto item = entry->getItem();
|
||||
const auto id = item->id;
|
||||
const auto i = _storyMsgsToMarkSelected.find(id);
|
||||
if (i != end(_storyMsgsToMarkSelected)) {
|
||||
ChangeItemSelection(
|
||||
_selected,
|
||||
item,
|
||||
_provider->computeSelectionData(item, selection),
|
||||
selectLimit);
|
||||
repaintItem(item);
|
||||
_storyMsgsToMarkSelected.erase(i);
|
||||
if (_storyMsgsToMarkSelected.empty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ListWidget::refreshRows() {
|
||||
saveScrollState();
|
||||
|
||||
@@ -554,6 +623,8 @@ void ListWidget::refreshRows() {
|
||||
for (const auto &item : _sections.back().items()) {
|
||||
trackSession(&item->getItem()->history()->session());
|
||||
}
|
||||
} else if (!_storyMsgsToMarkSelected.empty()) {
|
||||
markStoryMsgsSelected();
|
||||
}
|
||||
|
||||
if (const auto count = _provider->fullCount()) {
|
||||
@@ -819,8 +890,9 @@ void ListWidget::paintEvent(QPaintEvent *e) {
|
||||
const auto window = _controller->parentController();
|
||||
const auto paused = window->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::Layer);
|
||||
const auto selecting = hasSelectedItems() || _storiesAddToAlbumId;
|
||||
auto context = ListContext{
|
||||
Overview::Layout::PaintContext(ms, hasSelectedItems(), paused),
|
||||
Overview::Layout::PaintContext(ms, selecting, paused),
|
||||
&_selected,
|
||||
&_dragSelected,
|
||||
_dragSelectAction
|
||||
@@ -890,6 +962,9 @@ void ListWidget::mouseDoubleClickEvent(QMouseEvent *e) {
|
||||
void ListWidget::showContextMenu(
|
||||
QContextMenuEvent *e,
|
||||
ContextMenuSource source) {
|
||||
if (_storiesAddToAlbumId) {
|
||||
return;
|
||||
}
|
||||
if (_contextMenu) {
|
||||
_contextMenu = nullptr;
|
||||
repaintItem(_contextItem);
|
||||
@@ -1487,11 +1562,15 @@ void ListWidget::switchToWordSelection() {
|
||||
void ListWidget::applyItemSelection(
|
||||
HistoryItem *item,
|
||||
TextSelection selection) {
|
||||
const auto selectLimit = _storiesAddToAlbumId
|
||||
? _controller->session().appConfig().storiesAlbumLimit()
|
||||
: MaxSelectedItems;
|
||||
if (item
|
||||
&& ChangeItemSelection(
|
||||
_selected,
|
||||
item,
|
||||
_provider->computeSelectionData(item, selection))) {
|
||||
_provider->computeSelectionData(item, selection),
|
||||
selectLimit)) {
|
||||
repaintItem(item);
|
||||
pushSelectedItems();
|
||||
}
|
||||
@@ -1961,22 +2040,21 @@ void ListWidget::mouseActionFinish(
|
||||
auto pressState = base::take(_pressState);
|
||||
repaintItem(pressState.item);
|
||||
|
||||
const auto selectionMode = hasSelectedItems() || _storiesAddToAlbumId;
|
||||
auto simpleSelectionChange = pressState.item
|
||||
&& pressState.inside
|
||||
&& !_pressWasInactive
|
||||
&& (button != Qt::RightButton)
|
||||
&& (_mouseAction == MouseAction::PrepareDrag
|
||||
|| _mouseAction == MouseAction::PrepareSelect);
|
||||
auto needSelectionToggle = simpleSelectionChange
|
||||
&& hasSelectedItems();
|
||||
auto needSelectionClear = simpleSelectionChange
|
||||
&& hasSelectedText();
|
||||
auto needSelectionToggle = simpleSelectionChange && selectionMode;
|
||||
auto needSelectionClear = simpleSelectionChange && hasSelectedText();
|
||||
|
||||
auto activated = ClickHandler::unpressed();
|
||||
if (_mouseAction == MouseAction::Dragging
|
||||
|| _mouseAction == MouseAction::Selecting) {
|
||||
activated = nullptr;
|
||||
} else if (needSelectionToggle) {
|
||||
} else if (needSelectionToggle || _storiesAddToAlbumId) {
|
||||
activated = nullptr;
|
||||
}
|
||||
|
||||
@@ -2034,11 +2112,15 @@ void ListWidget::applyDragSelection() {
|
||||
|
||||
void ListWidget::applyDragSelection(SelectedMap &applyTo) const {
|
||||
if (_dragSelectAction == DragSelectAction::Selecting) {
|
||||
const auto selectLimit = _storiesAddToAlbumId
|
||||
? _controller->session().appConfig().storiesAlbumLimit()
|
||||
: MaxSelectedItems;
|
||||
for (auto &[item, data] : _dragSelected) {
|
||||
ChangeItemSelection(
|
||||
applyTo,
|
||||
item,
|
||||
_provider->computeSelectionData(item, FullSelection));
|
||||
_provider->computeSelectionData(item, FullSelection),
|
||||
selectLimit);
|
||||
}
|
||||
} else if (_dragSelectAction == DragSelectAction::Deselecting) {
|
||||
for (auto &[item, data] : _dragSelected) {
|
||||
|
||||
@@ -171,6 +171,7 @@ private:
|
||||
void itemLayoutChanged(not_null<const HistoryItem*> item);
|
||||
|
||||
void refreshRows();
|
||||
void markStoryMsgsSelected();
|
||||
void trackSession(not_null<Main::Session*> session);
|
||||
|
||||
[[nodiscard]] SelectedItems collectSelectedItems() const;
|
||||
@@ -274,6 +275,8 @@ private:
|
||||
|
||||
void setActionBoxWeak(base::weak_qptr<Ui::BoxContent> box);
|
||||
|
||||
void setupStoriesTrackIds();
|
||||
|
||||
const not_null<AbstractController*> _controller;
|
||||
const std::unique_ptr<ListProvider> _provider;
|
||||
|
||||
@@ -305,6 +308,10 @@ private:
|
||||
|
||||
const std::unique_ptr<DateBadge> _dateBadge;
|
||||
|
||||
int _storiesAddToAlbumId = 0;
|
||||
base::flat_set<StoryId> _storiesInAlbum;
|
||||
base::flat_set<MsgId> _storyMsgsToMarkSelected;
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> _contextMenu;
|
||||
rpl::event_stream<> _checkForHide;
|
||||
base::weak_qptr<Ui::BoxContent> _actionBoxWeak;
|
||||
|
||||
@@ -12,13 +12,18 @@ namespace Info::Stories {
|
||||
[[nodiscard]] int ArchiveId();
|
||||
|
||||
struct Tag {
|
||||
explicit Tag(not_null<PeerData*> peer, int albumId = 0)
|
||||
explicit Tag(
|
||||
not_null<PeerData*> peer,
|
||||
int albumId = 0,
|
||||
int addingToAlbumId = 0)
|
||||
: peer(peer)
|
||||
, albumId(albumId) {
|
||||
, albumId(albumId)
|
||||
, addingToAlbumId(addingToAlbumId) {
|
||||
}
|
||||
|
||||
not_null<PeerData*> peer;
|
||||
int albumId = 0;
|
||||
int addingToAlbumId = 0;
|
||||
};
|
||||
|
||||
} // namespace Info::Stories
|
||||
|
||||
@@ -47,6 +47,150 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace Info::Stories {
|
||||
namespace {
|
||||
|
||||
class EditAlbumBox final : public Ui::BoxContent {
|
||||
public:
|
||||
EditAlbumBox(
|
||||
QWidget*,
|
||||
not_null<Controller*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void()> reload,
|
||||
int albumId);
|
||||
|
||||
private:
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
const not_null<Window::SessionController*> _window;
|
||||
const not_null<WrapWidget*> _content;
|
||||
rpl::variable<Data::StoryAlbumUpdate> _changes;
|
||||
Fn<void()> _reload;
|
||||
bool _saving = false;
|
||||
|
||||
};
|
||||
|
||||
EditAlbumBox::EditAlbumBox(
|
||||
QWidget*,
|
||||
not_null<Controller*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void()> reload,
|
||||
int albumId)
|
||||
: _window(controller->parentController())
|
||||
, _content(Ui::CreateChild<WrapWidget>(
|
||||
this,
|
||||
_window,
|
||||
Wrap::StoryAlbumEdit,
|
||||
std::make_shared<Info::Memento>(
|
||||
std::vector<std::shared_ptr<ContentMemento>>(
|
||||
1,
|
||||
std::make_shared<Memento>(
|
||||
peer,
|
||||
Data::kStoriesAlbumIdArchive,
|
||||
albumId))).get()))
|
||||
, _changes(Data::StoryAlbumUpdate{ .peer = peer, .albumId = albumId })
|
||||
, _reload(std::move(reload)) {
|
||||
_content->selectedListValue(
|
||||
) | rpl::start_with_next([=](const SelectedItems &selection) {
|
||||
const auto stories = &_window->session().data().stories();
|
||||
auto ids = stories->albumKnownInArchive(peer->id, albumId);
|
||||
auto now = _changes.current();
|
||||
now.added.clear();
|
||||
now.added.reserve(selection.list.size());
|
||||
now.removed.clear();
|
||||
now.removed.reserve(ids.size());
|
||||
for (const auto &entry : selection.list) {
|
||||
const auto id = StoryIdFromMsgId(entry.globalId.itemId.msg);
|
||||
if (!ids.remove(id)) {
|
||||
now.added.push_back(id);
|
||||
}
|
||||
}
|
||||
for (const auto id : ids) {
|
||||
now.removed.push_back(id);
|
||||
}
|
||||
_changes = std::move(now);
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void EditAlbumBox::prepare() {
|
||||
setTitle(tr::lng_stories_album_add_title());
|
||||
setStyle(st::collectionEditBox);
|
||||
|
||||
_content->desiredHeightValue(
|
||||
) | rpl::start_with_next([=](int height) {
|
||||
setDimensions(st::boxWideWidth, height);
|
||||
}, _content->lifetime());
|
||||
|
||||
addTopButton(st::boxTitleClose, [=] {
|
||||
closeBox();
|
||||
});
|
||||
|
||||
const auto weakBox = base::make_weak(this);
|
||||
auto text = _changes.value(
|
||||
) | rpl::map([=](const Data::StoryAlbumUpdate &update) {
|
||||
return (!update.added.empty() && update.removed.empty())
|
||||
? tr::lng_stories_album_add_title()
|
||||
: tr::lng_settings_save();
|
||||
}) | rpl::flatten_latest();
|
||||
addButton(std::move(text), [=] {
|
||||
if (_saving) {
|
||||
return;
|
||||
}
|
||||
auto add = QVector<MTPint>();
|
||||
auto remove = QVector<MTPint>();
|
||||
const auto &changes = _changes.current();
|
||||
for (const auto &id : changes.added) {
|
||||
add.push_back(MTP_int(id));
|
||||
}
|
||||
for (const auto &id : changes.removed) {
|
||||
remove.push_back(MTP_int(id));
|
||||
}
|
||||
if (add.empty() && remove.empty()) {
|
||||
closeBox();
|
||||
return;
|
||||
}
|
||||
_saving = true;
|
||||
const auto session = &_window->session();
|
||||
const auto reload = _reload;
|
||||
using Flag = MTPstories_UpdateAlbum::Flag;
|
||||
session->api().request(
|
||||
MTPstories_UpdateAlbum(
|
||||
MTP_flags(Flag()
|
||||
| (add.isEmpty() ? Flag() : Flag::f_add_stories)
|
||||
| (remove.isEmpty()
|
||||
? Flag()
|
||||
: Flag::f_delete_stories)),
|
||||
changes.peer->input,
|
||||
MTP_int(changes.albumId),
|
||||
MTPstring(),
|
||||
MTP_vector<MTPint>(remove),
|
||||
MTP_vector<MTPint>(add),
|
||||
MTPVector<MTPint>())
|
||||
).done([=] {
|
||||
if (const auto strong = weakBox.get()) {
|
||||
strong->_saving = false;
|
||||
strong->closeBox();
|
||||
}
|
||||
session->data().stories().notifyAlbumUpdate(
|
||||
base::duplicate(changes));
|
||||
if (const auto onstack = reload) {
|
||||
onstack();
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (const auto strong = weakBox.get()) {
|
||||
strong->_saving = false;
|
||||
strong->uiShow()->showToast(error.type());
|
||||
}
|
||||
}).send();
|
||||
});
|
||||
}
|
||||
|
||||
void EditAlbumBox::resizeEvent(QResizeEvent *e) {
|
||||
_content->setGeometry(rect());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
InnerWidget::InnerWidget(
|
||||
QWidget *parent,
|
||||
@@ -66,11 +210,8 @@ InnerWidget::InnerWidget(
|
||||
|
||||
_albumId.value(
|
||||
) | rpl::start_with_next([=](int albumId) {
|
||||
_list.destroy();
|
||||
_controller->replaceKey(Key(Tag(_peer, albumId)));
|
||||
setupList();
|
||||
setupEmpty();
|
||||
resizeToWidth(width());
|
||||
_controller->replaceKey(Key(Tag(_peer, albumId, _addingToAlbumId)));
|
||||
reload();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
@@ -108,7 +249,9 @@ InnerWidget::~InnerWidget() = default;
|
||||
|
||||
void InnerWidget::setupTop() {
|
||||
const auto albumId = _albumId.current();
|
||||
if (albumId == Data::kStoriesAlbumIdArchive) {
|
||||
if (_addingToAlbumId) {
|
||||
return;
|
||||
} else if (albumId == Data::kStoriesAlbumIdArchive) {
|
||||
createAboutArchive();
|
||||
} else if (_isStackBottom) {
|
||||
if (_peer->isSelf()) {
|
||||
@@ -608,107 +751,24 @@ rpl::producer<Data::StoryAlbumUpdate> InnerWidget::changes() const {
|
||||
return _albumChanges.value();
|
||||
}
|
||||
|
||||
void InnerWidget::reloadAlbum(int id) {
|
||||
// #TODO stories
|
||||
void InnerWidget::reload() {
|
||||
auto old = std::exchange(_list, object_ptr<Media::ListWidget>(nullptr));
|
||||
setupList();
|
||||
setupEmpty();
|
||||
old.destroy();
|
||||
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
||||
void InnerWidget::editAlbumStories(int id) {
|
||||
const auto weak = base::make_weak(this);
|
||||
_controller->uiShow()->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
box->setTitle(tr::lng_stories_album_add_title());
|
||||
box->setWidth(st::boxWideWidth);
|
||||
box->setStyle(st::collectionEditBox);
|
||||
auto box = Box<EditAlbumBox>(_controller, _peer, crl::guard(this, [=] {
|
||||
if (_albumId.current() == id) {
|
||||
reload();
|
||||
}
|
||||
}), id);
|
||||
|
||||
struct State {
|
||||
rpl::variable<Data::StoryAlbumUpdate> changes;
|
||||
base::unique_qptr<Ui::PopupMenu> menu;
|
||||
bool saving = false;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>(State{
|
||||
.changes = Data::StoryAlbumUpdate{
|
||||
.peer = _peer,
|
||||
.albumId = id,
|
||||
}
|
||||
});
|
||||
const auto content = box->addRow(
|
||||
object_ptr<InnerWidget>(
|
||||
box,
|
||||
_controller,
|
||||
rpl::single(Data::kStoriesAlbumIdArchive),
|
||||
id/*,
|
||||
_peer,
|
||||
state->descriptor.value(),
|
||||
id,
|
||||
(_all.filter == Filter()) ? _all : Entries()*/),
|
||||
{});
|
||||
state->changes = content->changes();
|
||||
|
||||
content->scrollToRequests(
|
||||
) | rpl::start_with_next([=](Ui::ScrollToRequest request) {
|
||||
box->scrollTo(request);
|
||||
}, content->lifetime());
|
||||
|
||||
box->addTopButton(st::boxTitleClose, [=] {
|
||||
box->closeBox();
|
||||
});
|
||||
const auto weakBox = base::make_weak(box);
|
||||
auto text = state->changes.value(
|
||||
) | rpl::map([=](const Data::StoryAlbumUpdate &update) {
|
||||
return (!update.added.empty() && update.removed.empty())
|
||||
? tr::lng_stories_album_add_title()
|
||||
: tr::lng_settings_save();
|
||||
}) | rpl::flatten_latest();
|
||||
box->addButton(std::move(text), [=] {
|
||||
if (state->saving) {
|
||||
return;
|
||||
}
|
||||
auto add = QVector<MTPint>();
|
||||
auto remove = QVector<MTPint>();
|
||||
const auto &changes = state->changes.current();
|
||||
for (const auto &id : changes.added) {
|
||||
add.push_back(MTP_int(id));
|
||||
}
|
||||
for (const auto &id : changes.removed) {
|
||||
remove.push_back(MTP_int(id));
|
||||
}
|
||||
if (add.empty() && remove.empty()) {
|
||||
box->closeBox();
|
||||
return;
|
||||
}
|
||||
state->saving = true;
|
||||
const auto session = &_controller->session();
|
||||
using Flag = MTPstories_UpdateAlbum::Flag;
|
||||
session->api().request(
|
||||
MTPstories_UpdateAlbum(
|
||||
MTP_flags(Flag()
|
||||
| (add.isEmpty() ? Flag() : Flag::f_add_stories)
|
||||
| (remove.isEmpty()
|
||||
? Flag()
|
||||
: Flag::f_delete_stories)),
|
||||
_peer->input,
|
||||
MTP_int(id),
|
||||
MTPstring(),
|
||||
MTP_vector<MTPint>(remove),
|
||||
MTP_vector<MTPint>(add),
|
||||
MTPVector<MTPint>())
|
||||
).done([=] {
|
||||
if (const auto strong = weakBox.get()) {
|
||||
state->saving = false;
|
||||
strong->closeBox();
|
||||
}
|
||||
session->data().stories().notifyAlbumUpdate(
|
||||
base::duplicate(changes));
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->reloadAlbum(id);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (const auto strong = weakBox.get()) {
|
||||
state->saving = false;
|
||||
strong->uiShow()->showToast(error.type());
|
||||
}
|
||||
}).send();
|
||||
});
|
||||
}));
|
||||
_controller->uiShow()->show(std::move(box));
|
||||
}
|
||||
|
||||
void InnerWidget::editAlbumName(int id) {
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
rpl::producer<SelectedItems> selectedListValue() const;
|
||||
void selectionAction(SelectionAction action);
|
||||
|
||||
void reloadAlbum(int id);
|
||||
void reload();
|
||||
void editAlbumStories(int id);
|
||||
void editAlbumName(int id);
|
||||
void confirmDeleteAlbum(int id);
|
||||
|
||||
@@ -49,7 +49,8 @@ Provider::Provider(not_null<AbstractController*> controller)
|
||||
: _controller(controller)
|
||||
, _peer(controller->key().storiesPeer())
|
||||
, _history(_peer->owner().history(_peer))
|
||||
, _albumId(controller->key().storiesAlbumId()) {
|
||||
, _albumId(controller->key().storiesAlbumId())
|
||||
, _addingToAlbumId(controller->key().storiesAddToAlbumId()) {
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
for (auto &layout : _layouts) {
|
||||
@@ -366,7 +367,7 @@ ListItemSelectionData Provider::computeSelectionData(
|
||||
TextSelection selection) {
|
||||
auto result = ListItemSelectionData(selection);
|
||||
const auto id = item->id;
|
||||
if (!IsStoryMsgId(id)) {
|
||||
if (_addingToAlbumId || !IsStoryMsgId(id)) {
|
||||
return result;
|
||||
}
|
||||
const auto peer = item->history()->peer;
|
||||
|
||||
@@ -117,6 +117,7 @@ private:
|
||||
const not_null<PeerData*> _peer;
|
||||
const not_null<History*> _history;
|
||||
const int _albumId = 0;
|
||||
const int _addingToAlbumId = 0;
|
||||
|
||||
StoryId _aroundId = kDefaultAroundId;
|
||||
int _idsLimit = kMinimalIdsLimit;
|
||||
|
||||
@@ -29,8 +29,8 @@ Memento::Memento(not_null<Controller*> controller)
|
||||
, _media(controller) {
|
||||
}
|
||||
|
||||
Memento::Memento(not_null<PeerData*> peer, int albumId)
|
||||
: ContentMemento(Tag{ peer, albumId })
|
||||
Memento::Memento(not_null<PeerData*> peer, int albumId, int addingToAlbumId)
|
||||
: ContentMemento(Tag{ peer, albumId, addingToAlbumId })
|
||||
, _media(peer, 0, Media::Type::PhotoVideo) {
|
||||
}
|
||||
|
||||
@@ -57,7 +57,8 @@ Widget::Widget(
|
||||
_inner = setInnerWidget(object_ptr<InnerWidget>(
|
||||
this,
|
||||
controller,
|
||||
_albumId.value()));
|
||||
_albumId.value(),
|
||||
controller->key().storiesAddToAlbumId()));
|
||||
_inner->albumIdChanges() | rpl::start_with_next([=](int id) {
|
||||
controller->showSection(
|
||||
Make(controller->storiesPeer(), id),
|
||||
@@ -139,7 +140,7 @@ std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer, int albumId) {
|
||||
return std::make_shared<Info::Memento>(
|
||||
std::vector<std::shared_ptr<ContentMemento>>(
|
||||
1,
|
||||
std::make_shared<Memento>(peer, albumId)));
|
||||
std::make_shared<Memento>(peer, albumId, 0)));
|
||||
}
|
||||
|
||||
} // namespace Info::Stories
|
||||
|
||||
@@ -18,7 +18,7 @@ class InnerWidget;
|
||||
class Memento final : public ContentMemento {
|
||||
public:
|
||||
Memento(not_null<Controller*> controller);
|
||||
Memento(not_null<PeerData*> peer, int albumId);
|
||||
Memento(not_null<PeerData*> peer, int albumId, int addingToAlbumId);
|
||||
~Memento();
|
||||
|
||||
object_ptr<ContentWidget> createWidget(
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
|
||||
private:
|
||||
Media::Memento _media;
|
||||
int _addingToAlbumId = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -238,6 +238,14 @@ QString AppConfig::starsRatingLearnMoreUrl() const {
|
||||
u"https://telegram.org/blog"_q);
|
||||
}
|
||||
|
||||
int AppConfig::storiesAlbumsLimit() const {
|
||||
return get<int>(u"stories_albums_limit"_q, 100);
|
||||
}
|
||||
|
||||
int AppConfig::storiesAlbumLimit() const {
|
||||
return get<int>(u"stories_album_stories_limit"_q, 1000);
|
||||
}
|
||||
|
||||
void AppConfig::refresh(bool force) {
|
||||
if (_requestId || !_api) {
|
||||
if (force) {
|
||||
|
||||
@@ -111,6 +111,9 @@ public:
|
||||
|
||||
[[nodiscard]] QString starsRatingLearnMoreUrl() const;
|
||||
|
||||
[[nodiscard]] int storiesAlbumsLimit() const;
|
||||
[[nodiscard]] int storiesAlbumLimit() const;
|
||||
|
||||
void refresh(bool force = false);
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user