Handle forum-non_forum changes in realtime.

This commit is contained in:
John Preston 2022-10-12 16:57:17 +04:00
parent 04d06e5b12
commit 6695eda1be
35 changed files with 286 additions and 499 deletions

View file

@ -1032,11 +1032,15 @@ void Application::preventOrInvoke(Fn<void()> &&callback) {
} }
void Application::lockByPasscode() { void Application::lockByPasscode() {
enumerateWindows([&](not_null<Window::Controller*> w) {
_passcodeLock = true;
w->setupPasscodeLock();
});
}
void Application::maybeLockByPasscode() {
preventOrInvoke([=] { preventOrInvoke([=] {
enumerateWindows([&](not_null<Window::Controller*> w) { lockByPasscode();
_passcodeLock = true;
w->setupPasscodeLock();
});
}); });
} }
@ -1427,7 +1431,7 @@ void Application::startShortcuts() {
}); });
request->check(Command::Lock) && request->handle([=] { request->check(Command::Lock) && request->handle([=] {
if (!passcodeLocked() && _domain->local().hasLocalPasscode()) { if (!passcodeLocked() && _domain->local().hasLocalPasscode()) {
lockByPasscode(); maybeLockByPasscode();
return true; return true;
} }
return false; return false;

View file

@ -263,6 +263,7 @@ public:
[[nodiscard]] bool downloadPreventsQuit(); [[nodiscard]] bool downloadPreventsQuit();
void checkLocalTime(); void checkLocalTime();
void lockByPasscode(); void lockByPasscode();
void maybeLockByPasscode();
void unlockPasscode(); void unlockPasscode();
[[nodiscard]] bool passcodeLocked() const; [[nodiscard]] bool passcodeLocked() const;
rpl::producer<bool> passcodeLockChanges() const; rpl::producer<bool> passcodeLockChanges() const;

View file

@ -67,6 +67,18 @@ not_null<Dialogs::MainList*> Forum::topicsList() {
return &_topicsList; return &_topicsList;
} }
rpl::producer<> Forum::destroyed() const {
return channel()->flagsValue(
) | rpl::filter([=](const ChannelData::Flags::Change &update) {
using Flag = ChannelData::Flag;
return (update.diff & Flag::Forum) && !(update.value & Flag::Forum);
}) | rpl::take(1) | rpl::to_empty;
}
rpl::producer<not_null<ForumTopic*>> Forum::topicDestroyed() const {
return _topicDestroyed.events();
}
void Forum::requestTopics() { void Forum::requestTopics() {
if (_allLoaded || _requestId) { if (_allLoaded || _requestId) {
return; return;

View file

@ -34,6 +34,9 @@ public:
[[nodiscard]] not_null<History*> history() const; [[nodiscard]] not_null<History*> history() const;
[[nodiscard]] not_null<ChannelData*> channel() const; [[nodiscard]] not_null<ChannelData*> channel() const;
[[nodiscard]] not_null<Dialogs::MainList*> topicsList(); [[nodiscard]] not_null<Dialogs::MainList*> topicsList();
[[nodiscard]] rpl::producer<> destroyed() const;
[[nodiscard]] auto topicDestroyed() const
-> rpl::producer<not_null<ForumTopic*>>;
void requestTopics(); void requestTopics();
[[nodiscard]] rpl::producer<> chatsListChanges() const; [[nodiscard]] rpl::producer<> chatsListChanges() const;
@ -75,6 +78,7 @@ private:
const not_null<History*> _history; const not_null<History*> _history;
base::flat_map<MsgId, std::unique_ptr<ForumTopic>> _topics; base::flat_map<MsgId, std::unique_ptr<ForumTopic>> _topics;
rpl::event_stream<not_null<ForumTopic*>> _topicDestroyed;
Dialogs::MainList _topicsList; Dialogs::MainList _topicsList;
base::flat_map<MsgId, TopicRequest> _topicRequests; base::flat_map<MsgId, TopicRequest> _topicRequests;

View file

@ -138,8 +138,8 @@ QImage ForumTopicIconFrame(
ForumTopic::ForumTopic(not_null<History*> history, MsgId rootId) ForumTopic::ForumTopic(not_null<History*> history, MsgId rootId)
: Entry(&history->owner(), Type::ForumTopic) : Entry(&history->owner(), Type::ForumTopic)
, _history(history) , _forum(history->peer->forum())
, _list(forum()->topicsList()) , _list(_forum->topicsList())
, _replies(std::make_shared<RepliesList>(history, rootId)) , _replies(std::make_shared<RepliesList>(history, rootId))
, _rootId(rootId) { , _rootId(rootId) {
_replies->unreadCountValue( _replies->unreadCountValue(
@ -165,15 +165,22 @@ std::shared_ptr<Data::RepliesList> ForumTopic::replies() const {
} }
not_null<ChannelData*> ForumTopic::channel() const { not_null<ChannelData*> ForumTopic::channel() const {
return _history->peer->asChannel(); return _forum->channel();
} }
not_null<History*> ForumTopic::history() const { not_null<History*> ForumTopic::history() const {
return _history; return _forum->history();
} }
not_null<Forum*> ForumTopic::forum() const { not_null<Forum*> ForumTopic::forum() const {
return channel()->forum(); return _forum;
}
rpl::producer<> ForumTopic::destroyed() const {
using namespace rpl::mappers;
return rpl::merge(
_forum->destroyed(),
_forum->topicDestroyed() | rpl::filter(_1 == this) | rpl::to_empty);
} }
MsgId ForumTopic::rootId() const { MsgId ForumTopic::rootId() const {
@ -183,7 +190,7 @@ MsgId ForumTopic::rootId() const {
void ForumTopic::setRealRootId(MsgId realId) { void ForumTopic::setRealRootId(MsgId realId) {
if (_rootId != realId) { if (_rootId != realId) {
_rootId = realId; _rootId = realId;
_replies = std::make_shared<RepliesList>(_history, _rootId); _replies = std::make_shared<RepliesList>(history(), _rootId);
} }
} }
@ -252,7 +259,7 @@ int ForumTopic::chatListNameVersion() const {
void ForumTopic::applyTopicTopMessage(MsgId topMessageId) { void ForumTopic::applyTopicTopMessage(MsgId topMessageId) {
if (topMessageId) { if (topMessageId) {
const auto itemId = FullMsgId(_history->peer->id, topMessageId); const auto itemId = FullMsgId(channel()->id, topMessageId);
if (const auto item = owner().message(itemId)) { if (const auto item = owner().message(itemId)) {
setLastServerMessage(item); setLastServerMessage(item);
@ -428,7 +435,7 @@ void ForumTopic::applyIconId(DocumentId iconId) {
if (_iconId != iconId) { if (_iconId != iconId) {
_iconId = iconId; _iconId = iconId;
_icon = iconId _icon = iconId
? _history->owner().customEmojiManager().create( ? owner().customEmojiManager().create(
_iconId, _iconId,
[=] { updateChatListEntry(); }, [=] { updateChatListEntry(); },
Data::CustomEmojiManager::SizeTag::Normal) Data::CustomEmojiManager::SizeTag::Normal)
@ -524,7 +531,7 @@ Dialogs::UnreadState ForumTopic::unreadStateFor(
bool known) const { bool known) const {
auto result = Dialogs::UnreadState(); auto result = Dialogs::UnreadState();
const auto mark = !count && unreadMark(); const auto mark = !count && unreadMark();
const auto muted = _history->mute(); const auto muted = history()->mute();
result.messages = count; result.messages = count;
result.messagesMuted = muted ? count : 0; result.messagesMuted = muted ? count : 0;
result.chats = count ? 1 : 0; result.chats = count ? 1 : 0;

View file

@ -55,6 +55,7 @@ public:
[[nodiscard]] not_null<ChannelData*> channel() const; [[nodiscard]] not_null<ChannelData*> channel() const;
[[nodiscard]] not_null<History*> history() const; [[nodiscard]] not_null<History*> history() const;
[[nodiscard]] not_null<Forum*> forum() const; [[nodiscard]] not_null<Forum*> forum() const;
[[nodiscard]] rpl::producer<> destroyed() const;
[[nodiscard]] MsgId rootId() const; [[nodiscard]] MsgId rootId() const;
[[nodiscard]] bool isGeneral() const { [[nodiscard]] bool isGeneral() const {
return (_rootId == kGeneralId); return (_rootId == kGeneralId);
@ -131,7 +132,7 @@ private:
int count, int count,
bool known) const; bool known) const;
const not_null<History*> _history; const not_null<Data::Forum*> _forum;
const not_null<Dialogs::MainList*> _list; const not_null<Dialogs::MainList*> _list;
std::shared_ptr<RepliesList> _replies; std::shared_ptr<RepliesList> _replies;
MsgId _rootId = 0; MsgId _rootId = 0;

View file

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_forum.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_histories.h" #include "data/data_histories.h"
@ -889,6 +890,22 @@ Data::Forum *PeerData::forum() const {
return nullptr; return nullptr;
} }
Data::ForumTopic *PeerData::forumTopicFor(
not_null<const HistoryItem*> item) const {
if (const auto forum = this->forum()) {
return forum->topicFor(item);
}
return nullptr;
}
Data::ForumTopic *PeerData::forumTopicFor(MsgId rootId) const {
if (const auto forum = this->forum()) {
return forum->topicFor(rootId);
}
return nullptr;
}
bool PeerData::canWrite() const { bool PeerData::canWrite() const {
if (const auto user = asUser()) { if (const auto user = asUser()) {
return user->canWrite(); return user->canWrite();

View file

@ -33,6 +33,7 @@ class Session;
namespace Data { namespace Data {
class Forum; class Forum;
class ForumTopic;
class Session; class Session;
class GroupCall; class GroupCall;
class CloudImageView; class CloudImageView;
@ -197,6 +198,9 @@ public:
} }
[[nodiscard]] Data::Forum *forum() const; [[nodiscard]] Data::Forum *forum() const;
[[nodiscard]] Data::ForumTopic *forumTopicFor(
not_null<const HistoryItem*> item) const;
[[nodiscard]] Data::ForumTopic *forumTopicFor(MsgId rootId) const;
[[nodiscard]] std::optional<TimeId> notifyMuteUntil() const { [[nodiscard]] std::optional<TimeId> notifyMuteUntil() const {
return _notify.muteUntil(); return _notify.muteUntil();

View file

@ -328,7 +328,7 @@ Widget::Widget(
}, lifetime()); }, lifetime());
_lockUnlock->setClickedCallback([this] { _lockUnlock->setClickedCallback([this] {
_lockUnlock->setIconOverride(&st::dialogsUnlockIcon, &st::dialogsUnlockIconOver); _lockUnlock->setIconOverride(&st::dialogsUnlockIcon, &st::dialogsUnlockIconOver);
Core::App().lockByPasscode(); Core::App().maybeLockByPasscode();
_lockUnlock->setIconOverride(nullptr); _lockUnlock->setIconOverride(nullptr);
}); });

View file

@ -487,6 +487,13 @@ void RepliesWidget::subscribeToTopic() {
_cornerButtons.updateUnreadThingsVisibility(); _cornerButtons.updateUnreadThingsVisibility();
}, _topicLifetime); }, _topicLifetime);
_topic->destroyed(
) | rpl::start_with_next([=] {
controller()->showBackFromStack(Window::SectionShow(
anim::type::normal,
anim::activation::background));
}, _topicLifetime);
_cornerButtons.updateUnreadThingsVisibility(); _cornerButtons.updateUnreadThingsVisibility();
} }

View file

@ -22,7 +22,7 @@ namespace Info {
namespace CommonGroups { namespace CommonGroups {
Memento::Memento(not_null<UserData*> user) Memento::Memento(not_null<UserData*> user)
: ContentMemento(user, 0) { : ContentMemento(user, nullptr, PeerId()) {
} }
Section Memento::section() const { Section Memento::section() const {

View file

@ -337,16 +337,23 @@ Key ContentMemento::key() const {
} }
} }
ContentMemento::ContentMemento(not_null<Data::ForumTopic*> topic) ContentMemento::ContentMemento(
: _peer(topic->channel()) not_null<PeerData*> peer,
, _migratedPeerId(_peer->migrateFrom() ? _peer->migrateFrom()->id : 0) Data::ForumTopic *topic,
PeerId migratedPeerId)
: _peer(peer)
, _migratedPeerId((!topic && peer->migrateFrom())
? peer->migrateFrom()->id
: 0)
, _topic(topic) { , _topic(topic) {
_peer->owner().itemIdChanged( if (_topic) {
) | rpl::start_with_next([=](const Data::Session::IdChange &change) { _peer->owner().itemIdChanged(
if (_topic->rootId() == change.oldId) { ) | rpl::start_with_next([=](const Data::Session::IdChange &change) {
_topic = _topic->forum()->topicFor(change.newId.msg); if (_topic->rootId() == change.oldId) {
} _topic = _topic->forum()->topicFor(change.newId.msg);
}, _lifetime); }
}, _lifetime);
}
} }
ContentMemento::ContentMemento(Settings::Tag settings) ContentMemento::ContentMemento(Settings::Tag settings)

View file

@ -144,11 +144,10 @@ private:
class ContentMemento { class ContentMemento {
public: public:
ContentMemento(not_null<PeerData*> peer, PeerId migratedPeerId) ContentMemento(
: _peer(peer) not_null<PeerData*> peer,
, _migratedPeerId(migratedPeerId) { Data::ForumTopic *topic,
} PeerId migratedPeerId);
explicit ContentMemento(not_null<Data::ForumTopic*> topic);
explicit ContentMemento(Settings::Tag settings); explicit ContentMemento(Settings::Tag settings);
explicit ContentMemento(Downloads::Tag downloads); explicit ContentMemento(Downloads::Tag downloads);
ContentMemento(not_null<PollData*> poll, FullMsgId contextId) ContentMemento(not_null<PollData*> poll, FullMsgId contextId)

View file

@ -192,7 +192,10 @@ Controller::Controller(
void Controller::setupMigrationViewer() { void Controller::setupMigrationViewer() {
const auto peer = _key.peer(); const auto peer = _key.peer();
if (!peer || (!peer->isChat() && !peer->isChannel()) || _migrated) { if (_key.topic()
|| !peer
|| (!peer->isChat() && !peer->isChannel())
|| _migrated) {
return; return;
} }
peer->session().changes().peerFlagsValue( peer->session().changes().peerFlagsValue(
@ -335,6 +338,7 @@ auto Controller::produceSearchQuery(
auto result = SearchQuery(); auto result = SearchQuery();
result.type = _section.mediaType(); result.type = _section.mediaType();
result.peerId = _key.peer()->id; result.peerId = _key.peer()->id;
result.topicRootId = _key.topic() ? _key.topic()->rootId() : 0;
result.query = query; result.query = query;
result.migratedPeerId = _migrated ? _migrated->id : PeerId(0); result.migratedPeerId = _migrated ? _migrated->id : PeerId(0);
return result; return result;

View file

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peer_list_box.h" #include "boxes/peer_list_box.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_chat.h" #include "data/data_chat.h"
#include "data/data_forum_topic.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "main/main_session.h" #include "main/main_session.h"
@ -51,6 +52,27 @@ Memento::Memento(not_null<PollData*> poll, FullMsgId contextId)
Memento::Memento(std::vector<std::shared_ptr<ContentMemento>> stack) Memento::Memento(std::vector<std::shared_ptr<ContentMemento>> stack)
: _stack(std::move(stack)) { : _stack(std::move(stack)) {
auto topics = base::flat_set<not_null<Data::ForumTopic*>>();
for (auto &entry : _stack) {
if (const auto topic = entry->topic()) {
topics.emplace(topic);
}
}
for (const auto &topic : topics) {
topic->destroyed(
) | rpl::start_with_next([=] {
for (auto i = begin(_stack); i != end(_stack);) {
if (i->get()->topic() == topic) {
i = _stack.erase(i);
} else {
++i;
}
}
if (_stack.empty()) {
_removeRequests.fire({});
}
}, _lifetime);
}
} }
std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack( std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack(

View file

@ -58,6 +58,10 @@ public:
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
const QRect &geometry) override; const QRect &geometry) override;
rpl::producer<> removeRequests() const override {
return _removeRequests.events();
}
int stackSize() const { int stackSize() const {
return int(_stack.size()); return int(_stack.size());
} }
@ -96,6 +100,8 @@ private:
Section section); Section section);
std::vector<std::shared_ptr<ContentMemento>> _stack; std::vector<std::shared_ptr<ContentMemento>> _stack;
rpl::event_stream<> _removeRequests;
rpl::lifetime _lifetime;
}; };

View file

@ -124,6 +124,10 @@ object_ptr<Ui::LayerWidget> SectionWidget::moveContentToLayer(
bodyGeometry); bodyGeometry);
} }
rpl::producer<> SectionWidget::removeRequests() const {
return _content->removeRequests();
}
bool SectionWidget::floatPlayerHandleWheelEvent(QEvent *e) { bool SectionWidget::floatPlayerHandleWheelEvent(QEvent *e) {
return _content->floatPlayerHandleWheelEvent(e); return _content->floatPlayerHandleWheelEvent(e);
} }

View file

@ -53,6 +53,8 @@ public:
object_ptr<Ui::LayerWidget> moveContentToLayer( object_ptr<Ui::LayerWidget> moveContentToLayer(
QRect bodyGeometry) override; QRect bodyGeometry) override;
rpl::producer<> removeRequests() const override;
// Float player interface. // Float player interface.
bool floatPlayerHandleWheelEvent(QEvent *e) override; bool floatPlayerHandleWheelEvent(QEvent *e) override;
QRect floatPlayerAvailableRect() override; QRect floatPlayerAvailableRect() override;

View file

@ -40,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_forum_topic.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "styles/style_chat.h" // popupMenuExpandedSeparator #include "styles/style_chat.h" // popupMenuExpandedSeparator
@ -104,6 +105,22 @@ WrapWidget::WrapWidget(
}); });
}, lifetime()); }, lifetime());
restoreHistoryStack(memento->takeStack()); restoreHistoryStack(memento->takeStack());
if (const auto topic = _controller->topic()) {
topic->destroyed(
) | rpl::start_with_next([=] {
if (_wrap.current() == Wrap::Layer) {
_controller->parentController()->hideSpecialLayer();
} else if (_wrap.current() == Wrap::Narrow) {
_controller->parentController()->showBackFromStack(
Window::SectionShow(
anim::type::normal,
anim::activation::background));
} else {
_removeRequests.fire({});
}
}, lifetime());
}
} }
void WrapWidget::setupShortcuts() { void WrapWidget::setupShortcuts() {
@ -233,129 +250,16 @@ Dialogs::RowDescriptor WrapWidget::activeChat() const {
Unexpected("Owner in WrapWidget::activeChat()."); Unexpected("Owner in WrapWidget::activeChat().");
} }
// This was done for tabs support.
//
//void WrapWidget::createTabs() {
// _topTabs.create(this, st::infoTabs);
// auto sections = QStringList();
// sections.push_back(tr::lng_profile_info_section(tr::now).toUpper());
// sections.push_back(tr::lng_info_tab_media(tr::now).toUpper());
// _topTabs->setSections(sections);
// _topTabs->setActiveSection(static_cast<int>(_tab));
// _topTabs->finishAnimating();
//
// _topTabs->sectionActivated(
// ) | rpl::map([](int index) {
// return static_cast<Tab>(index);
// }) | rpl::start_with_next(
// [this](Tab tab) { showTab(tab); },
// lifetime());
//
// _topTabs->move(0, 0);
// _topTabs->resizeToWidth(width());
// _topTabs->show();
//
// _topTabsBackground.create(this, st::profileBg);
// _topTabsBackground->setAttribute(Qt::WA_OpaquePaintEvent);
//
// _topTabsBackground->move(0, 0);
// _topTabsBackground->resize(
// width(),
// _topTabs->height() - st::lineWidth);
// _topTabsBackground->show();
//}
void WrapWidget::forceContentRepaint() { void WrapWidget::forceContentRepaint() {
// WA_OpaquePaintEvent on TopBar creates render glitches when // WA_OpaquePaintEvent on TopBar creates render glitches when
// animating the LayerWidget's height :( Fixing by repainting. // animating the LayerWidget's height :( Fixing by repainting.
// This was done for tabs support.
//
//if (_topTabs) {
// _topTabsBackground->update();
//}
if (_topBar) { if (_topBar) {
_topBar->update(); _topBar->update();
} }
_content->update(); _content->update();
} }
// This was done for tabs support.
//
//void WrapWidget::showTab(Tab tab) {
// if (_tab == tab) {
// return;
// }
// Expects(_content != nullptr);
// auto direction = (tab > _tab)
// ? SlideDirection::FromRight
// : SlideDirection::FromLeft;
// auto newAnotherMemento = _content->createMemento();
// if (!_anotherTabMemento) {
// _anotherTabMemento = createTabMemento(tab);
// }
// auto newController = createController(
// _controller->parentController(),
// _anotherTabMemento.get());
// auto newContent = createContent(
// _anotherTabMemento.get(),
// newController.get());
// auto animationParams = SectionSlideParams();
//// animationParams.withFade = (wrap() == Wrap::Layer);
// animationParams.withTabs = true;
// animationParams.withTopBarShadow = hasTopBarShadow()
// && newContent->hasTopBarShadow();
// animationParams.oldContentCache = grabForShowAnimation(
// animationParams);
//
// _controller = std::move(newController);
// showContent(std::move(newContent));
//
// showAnimated(direction, animationParams);
//
// _anotherTabMemento = std::move(newAnotherMemento);
// _tab = tab;
//}
//
//void WrapWidget::setupTabbedTop() {
// auto section = _controller->section();
// switch (section.type()) {
// case Section::Type::Profile:
// setupTabs(Tab::Profile);
// break;
// case Section::Type::Media:
// switch (section.mediaType()) {
// case Section::MediaType::Photo:
// case Section::MediaType::Video:
// case Section::MediaType::File:
// setupTabs(Tab::Media);
// break;
// default:
// setupTabs(Tab::None);
// break;
// }
// break;
// case Section::Type::CommonGroups:
// case Section::Type::Members:
// setupTabs(Tab::None);
// break;
// }
//}
void WrapWidget::setupTop() { void WrapWidget::setupTop() {
// This was done for tabs support.
//
//if (wrap() == Wrap::Side && !hasStackHistory()) {
// setupTabbedTop();
//} else {
// setupTabs(Tab::None);
//}
//if (_topTabs) {
// _topBar.destroy();
//} else {
// createTopBar();
//}
if (HasCustomTopBar(_controller.get())) { if (HasCustomTopBar(_controller.get())) {
_topBar.destroy(); _topBar.destroy();
return; return;
@ -602,11 +506,6 @@ bool WrapWidget::requireTopBarSearch() const {
} else if (hasStackHistory()) { } else if (hasStackHistory()) {
return true; return true;
} }
// This was for top-level tabs support.
//
//auto section = _controller->section();
//return (section.type() != Section::Type::Media)
// || !Media::TypeToTabIndex(section.mediaType()).has_value();
return false; return false;
} }
@ -618,7 +517,6 @@ bool WrapWidget::showBackFromStackInternal(
showNewContent( showNewContent(
last.section.get(), last.section.get(),
params.withWay(Window::SectionShow::Way::Backward)); params.withWay(Window::SectionShow::Way::Backward));
//_anotherTabMemento = std::move(last.anotherTab);
return true; return true;
} }
return (wrap() == Wrap::Layer); return (wrap() == Wrap::Layer);
@ -645,11 +543,6 @@ void WrapWidget::removeFromStack(const std::vector<Section> &sections) {
} }
not_null<Ui::RpWidget*> WrapWidget::topWidget() const { not_null<Ui::RpWidget*> WrapWidget::topWidget() const {
// This was done for tabs support.
//
//if (_topTabs) {
// return _topTabsBackground;
//}
return _topBar; return _topBar;
} }
@ -670,7 +563,6 @@ void WrapWidget::showContent(object_ptr<ContentWidget> content) {
} }
_additionalScroll = 0; _additionalScroll = 0;
_content->show(); _content->show();
//_anotherTabMemento = nullptr;
finishShowContent(); finishShowContent();
} }
@ -696,23 +588,9 @@ void WrapWidget::finishShowContent() {
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
updateContentGeometry(); updateContentGeometry();
}, _content->lifetime()); }, _content->lifetime());
// This was done for tabs support.
//
//if (_topTabs) {
// _topTabs->raise();
//}
} }
rpl::producer<bool> WrapWidget::topShadowToggledValue() const { rpl::producer<bool> WrapWidget::topShadowToggledValue() const {
// Allows always showing shadow for specific wrap value.
// Was done for top level tabs support.
//
//using namespace rpl::mappers;
//return rpl::combine(
// _controller->wrapValue(),
// _desiredShadowVisibilities.events() | rpl::flatten_latest(),
// (_1 == Wrap::Side) || _2);
return _desiredShadowVisibilities.events() return _desiredShadowVisibilities.events()
| rpl::flatten_latest( | rpl::flatten_latest(
) | rpl::map([=](bool v) { return v && (_topBar != nullptr); }); ) | rpl::map([=](bool v) { return v && (_topBar != nullptr); });
@ -730,22 +608,6 @@ rpl::producer<SelectedItems> WrapWidget::selectedListValue() const {
return _selectedLists.events() | rpl::flatten_latest(); return _selectedLists.events() | rpl::flatten_latest();
} }
// Was done for top level tabs support.
//
//std::shared_ptr<ContentMemento> WrapWidget::createTabMemento(
// Tab tab) {
// switch (tab) {
// case Tab::Profile: return std::make_shared<Profile::Memento>(
// _controller->peerId(),
// _controller->migratedPeerId());
// case Tab::Media: return std::make_shared<Media::Memento>(
// _controller->peerId(),
// _controller->migratedPeerId(),
// Media::Type::Photo);
// }
// Unexpected("Tab value in Info::WrapWidget::createInner()");
//}
object_ptr<ContentWidget> WrapWidget::createContent( object_ptr<ContentWidget> WrapWidget::createContent(
not_null<ContentMemento*> memento, not_null<ContentMemento*> memento,
not_null<Controller*> controller) { not_null<Controller*> controller) {
@ -755,43 +617,11 @@ object_ptr<ContentWidget> WrapWidget::createContent(
contentGeometry()); contentGeometry());
} }
// Was done for top level tabs support.
//
//void WrapWidget::convertProfileFromStackToTab() {
// if (!hasStackHistory()) {
// return;
// }
// auto &entry = _historyStack[0];
// if (entry.section->section().type() != Section::Type::Profile) {
// return;
// }
// auto convertInsideStack = (_historyStack.size() > 1);
// auto checkSection = convertInsideStack
// ? _historyStack[1].section->section()
// : _controller->section();
// auto &anotherMemento = convertInsideStack
// ? _historyStack[1].anotherTab
// : _anotherTabMemento;
// if (checkSection.type() != Section::Type::Media) {
// return;
// }
// if (!Info::Media::TypeToTabIndex(checkSection.mediaType())) {
// return;
// }
// anotherMemento = std::move(entry.section);
// _historyStack.erase(_historyStack.begin());
//}
rpl::producer<Wrap> WrapWidget::wrapValue() const { rpl::producer<Wrap> WrapWidget::wrapValue() const {
return _wrap.value(); return _wrap.value();
} }
void WrapWidget::setWrap(Wrap wrap) { void WrapWidget::setWrap(Wrap wrap) {
// Was done for top level tabs support.
//
//if (_wrap.current() != Wrap::Side && wrap == Wrap::Side) {
// convertProfileFromStackToTab();
//}
_wrap = wrap; _wrap = wrap;
} }
@ -810,9 +640,6 @@ QPixmap WrapWidget::grabForShowAnimation(
} else { } else {
_topShadow->setVisible(_topShadow->toggled()); _topShadow->setVisible(_topShadow->toggled());
} }
//if (params.withTabs && _topTabs) {
// _topTabs->hide();
//}
const auto expanding = _expanding; const auto expanding = _expanding;
if (expanding) { if (expanding) {
_grabbingForExpanding = true; _grabbingForExpanding = true;
@ -824,18 +651,11 @@ QPixmap WrapWidget::grabForShowAnimation(
if (params.withTopBarShadow) { if (params.withTopBarShadow) {
_topShadow->setVisible(true); _topShadow->setVisible(true);
} }
//if (params.withTabs && _topTabs) {
// _topTabs->show();
//}
return result; return result;
} }
void WrapWidget::showAnimatedHook( void WrapWidget::showAnimatedHook(
const Window::SectionSlideParams &params) { const Window::SectionSlideParams &params) {
//if (params.withTabs && _topTabs) {
// _topTabs->show();
// _topTabsBackground->show();
//}
if (params.withTopBarShadow) { if (params.withTopBarShadow) {
_topShadow->setVisible(true); _topShadow->setVisible(true);
} }
@ -870,25 +690,6 @@ bool WrapWidget::showInternal(
if (!skipInternal && _content->showInternal(content)) { if (!skipInternal && _content->showInternal(content)) {
highlightTopBar(); highlightTopBar();
return true; return true;
// This was done for tabs support.
//
//} else if (_topTabs) {
// // If we open the profile being in the media tab.
// // Just switch back to the profile tab.
// auto type = content->section().type();
// if (type == Section::Type::Profile
// && _tab != Tab::Profile) {
// _anotherTabMemento = std::move(infoMemento->takeStack().back());
// _topTabs->setActiveSection(static_cast<int>(Tab::Profile));
// return true;
// } else if (type == Section::Type::Media
// && _tab != Tab::Media
// && Media::TypeToTabIndex(content->section().mediaType()).has_value()) {
// _anotherTabMemento = std::move(infoMemento->takeStack().back());
// _topTabs->setActiveSection(static_cast<int>(Tab::Media));
// return true;
// }
} }
} }
@ -899,9 +700,7 @@ bool WrapWidget::showInternal(
return true; return true;
} }
showNewContent( showNewContent(content, params);
content,
params);
return true; return true;
} }
return false; return false;
@ -997,9 +796,6 @@ void WrapWidget::showNewContent(
if (saveToStack) { if (saveToStack) {
auto item = StackItem(); auto item = StackItem();
item.section = _content->createMemento(); item.section = _content->createMemento();
//if (_anotherTabMemento) {
// item.anotherTab = std::move(_anotherTabMemento);
//}
_historyStack.push_back(std::move(item)); _historyStack.push_back(std::move(item));
} else if (params.way == Window::SectionShow::Way::ClearStack) { } else if (params.way == Window::SectionShow::Way::ClearStack) {
_historyStack.clear(); _historyStack.clear();
@ -1041,29 +837,7 @@ void WrapWidget::showNewContent(not_null<ContentMemento*> memento) {
showContent(createContent(memento, _controller.get())); showContent(createContent(memento, _controller.get()));
} }
// This was done for tabs support.
//
//void WrapWidget::setupTabs(Tab tab) {
// _tab = tab;
// if (_tab == Tab::None) {
// _topTabs.destroy();
// _topTabsBackground.destroy();
// } else if (!_topTabs) {
// createTabs();
// } else {
// _topTabs->setActiveSection(static_cast<int>(tab));
// }
//}
void WrapWidget::resizeEvent(QResizeEvent *e) { void WrapWidget::resizeEvent(QResizeEvent *e) {
// This was done for tabs support.
//
//if (_topTabs) {
// _topTabs->resizeToWidth(width());
// _topTabsBackground->resize(
// width(),
// _topTabs->height() - st::lineWidth);
//}
if (_topBar) { if (_topBar) {
_topBar->resizeToWidth(width()); _topBar->resizeToWidth(width());
} }

View file

@ -132,6 +132,10 @@ public:
[[nodiscard]] rpl::producer<bool> grabbingForExpanding() const; [[nodiscard]] rpl::producer<bool> grabbingForExpanding() const;
[[nodiscard]] const Ui::RoundRect *bottomSkipRounding() const; [[nodiscard]] const Ui::RoundRect *bottomSkipRounding() const;
[[nodiscard]] rpl::producer<> removeRequests() const {
return _removeRequests.events();
}
~WrapWidget(); ~WrapWidget();
protected: protected:
@ -147,11 +151,6 @@ protected:
private: private:
using SlideDirection = Window::SlideDirection; using SlideDirection = Window::SlideDirection;
using SectionSlideParams = Window::SectionSlideParams; using SectionSlideParams = Window::SectionSlideParams;
//enum class Tab {
// Profile,
// Media,
// None,
//};
struct StackItem; struct StackItem;
void startInjectingActivePeerProfiles(); void startInjectingActivePeerProfiles();
@ -173,9 +172,6 @@ private:
not_null<ContentMemento*> memento, not_null<ContentMemento*> memento,
const Window::SectionShow &params); const Window::SectionShow &params);
void setupTop(); void setupTop();
//void setupTabbedTop();
//void setupTabs(Tab tab);
//void createTabs();
void createTopBar(); void createTopBar();
void highlightTopBar(); void highlightTopBar();
void setupShortcuts(); void setupShortcuts();
@ -190,16 +186,13 @@ private:
rpl::producer<bool> topShadowToggledValue() const; rpl::producer<bool> topShadowToggledValue() const;
void updateContentGeometry(); void updateContentGeometry();
//void showTab(Tab tab);
void showContent(object_ptr<ContentWidget> content); void showContent(object_ptr<ContentWidget> content);
//std::shared_ptr<ContentMemento> createTabMemento(Tab tab);
object_ptr<ContentWidget> createContent( object_ptr<ContentWidget> createContent(
not_null<ContentMemento*> memento, not_null<ContentMemento*> memento,
not_null<Controller*> controller); not_null<Controller*> controller);
std::unique_ptr<Controller> createController( std::unique_ptr<Controller> createController(
not_null<Window::SessionController*> window, not_null<Window::SessionController*> window,
not_null<ContentMemento*> memento); not_null<ContentMemento*> memento);
//void convertProfileFromStackToTab();
rpl::producer<SelectedItems> selectedListValue() const; rpl::producer<SelectedItems> selectedListValue() const;
bool requireTopBarSearch() const; bool requireTopBarSearch() const;
@ -215,8 +208,6 @@ private:
int _additionalScroll = 0; int _additionalScroll = 0;
bool _expanding = false; bool _expanding = false;
rpl::variable<bool> _grabbingForExpanding = false; rpl::variable<bool> _grabbingForExpanding = false;
//object_ptr<Ui::PlainShadow> _topTabsBackground = { nullptr };
//object_ptr<Ui::SettingsSlider> _topTabs = { nullptr };
object_ptr<TopBar> _topBar = { nullptr }; object_ptr<TopBar> _topBar = { nullptr };
object_ptr<Ui::RpWidget> _topBarSurrogate = { nullptr }; object_ptr<Ui::RpWidget> _topBarSurrogate = { nullptr };
Ui::Animations::Simple _topBarOverrideAnimation; Ui::Animations::Simple _topBarOverrideAnimation;
@ -227,9 +218,8 @@ private:
base::unique_qptr<Ui::IconButton> _topBarMenuToggle; base::unique_qptr<Ui::IconButton> _topBarMenuToggle;
base::unique_qptr<Ui::PopupMenu> _topBarMenu; base::unique_qptr<Ui::PopupMenu> _topBarMenu;
// Tab _tab = Tab::Profile;
// std::shared_ptr<ContentMemento> _anotherTabMemento;
std::vector<StackItem> _historyStack; std::vector<StackItem> _historyStack;
rpl::event_stream<> _removeRequests;
rpl::event_stream<rpl::producer<int>> _desiredHeights; rpl::event_stream<rpl::producer<int>> _desiredHeights;
rpl::event_stream<rpl::producer<bool>> _desiredShadowVisibilities; rpl::event_stream<rpl::producer<bool>> _desiredShadowVisibilities;

View file

@ -93,8 +93,15 @@ inline auto AddButton(
MediaText(type), MediaText(type),
tracker)->entity(); tracker)->entity();
result->addClickHandler([=] { result->addClickHandler([=] {
navigation->showSection( const auto topic = topicRootId
std::make_shared<Info::Memento>(peer, Section(type))); ? peer->forumTopicFor(topicRootId)
: nullptr;
if (topicRootId && !topic) {
return;
}
navigation->showSection(topicRootId
? std::make_shared<Info::Memento>(topic, Section(type))
: std::make_shared<Info::Memento>(peer, Section(type)));
}); });
return result; return result;
}; };

View file

@ -41,8 +41,7 @@ InnerWidget::InnerWidget(
} }
// Allows showing additional shared media links and tabs. // Allows showing additional shared media links and tabs.
// Was done for top level tabs support. // Used for shared media in Saved Messages.
// Now used for shared media in Saved Messages.
void InnerWidget::setupOtherTypes() { void InnerWidget::setupOtherTypes() {
if (_controller->key().peer()->isSelf() && _isStackBottom) { if (_controller->key().peer()->isSelf() && _isStackBottom) {
createOtherTypes(); createOtherTypes();
@ -50,26 +49,14 @@ void InnerWidget::setupOtherTypes() {
_otherTypes.destroy(); _otherTypes.destroy();
refreshHeight(); refreshHeight();
} }
//rpl::combine(
// _controller->wrapValue(),
// _controller->searchEnabledByContent()
//) | rpl::start_with_next([this](Wrap wrap, bool enabled) {
// _searchEnabled = enabled;
// refreshSearchField();
//}, lifetime());
} }
void InnerWidget::createOtherTypes() { void InnerWidget::createOtherTypes() {
//_otherTabsShadow.create(this);
//_otherTabsShadow->show();
//_otherTabs = nullptr;
_otherTypes.create(this); _otherTypes.create(this);
_otherTypes->show(); _otherTypes->show();
createTypeButtons(); createTypeButtons();
_otherTypes->add(object_ptr<Ui::BoxContentDivider>(_otherTypes)); _otherTypes->add(object_ptr<Ui::BoxContentDivider>(_otherTypes));
//createTabs();
_otherTypes->resizeToWidth(width()); _otherTypes->resizeToWidth(width());
_otherTypes->heightValue( _otherTypes->heightValue(
@ -111,19 +98,6 @@ void InnerWidget::createTypeButtons() {
icon, icon,
st::infoSharedMediaButtonIconPosition)->show(); st::infoSharedMediaButtonIconPosition)->show();
}; };
//auto addCommonGroupsButton = [&](
// not_null<UserData*> user,
// const style::icon &icon) {
// auto result = AddCommonGroupsButton(
// content,
// _controller,
// user,
// tracker);
// object_ptr<Profile::FloatingIcon>(
// result,
// icon,
// st::infoSharedMediaButtonIconPosition)->show();
//};
addMediaButton(Type::Photo, st::infoIconMediaPhoto); addMediaButton(Type::Photo, st::infoIconMediaPhoto);
addMediaButton(Type::Video, st::infoIconMediaVideo); addMediaButton(Type::Video, st::infoIconMediaVideo);
@ -132,9 +106,6 @@ void InnerWidget::createTypeButtons() {
addMediaButton(Type::Link, st::infoIconMediaLink); addMediaButton(Type::Link, st::infoIconMediaLink);
addMediaButton(Type::RoundVoiceFile, st::infoIconMediaVoice); addMediaButton(Type::RoundVoiceFile, st::infoIconMediaVoice);
addMediaButton(Type::GIF, st::infoIconMediaGif); addMediaButton(Type::GIF, st::infoIconMediaGif);
// if (auto user = _controller->key().peer()->asUser()) {
// addCommonGroupsButton(user, st::infoIconMediaGroup);
// }
content->add(object_ptr<Ui::FixedHeightWidget>( content->add(object_ptr<Ui::FixedHeightWidget>(
content, content,
@ -143,33 +114,6 @@ void InnerWidget::createTypeButtons() {
wrap->finishAnimating(); wrap->finishAnimating();
} }
//void InnerWidget::createTabs() {
// _otherTabs = _otherTypes->add(object_ptr<Ui::SettingsSlider>(
// this,
// st::infoTabs));
// auto sections = QStringList();
// sections.push_back(tr::lng_media_type_photos(tr::now).toUpper());
// sections.push_back(tr::lng_media_type_videos(tr::now).toUpper());
// sections.push_back(tr::lng_media_type_files(tr::now).toUpper());
// _otherTabs->setSections(sections);
// _otherTabs->setActiveSection(*TypeToTabIndex(type()));
// _otherTabs->finishAnimating();
//
// _otherTabs->sectionActivated(
// ) | rpl::map([](int index) {
// return TabIndexToType(index);
// }) | rpl::start_with_next(
// [this](Type newType) {
// if (type() != newType) {
// switchToTab(Memento(
// _controller->peerId(),
// _controller->migratedPeerId(),
// newType));
// }
// },
// _otherTabs->lifetime());
//}
Type InnerWidget::type() const { Type InnerWidget::type() const {
return _controller->section().mediaType(); return _controller->section().mediaType();
} }
@ -188,63 +132,10 @@ bool InnerWidget::showInternal(not_null<Memento*> memento) {
if (mementoType == type()) { if (mementoType == type()) {
restoreState(memento); restoreState(memento);
return true; return true;
// Allows showing additional shared media links and tabs.
// Was done for top level tabs support.
//
//} else if (_otherTypes) {
// if (TypeToTabIndex(mementoType)) {
// switchToTab(std::move(*memento));
// return true;
// }
} }
return false; return false;
} }
// Allows showing additional shared media links and tabs.
// Was done for top level tabs support.
//
//void InnerWidget::switchToTab(Memento &&memento) {
// // Save state of the tab before setSection() call.
// _controller->setSection(&memento);
// _list = setupList();
// restoreState(&memento);
// _list->show();
// _list->resizeToWidth(width());
// refreshHeight();
// if (_otherTypes) {
// _otherTabsShadow->raise();
// _otherTypes->raise();
// _otherTabs->setActiveSection(*TypeToTabIndex(type()));
// }
//}
//
//void InnerWidget::refreshSearchField() {
// auto search = _controller->searchFieldController();
// if (search && _otherTabs && _searchEnabled) {
// _searchField = search->createRowView(
// this,
// st::infoMediaSearch);
// _searchField->resizeToWidth(width());
// _searchField->show();
// search->queryChanges(
// ) | rpl::start_with_next([this] {
// scrollToSearchField();
// }, _searchField->lifetime());
// } else {
// _searchField = nullptr;
// }
//}
//
//void InnerWidget::scrollToSearchField() {
// Expects(_searchField != nullptr);
//
// auto top = _searchField->y();
// auto bottom = top + _searchField->height();
// _scrollToRequests.fire({ top, bottom });
//}
object_ptr<ListWidget> InnerWidget::setupList() { object_ptr<ListWidget> InnerWidget::setupList() {
auto result = object_ptr<ListWidget>( auto result = object_ptr<ListWidget>(
this, this,
@ -299,11 +190,7 @@ int InnerWidget::resizeGetHeight(int newWidth) {
if (_otherTypes) { if (_otherTypes) {
_otherTypes->resizeToWidth(newWidth); _otherTypes->resizeToWidth(newWidth);
//_otherTabsShadow->resizeToWidth(newWidth);
} }
//if (_searchField) {
// _searchField->resizeToWidth(newWidth);
//}
_list->resizeToWidth(newWidth); _list->resizeToWidth(newWidth);
_empty->resizeToWidth(newWidth); _empty->resizeToWidth(newWidth);
return recountHeight(); return recountHeight();
@ -321,12 +208,7 @@ int InnerWidget::recountHeight() {
if (_otherTypes) { if (_otherTypes) {
_otherTypes->moveToLeft(0, top); _otherTypes->moveToLeft(0, top);
top += _otherTypes->heightNoMargins() - st::lineWidth; top += _otherTypes->heightNoMargins() - st::lineWidth;
// _otherTabsShadow->moveToLeft(0, top);
} }
//if (_searchField) {
// _searchField->moveToLeft(0, top);
// top += _searchField->heightNoMargins() - st::lineWidth;
//}
auto listHeight = 0; auto listHeight = 0;
if (_list) { if (_list) {
_list->moveToLeft(0, top); _list->moveToLeft(0, top);

View file

@ -62,18 +62,10 @@ private:
int recountHeight(); int recountHeight();
void refreshHeight(); void refreshHeight();
// Allows showing additional shared media links and tabs. // Allows showing additional shared media links and tabs.
// Was done for top level tabs support. // Used for shared media in Saved Messages.
// Now used for shared media in Saved Messages.
void setupOtherTypes(); void setupOtherTypes();
void createOtherTypes(); void createOtherTypes();
void createTypeButtons(); void createTypeButtons();
// Allows showing additional shared media links and tabs.
// Was done for top level tabs support.
//
//void createTabs();
//void switchToTab(Memento &&memento);
//void refreshSearchField();
//void scrollToSearchField();
Type type() const; Type type() const;
@ -81,13 +73,9 @@ private:
const not_null<Controller*> _controller; const not_null<Controller*> _controller;
//Ui::SettingsSlider *_otherTabs = nullptr;
object_ptr<Ui::VerticalLayout> _otherTypes = { nullptr }; object_ptr<Ui::VerticalLayout> _otherTypes = { nullptr };
//object_ptr<Ui::PlainShadow> _otherTabsShadow = { nullptr };
//base::unique_qptr<Ui::RpWidget> _searchField = nullptr;
object_ptr<ListWidget> _list = { nullptr }; object_ptr<ListWidget> _list = { nullptr };
object_ptr<EmptyWidget> _empty; object_ptr<EmptyWidget> _empty;
//bool _searchEnabled = false;
bool _inResize = false; bool _inResize = false;
bool _isStackBottom = false; bool _isStackBottom = false;

View file

@ -15,6 +15,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "data/data_peer.h" #include "data/data_peer.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_channel.h"
#include "data/data_forum_topic.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "styles/style_info.h" #include "styles/style_info.h"
@ -43,6 +45,7 @@ Memento::Memento(not_null<Controller*> controller)
(controller->peer() (controller->peer()
? controller->peer() ? controller->peer()
: controller->parentController()->session().user()), : controller->parentController()->session().user()),
controller->topic(),
controller->migratedPeerId(), controller->migratedPeerId(),
(controller->section().type() == Section::Type::Downloads (controller->section().type() == Section::Type::Downloads
? Type::File ? Type::File
@ -50,23 +53,25 @@ Memento::Memento(not_null<Controller*> controller)
} }
Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId, Type type) Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId, Type type)
: ContentMemento(peer, migratedPeerId) : Memento(peer, nullptr, migratedPeerId, type) {
, _type(type) {
_searchState.query.type = type;
_searchState.query.peerId = peer->id;
_searchState.query.migratedPeerId = migratedPeerId;
if (migratedPeerId) {
_searchState.migratedList = Storage::SparseIdsList();
}
} }
Memento::Memento(not_null<Data::ForumTopic*> topic, Type type) Memento::Memento(not_null<Data::ForumTopic*> topic, Type type)
: ContentMemento(topic) : Memento(topic->channel(), topic, PeerId(), type) {
}
Memento::Memento(
not_null<PeerData*> peer,
Data::ForumTopic *topic,
PeerId migratedPeerId,
Type type)
: ContentMemento(peer, topic, migratedPeerId)
, _type(type) { , _type(type) {
_searchState.query.type = type; // #TODO forum search _searchState.query.type = type;
_searchState.query.peerId = peer()->id; _searchState.query.peerId = peer->id;
_searchState.query.migratedPeerId = migratedPeerId(); _searchState.query.topicRootId = topic ? topic->rootId() : 0;
if (migratedPeerId()) { _searchState.query.migratedPeerId = migratedPeerId;
if (migratedPeerId) {
_searchState.migratedList = Storage::SparseIdsList(); _searchState.migratedList = Storage::SparseIdsList();
} }
} }

View file

@ -83,6 +83,12 @@ public:
} }
private: private:
Memento(
not_null<PeerData*> peer,
Data::ForumTopic *topic,
PeerId migratedPeerId,
Type type);
Type _type = Type::Photo; Type _type = Type::Photo;
FullMsgId _aroundId; FullMsgId _aroundId;
int _idsLimit = 0; int _idsLimit = 0;

View file

@ -26,7 +26,7 @@ Memento::Memento(not_null<Controller*> controller)
} }
Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId) Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId)
: ContentMemento(peer, migratedPeerId) { : ContentMemento(peer, nullptr, migratedPeerId) {
} }
Section Memento::section() const { Section Memento::section() const {

View file

@ -73,8 +73,9 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
_topic ? TitleValue(_topic) : NameValue(_peer))); _topic ? TitleValue(_topic) : NameValue(_peer)));
_cover->showSection( _cover->showSection(
) | rpl::start_with_next([=](Section section) { ) | rpl::start_with_next([=](Section section) {
_controller->showSection( _controller->showSection(_topic
std::make_shared<Info::Memento>(_peer, section)); ? std::make_shared<Info::Memento>(_topic, section)
: std::make_shared<Info::Memento>(_peer, section));
}, _cover->lifetime()); }, _cover->lifetime());
_cover->setOnlineCount(rpl::single(0)); _cover->setOnlineCount(rpl::single(0));
if (_topic) { if (_topic) {
@ -166,34 +167,6 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
object_ptr<Ui::VerticalLayout>(parent) object_ptr<Ui::VerticalLayout>(parent)
); );
// Allows removing shared media links in third column.
// Was done for tabs support.
//
//using ToggledData = std::tuple<bool, Wrap, bool>;
//rpl::combine(
// tracker.atLeastOneShownValue(),
// _controller->wrapValue(),
// _isStackBottom.value()
//) | rpl::combine_previous(
// ToggledData()
//) | rpl::start_with_next([wrap = result.data()](
// const ToggledData &was,
// const ToggledData &now) {
// bool wasOneShown, wasStackBottom, nowOneShown, nowStackBottom;
// Wrap wasWrap, nowWrap;
// std::tie(wasOneShown, wasWrap, wasStackBottom) = was;
// std::tie(nowOneShown, nowWrap, nowStackBottom) = now;
// // MSVC Internal Compiler Error
// //auto [wasOneShown, wasWrap, wasStackBottom] = was;
// //auto [nowOneShown, nowWrap, nowStackBottom] = now;
// wrap->toggle(
// nowOneShown && (nowWrap != Wrap::Side || !nowStackBottom),
// (wasStackBottom == nowStackBottom && wasWrap == nowWrap)
// ? anim::type::normal
// : anim::type::instant);
//}, result->lifetime());
//
// Using that instead
result->setDuration( result->setDuration(
st::infoSlideDuration st::infoSlideDuration
)->toggleOn( )->toggleOn(

View file

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "data/data_peer.h" #include "data/data_peer.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_forum_topic.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "info/info_controller.h" #include "info/info_controller.h"
@ -22,15 +23,23 @@ namespace Info::Profile {
Memento::Memento(not_null<Controller*> controller) Memento::Memento(not_null<Controller*> controller)
: Memento( : Memento(
controller->peer(), controller->peer(),
controller->topic(),
controller->migratedPeerId()) { controller->migratedPeerId()) {
} }
Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId) Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId)
: ContentMemento(peer, migratedPeerId) { : Memento(peer, nullptr, migratedPeerId) {
}
Memento::Memento(
not_null<PeerData*> peer,
Data::ForumTopic *topic,
PeerId migratedPeerId)
: ContentMemento(peer, topic, migratedPeerId) {
} }
Memento::Memento(not_null<Data::ForumTopic*> topic) Memento::Memento(not_null<Data::ForumTopic*> topic)
: ContentMemento(topic) { : ContentMemento(topic->channel(), topic, 0) {
} }
Section Memento::section() const { Section Memento::section() const {

View file

@ -37,6 +37,11 @@ public:
~Memento(); ~Memento();
private: private:
Memento(
not_null<PeerData*> peer,
Data::ForumTopic *topic,
PeerId migratedPeerId);
std::unique_ptr<MembersState> _membersState; std::unique_ptr<MembersState> _membersState;
}; };

View file

@ -123,27 +123,33 @@ enum StackItemType {
class StackItem { class StackItem {
public: public:
StackItem(PeerData *peer) : _peer(peer) { explicit StackItem(PeerData *peer) : _peer(peer) {
} }
PeerData *peer() const { [[nodiscard]] PeerData *peer() const {
return _peer; return _peer;
} }
void setThirdSectionMemento( void setThirdSectionMemento(
std::shared_ptr<Window::SectionMemento> memento); std::shared_ptr<Window::SectionMemento> memento);
std::shared_ptr<Window::SectionMemento> takeThirdSectionMemento() { [[nodiscard]] auto takeThirdSectionMemento()
-> std::shared_ptr<Window::SectionMemento> {
return std::move(_thirdSectionMemento); return std::move(_thirdSectionMemento);
} }
void setThirdSectionWeak(QPointer<Window::SectionWidget> section) { void setThirdSectionWeak(QPointer<Window::SectionWidget> section) {
_thirdSectionWeak = section; _thirdSectionWeak = section;
} }
QPointer<Window::SectionWidget> thirdSectionWeak() const { [[nodiscard]] QPointer<Window::SectionWidget> thirdSectionWeak() const {
return _thirdSectionWeak; return _thirdSectionWeak;
} }
virtual StackItemType type() const = 0; [[nodiscard]] rpl::lifetime &lifetime() {
return _lifetime;
}
[[nodiscard]] virtual StackItemType type() const = 0;
[[nodiscard]] virtual rpl::producer<> removeRequests() const = 0;
virtual ~StackItem() = default; virtual ~StackItem() = default;
private: private:
@ -151,9 +157,11 @@ private:
QPointer<Window::SectionWidget> _thirdSectionWeak; QPointer<Window::SectionWidget> _thirdSectionWeak;
std::shared_ptr<Window::SectionMemento> _thirdSectionMemento; std::shared_ptr<Window::SectionMemento> _thirdSectionMemento;
rpl::lifetime _lifetime;
}; };
class StackItemHistory : public StackItem { class StackItemHistory final : public StackItem {
public: public:
StackItemHistory( StackItemHistory(
not_null<History*> history, not_null<History*> history,
@ -168,6 +176,9 @@ public:
StackItemType type() const override { StackItemType type() const override {
return HistoryStackItem; return HistoryStackItem;
} }
rpl::producer<> removeRequests() const override {
return rpl::never<>();
}
not_null<History*> history; not_null<History*> history;
MsgId msgId; MsgId msgId;
@ -183,6 +194,9 @@ public:
StackItemType type() const override { StackItemType type() const override {
return SectionStackItem; return SectionStackItem;
} }
rpl::producer<> removeRequests() const override {
return _memento->removeRequests();
}
std::shared_ptr<Window::SectionMemento> takeMemento() { std::shared_ptr<Window::SectionMemento> takeMemento() {
return std::move(_memento); return std::move(_memento);
} }
@ -1499,15 +1513,28 @@ void MainWidget::saveSectionInStack() {
if (auto memento = _mainSection->createMemento()) { if (auto memento = _mainSection->createMemento()) {
_stack.push_back(std::make_unique<StackItemSection>( _stack.push_back(std::make_unique<StackItemSection>(
std::move(memento))); std::move(memento)));
_stack.back()->setThirdSectionWeak(_thirdSection.data()); } else {
return;
} }
} else if (const auto history = _history->history()) { } else if (const auto history = _history->history()) {
_stack.push_back(std::make_unique<StackItemHistory>( _stack.push_back(std::make_unique<StackItemHistory>(
history, history,
_history->msgId(), _history->msgId(),
_history->replyReturns())); _history->replyReturns()));
_stack.back()->setThirdSectionWeak(_thirdSection.data()); } else {
return;
} }
const auto raw = _stack.back().get();
raw->setThirdSectionWeak(_thirdSection.data());
raw->removeRequests(
) | rpl::start_with_next([=] {
for (auto i = begin(_stack); i != end(_stack); ++i) {
if (i->get() == raw) {
_stack.erase(i);
return;
}
}
}, raw->lifetime());
} }
void MainWidget::showSection( void MainWidget::showSection(
@ -1715,6 +1742,12 @@ void MainWidget::showNewSection(
: _mainSection; : _mainSection;
if (newThirdSection) { if (newThirdSection) {
_thirdSection = std::move(newThirdSection); _thirdSection = std::move(newThirdSection);
_thirdSection->removeRequests(
) | rpl::start_with_next([=] {
_thirdSection.destroy();
_thirdShadow.destroy();
updateControlsGeometry();
}, _thirdSection->lifetime());
if (!_thirdShadow) { if (!_thirdShadow) {
_thirdShadow.create(this); _thirdShadow.create(this);
_thirdShadow->show(); _thirdShadow->show();
@ -1821,9 +1854,9 @@ bool MainWidget::preventsCloseSection(Fn<void()> callback) const {
bool MainWidget::preventsCloseSection( bool MainWidget::preventsCloseSection(
Fn<void()> callback, Fn<void()> callback,
const SectionShow &params) const { const SectionShow &params) const {
return params.thirdColumn return !params.thirdColumn
? false && (params.activation != anim::activation::background)
: preventsCloseSection(std::move(callback)); && preventsCloseSection(std::move(callback));
} }
void MainWidget::showBackFromStack( void MainWidget::showBackFromStack(

View file

@ -1902,9 +1902,19 @@ void OverlayWidget::showMediaOverview() {
close(); close();
if (SharedMediaOverviewType(*overviewType)) { if (SharedMediaOverviewType(*overviewType)) {
if (const auto window = findWindow()) { if (const auto window = findWindow()) {
window->showSection(std::make_shared<Info::Memento>( const auto topic = _topicRootId
_history->peer, ? _history->peer->forumTopicFor(_topicRootId)
Info::Section(*overviewType))); : nullptr;
if (_topicRootId && !topic) {
return;
}
window->showSection(_topicRootId
? std::make_shared<Info::Memento>(
topic,
Info::Section(*overviewType))
: std::make_shared<Info::Memento>(
_history->peer,
Info::Section(*overviewType)));
} }
} }
} }

View file

@ -1225,11 +1225,11 @@ reactionPremiumLocked: icon{
{ "chat/reactions_premium_star", historyPeerUserpicFg }, { "chat/reactions_premium_star", historyPeerUserpicFg },
}; };
reactionExpandPanel: icon{ reactionExpandPanel: icon{
{ "chat/reactions_round_big", windowSubTextFg }, { "chat/reactions_round_big", windowBgRipple },
{ "chat/reactions_expand_panel", windowBg }, { "chat/reactions_expand_panel", windowBg },
}; };
reactionsExpandDropdown: icon{ reactionsExpandDropdown: icon{
{ "chat/reactions_round_small", windowSubTextFg }, { "chat/reactions_round_small", windowBgRipple },
{ "chat/reactions_expand_panel", windowBg }, { "chat/reactions_expand_panel", windowBg },
}; };

View file

@ -19,21 +19,25 @@ enum class Column;
class SectionMemento { class SectionMemento {
public: public:
virtual object_ptr<SectionWidget> createWidget( [[nodiscard]] virtual object_ptr<SectionWidget> createWidget(
QWidget *parent, QWidget *parent,
not_null<SessionController*> controller, not_null<SessionController*> controller,
Column column, Column column,
const QRect &geometry) = 0; const QRect &geometry) = 0;
virtual object_ptr<Ui::LayerWidget> createLayer( [[nodiscard]] virtual object_ptr<Ui::LayerWidget> createLayer(
not_null<SessionController*> controller, not_null<SessionController*> controller,
const QRect &geometry) { const QRect &geometry) {
return nullptr; return nullptr;
} }
virtual bool instant() const { [[nodiscard]] virtual bool instant() const {
return false; return false;
} }
[[nodiscard]] virtual rpl::producer<> removeRequests() const {
return rpl::never<>();
}
virtual ~SectionMemento() = default; virtual ~SectionMemento() = default;
}; };

View file

@ -139,7 +139,8 @@ public:
return false; return false;
} }
virtual bool preventsClose(Fn<void()> &&continueCallback) const { [[nodiscard]] virtual bool preventsClose(
Fn<void()> &&continueCallback) const {
return false; return false;
} }
@ -157,10 +158,13 @@ public:
doSetInnerFocus(); doSetInnerFocus();
} }
virtual rpl::producer<int> desiredHeight() const; [[nodiscard]] virtual rpl::producer<int> desiredHeight() const;
[[nodiscard]] virtual rpl::producer<> removeRequests() const {
return rpl::never<>();
}
// Some sections convert to layers on some geometry sizes. // Some sections convert to layers on some geometry sizes.
virtual object_ptr<Ui::LayerWidget> moveContentToLayer( [[nodiscard]] virtual object_ptr<Ui::LayerWidget> moveContentToLayer(
QRect bodyGeometry) { QRect bodyGeometry) {
return nullptr; return nullptr;
} }

View file

@ -893,12 +893,8 @@ void SessionController::openForum(
closeFolder(); closeFolder();
_openedForum = forum.get(); _openedForum = forum.get();
if (_openedForum.current() == forum) { if (_openedForum.current() == forum) {
forum->flagsValue( forum->forum()->destroyed(
) | rpl::filter([=](const ChannelData::Flags::Change &update) { ) | rpl::start_with_next([=] {
using Flag = ChannelData::Flag;
return (update.diff & Flag::Forum)
&& !(update.value & Flag::Forum);
}) | rpl::start_with_next([=] {
closeForum(); closeForum();
showPeerHistory( showPeerHistory(
forum, forum,