2017-10-31 18:25:22 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
2018-01-03 10:23:14 +00:00
|
|
|
the official desktop application for the Telegram messaging service.
|
2017-10-31 18:25:22 +00:00
|
|
|
|
2018-01-03 10:23:14 +00:00
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
2017-10-31 18:25:22 +00:00
|
|
|
*/
|
|
|
|
#include "info/info_controller.h"
|
|
|
|
|
2017-11-14 17:22:44 +00:00
|
|
|
#include <rpl/range.h>
|
|
|
|
#include <rpl/then.h>
|
2017-10-31 18:25:22 +00:00
|
|
|
#include "ui/search_field_controller.h"
|
2017-11-06 07:31:18 +00:00
|
|
|
#include "data/data_shared_media.h"
|
2017-10-31 18:25:22 +00:00
|
|
|
#include "info/info_content_widget.h"
|
|
|
|
#include "info/info_memento.h"
|
2017-11-03 15:47:08 +00:00
|
|
|
#include "info/media/info_media_widget.h"
|
2020-06-12 12:12:34 +00:00
|
|
|
#include "data/data_changes.h"
|
2019-01-04 11:09:48 +00:00
|
|
|
#include "data/data_peer.h"
|
|
|
|
#include "data/data_channel.h"
|
|
|
|
#include "data/data_chat.h"
|
2019-01-18 12:27:37 +00:00
|
|
|
#include "data/data_session.h"
|
2020-01-15 11:53:42 +00:00
|
|
|
#include "data/data_media_types.h"
|
|
|
|
#include "history/history_item.h"
|
2019-07-24 11:45:24 +00:00
|
|
|
#include "main/main_session.h"
|
2019-06-06 10:21:40 +00:00
|
|
|
#include "window/window_session_controller.h"
|
2017-10-31 18:25:22 +00:00
|
|
|
|
|
|
|
namespace Info {
|
|
|
|
|
2018-01-22 19:51:38 +00:00
|
|
|
Key::Key(not_null<PeerData*> peer) : _value(peer) {
|
|
|
|
}
|
|
|
|
|
2018-09-05 19:05:49 +00:00
|
|
|
Key::Key(Settings::Tag settings) : _value(settings) {
|
|
|
|
}
|
|
|
|
|
2020-01-15 11:53:42 +00:00
|
|
|
Key::Key(not_null<PollData*> poll, FullMsgId contextId)
|
|
|
|
: _value(PollKey{ poll, contextId }) {
|
|
|
|
}
|
|
|
|
|
2018-01-22 19:51:38 +00:00
|
|
|
PeerData *Key::peer() const {
|
2020-08-31 08:14:53 +00:00
|
|
|
if (const auto peer = std::get_if<not_null<PeerData*>>(&_value)) {
|
2018-01-22 19:51:38 +00:00
|
|
|
return *peer;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-09-05 19:05:49 +00:00
|
|
|
UserData *Key::settingsSelf() const {
|
2020-08-31 08:14:53 +00:00
|
|
|
if (const auto tag = std::get_if<Settings::Tag>(&_value)) {
|
2018-09-05 19:05:49 +00:00
|
|
|
return tag->self;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-01-15 11:53:42 +00:00
|
|
|
PollData *Key::poll() const {
|
2020-08-31 08:14:53 +00:00
|
|
|
if (const auto data = std::get_if<PollKey>(&_value)) {
|
2020-01-15 11:53:42 +00:00
|
|
|
return data->poll;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
FullMsgId Key::pollContextId() const {
|
2020-08-31 08:14:53 +00:00
|
|
|
if (const auto data = std::get_if<PollKey>(&_value)) {
|
2020-01-15 11:53:42 +00:00
|
|
|
return data->contextId;
|
|
|
|
}
|
|
|
|
return FullMsgId();
|
|
|
|
}
|
|
|
|
|
2017-12-09 15:13:06 +00:00
|
|
|
rpl::producer<SparseIdsMergedSlice> AbstractController::mediaSource(
|
|
|
|
SparseIdsMergedSlice::UniversalMsgId aroundId,
|
|
|
|
int limitBefore,
|
|
|
|
int limitAfter) const {
|
2020-06-08 09:06:50 +00:00
|
|
|
Expects(peer() != nullptr);
|
|
|
|
|
2021-07-01 12:00:09 +00:00
|
|
|
const auto isScheduled = [&] {
|
|
|
|
if (IsServerMsgId(aroundId)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto channelId = peerToChannel(peer()->id);
|
|
|
|
if (const auto item = session().data().message(channelId, aroundId)) {
|
|
|
|
return item->isScheduled();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}();
|
|
|
|
|
|
|
|
auto mediaViewer = isScheduled
|
|
|
|
? SharedScheduledMediaViewer
|
|
|
|
: SharedMediaMergedViewer;
|
|
|
|
|
|
|
|
return mediaViewer(
|
2020-06-08 09:06:50 +00:00
|
|
|
&session(),
|
2017-12-09 15:13:06 +00:00
|
|
|
SharedMediaMergedKey(
|
|
|
|
SparseIdsMergedSlice::Key(
|
2020-06-08 09:06:50 +00:00
|
|
|
peer()->id,
|
2017-12-09 15:13:06 +00:00
|
|
|
migratedPeerId(),
|
|
|
|
aroundId),
|
|
|
|
section().mediaType()),
|
|
|
|
limitBefore,
|
|
|
|
limitAfter);
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl::producer<QString> AbstractController::mediaSourceQueryValue() const {
|
|
|
|
return rpl::single(QString());
|
|
|
|
}
|
|
|
|
|
2019-06-06 10:21:40 +00:00
|
|
|
AbstractController::AbstractController(
|
|
|
|
not_null<Window::SessionController*> parent)
|
|
|
|
: SessionNavigation(&parent->session())
|
2019-01-18 12:27:37 +00:00
|
|
|
, _parent(parent) {
|
|
|
|
}
|
|
|
|
|
2020-06-08 09:06:50 +00:00
|
|
|
PeerData *AbstractController::peer() const {
|
|
|
|
return key().peer();
|
2019-01-04 11:09:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PeerId AbstractController::migratedPeerId() const {
|
|
|
|
if (const auto peer = migrated()) {
|
|
|
|
return peer->id;
|
|
|
|
}
|
|
|
|
return PeerId(0);
|
|
|
|
}
|
|
|
|
|
2020-01-15 11:53:42 +00:00
|
|
|
PollData *AbstractController::poll() const {
|
|
|
|
if (const auto item = session().data().message(pollContextId())) {
|
|
|
|
if (const auto media = item->media()) {
|
|
|
|
return media->poll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-12-09 15:13:06 +00:00
|
|
|
void AbstractController::showSection(
|
2020-12-14 14:48:10 +00:00
|
|
|
std::shared_ptr<Window::SectionMemento> memento,
|
2017-12-09 15:13:06 +00:00
|
|
|
const Window::SectionShow ¶ms) {
|
|
|
|
return parentController()->showSection(std::move(memento), params);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractController::showBackFromStack(
|
|
|
|
const Window::SectionShow ¶ms) {
|
|
|
|
return parentController()->showBackFromStack(params);
|
|
|
|
}
|
|
|
|
|
2020-09-22 15:05:07 +00:00
|
|
|
void AbstractController::showPeerHistory(
|
|
|
|
PeerId peerId,
|
|
|
|
const Window::SectionShow ¶ms,
|
|
|
|
MsgId msgId) {
|
|
|
|
return parentController()->showPeerHistory(peerId, params, msgId);
|
|
|
|
}
|
|
|
|
|
2017-10-31 18:25:22 +00:00
|
|
|
Controller::Controller(
|
|
|
|
not_null<WrapWidget*> widget,
|
2019-06-06 10:21:40 +00:00
|
|
|
not_null<Window::SessionController*> window,
|
2017-10-31 18:25:22 +00:00
|
|
|
not_null<ContentMemento*> memento)
|
2017-12-09 15:13:06 +00:00
|
|
|
: AbstractController(window)
|
|
|
|
, _widget(widget)
|
2018-09-05 19:05:49 +00:00
|
|
|
, _key(memento->key())
|
2017-10-31 18:25:22 +00:00
|
|
|
, _migrated(memento->migratedPeerId()
|
2020-06-08 09:06:50 +00:00
|
|
|
? window->session().data().peer(memento->migratedPeerId()).get()
|
2017-10-31 18:25:22 +00:00
|
|
|
: nullptr)
|
|
|
|
, _section(memento->section()) {
|
2017-11-03 15:47:08 +00:00
|
|
|
updateSearchControllers(memento);
|
2017-11-06 12:14:44 +00:00
|
|
|
setupMigrationViewer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::setupMigrationViewer() {
|
2018-01-22 19:51:38 +00:00
|
|
|
const auto peer = _key.peer();
|
|
|
|
if (!peer || (!peer->isChat() && !peer->isChannel()) || _migrated) {
|
2017-11-06 12:14:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-06-12 12:12:34 +00:00
|
|
|
peer->session().changes().peerFlagsValue(
|
2018-01-22 19:51:38 +00:00
|
|
|
peer,
|
2020-06-12 12:12:34 +00:00
|
|
|
Data::PeerUpdate::Flag::Migration
|
|
|
|
) | rpl::filter([=] {
|
|
|
|
return peer->migrateTo() || (peer->migrateFrom() != _migrated);
|
|
|
|
}) | rpl::start_with_next([=] {
|
|
|
|
const auto window = parentController();
|
|
|
|
const auto section = _section;
|
|
|
|
InvokeQueued(_widget, [=] {
|
|
|
|
window->showSection(
|
2020-12-14 14:48:10 +00:00
|
|
|
std::make_shared<Memento>(peer, section),
|
2020-06-12 12:12:34 +00:00
|
|
|
Window::SectionShow(
|
|
|
|
Window::SectionShow::Way::Backward,
|
|
|
|
anim::type::instant,
|
|
|
|
anim::activation::background));
|
|
|
|
});
|
2017-12-22 07:05:20 +00:00
|
|
|
}, lifetime());
|
2017-10-31 18:25:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Wrap Controller::wrap() const {
|
|
|
|
return _widget->wrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl::producer<Wrap> Controller::wrapValue() const {
|
|
|
|
return _widget->wrapValue();
|
2017-11-03 12:03:00 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 18:25:22 +00:00
|
|
|
bool Controller::validateMementoPeer(
|
|
|
|
not_null<ContentMemento*> memento) const {
|
2020-06-08 09:06:50 +00:00
|
|
|
return memento->peer() == peer()
|
2018-01-22 19:51:38 +00:00
|
|
|
&& memento->migratedPeerId() == migratedPeerId()
|
2018-09-05 19:05:49 +00:00
|
|
|
&& memento->settingsSelf() == settingsSelf();
|
2017-10-31 18:25:22 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 15:47:08 +00:00
|
|
|
void Controller::setSection(not_null<ContentMemento*> memento) {
|
|
|
|
_section = memento->section();
|
|
|
|
updateSearchControllers(memento);
|
2017-10-31 18:25:22 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 15:47:08 +00:00
|
|
|
void Controller::updateSearchControllers(
|
|
|
|
not_null<ContentMemento*> memento) {
|
2017-11-17 13:23:36 +00:00
|
|
|
using Type = Section::Type;
|
|
|
|
auto type = _section.type();
|
|
|
|
auto isMedia = (type == Type::Media);
|
2017-10-31 18:25:22 +00:00
|
|
|
auto mediaType = isMedia
|
|
|
|
? _section.mediaType()
|
|
|
|
: Section::MediaType::kCount;
|
|
|
|
auto hasMediaSearch = isMedia
|
|
|
|
&& SharedMediaAllowSearch(mediaType);
|
2017-11-03 18:26:14 +00:00
|
|
|
auto hasCommonGroupsSearch
|
2017-11-17 13:23:36 +00:00
|
|
|
= (type == Type::CommonGroups);
|
2021-02-25 13:03:51 +00:00
|
|
|
auto hasMembersSearch = (type == Type::Members || type == Type::Profile);
|
2017-11-03 15:47:08 +00:00
|
|
|
auto searchQuery = memento->searchFieldQuery();
|
2017-10-31 18:25:22 +00:00
|
|
|
if (isMedia) {
|
|
|
|
_searchController
|
2019-11-27 08:02:56 +00:00
|
|
|
= std::make_unique<Api::DelayedSearchController>(&session());
|
2017-11-03 15:47:08 +00:00
|
|
|
auto mediaMemento = dynamic_cast<Media::Memento*>(memento.get());
|
|
|
|
Assert(mediaMemento != nullptr);
|
|
|
|
_searchController->restoreState(
|
|
|
|
mediaMemento->searchState());
|
2017-10-31 18:25:22 +00:00
|
|
|
} else {
|
|
|
|
_searchController = nullptr;
|
|
|
|
}
|
2017-11-17 13:23:36 +00:00
|
|
|
if (hasMediaSearch || hasCommonGroupsSearch || hasMembersSearch) {
|
2017-10-31 18:25:22 +00:00
|
|
|
_searchFieldController
|
2017-11-03 15:47:08 +00:00
|
|
|
= std::make_unique<Ui::SearchFieldController>(
|
|
|
|
searchQuery);
|
2017-11-03 18:26:14 +00:00
|
|
|
if (_searchController) {
|
2017-12-22 07:05:20 +00:00
|
|
|
_searchFieldController->queryValue(
|
|
|
|
) | rpl::start_with_next([=](QString &&query) {
|
|
|
|
_searchController->setQuery(
|
|
|
|
produceSearchQuery(std::move(query)));
|
|
|
|
}, _searchFieldController->lifetime());
|
2017-11-03 18:26:14 +00:00
|
|
|
}
|
|
|
|
_seachEnabledByContent = memento->searchEnabledByContent();
|
2017-12-08 08:14:30 +00:00
|
|
|
_searchStartsFocused = memento->searchStartsFocused();
|
2017-10-31 18:25:22 +00:00
|
|
|
} else {
|
|
|
|
_searchFieldController = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-03 15:47:08 +00:00
|
|
|
void Controller::saveSearchState(not_null<ContentMemento*> memento) {
|
|
|
|
if (_searchFieldController) {
|
|
|
|
memento->setSearchFieldQuery(
|
|
|
|
_searchFieldController->query());
|
2017-11-03 18:26:14 +00:00
|
|
|
memento->setSearchEnabledByContent(
|
|
|
|
_seachEnabledByContent.current());
|
2017-11-03 15:47:08 +00:00
|
|
|
}
|
|
|
|
if (_searchController) {
|
|
|
|
auto mediaMemento = dynamic_cast<Media::Memento*>(
|
|
|
|
memento.get());
|
|
|
|
Assert(mediaMemento != nullptr);
|
|
|
|
mediaMemento->setSearchState(_searchController->saveState());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-04 07:33:33 +00:00
|
|
|
void Controller::showSection(
|
2020-12-14 14:48:10 +00:00
|
|
|
std::shared_ptr<Window::SectionMemento> memento,
|
2017-12-04 07:33:33 +00:00
|
|
|
const Window::SectionShow ¶ms) {
|
2020-11-21 22:37:05 +00:00
|
|
|
if (!_widget->showInternal(memento.get(), params)) {
|
2017-12-09 15:13:06 +00:00
|
|
|
AbstractController::showSection(std::move(memento), params);
|
2017-12-04 07:33:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::showBackFromStack(const Window::SectionShow ¶ms) {
|
|
|
|
if (!_widget->showBackFromStackInternal(params)) {
|
2017-12-09 15:13:06 +00:00
|
|
|
AbstractController::showBackFromStack(params);
|
2017-12-04 07:33:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-31 18:25:22 +00:00
|
|
|
auto Controller::produceSearchQuery(
|
2017-11-03 15:47:08 +00:00
|
|
|
const QString &query) const -> SearchQuery {
|
2018-01-22 19:51:38 +00:00
|
|
|
Expects(_key.peer() != nullptr);
|
|
|
|
|
2017-10-31 18:25:22 +00:00
|
|
|
auto result = SearchQuery();
|
|
|
|
result.type = _section.mediaType();
|
2018-01-22 19:51:38 +00:00
|
|
|
result.peerId = _key.peer()->id;
|
2017-11-03 15:47:08 +00:00
|
|
|
result.query = query;
|
2017-10-31 18:25:22 +00:00
|
|
|
result.migratedPeerId = _migrated ? _migrated->id : PeerId(0);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-11-21 09:20:56 +00:00
|
|
|
rpl::producer<bool> Controller::searchEnabledByContent() const {
|
|
|
|
return _seachEnabledByContent.value();
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl::producer<QString> Controller::mediaSourceQueryValue() const {
|
|
|
|
return _searchController->currentQueryValue();
|
|
|
|
}
|
|
|
|
|
2017-10-31 18:25:22 +00:00
|
|
|
rpl::producer<SparseIdsMergedSlice> Controller::mediaSource(
|
|
|
|
SparseIdsMergedSlice::UniversalMsgId aroundId,
|
|
|
|
int limitBefore,
|
|
|
|
int limitAfter) const {
|
|
|
|
auto query = _searchController->currentQuery();
|
|
|
|
if (!query.query.isEmpty()) {
|
|
|
|
return _searchController->idsSlice(
|
|
|
|
aroundId,
|
|
|
|
limitBefore,
|
|
|
|
limitAfter);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SharedMediaMergedViewer(
|
2020-06-08 09:06:50 +00:00
|
|
|
&session(),
|
2017-10-31 18:25:22 +00:00
|
|
|
SharedMediaMergedKey(
|
|
|
|
SparseIdsMergedSlice::Key(
|
|
|
|
query.peerId,
|
|
|
|
query.migratedPeerId,
|
|
|
|
aroundId),
|
|
|
|
query.type),
|
|
|
|
limitBefore,
|
|
|
|
limitAfter);
|
|
|
|
}
|
|
|
|
|
2018-09-09 17:38:08 +00:00
|
|
|
void Controller::setCanSaveChanges(rpl::producer<bool> can) {
|
|
|
|
_canSaveChanges = std::move(can);
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl::producer<bool> Controller::canSaveChanges() const {
|
|
|
|
return _canSaveChanges.value();
|
|
|
|
}
|
|
|
|
|
2018-09-11 07:46:07 +00:00
|
|
|
bool Controller::canSaveChangesNow() const {
|
|
|
|
return _canSaveChanges.current();
|
|
|
|
}
|
|
|
|
|
2017-10-31 18:25:22 +00:00
|
|
|
Controller::~Controller() = default;
|
|
|
|
|
|
|
|
} // namespace Info
|