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

View file

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

View file

@ -67,6 +67,18 @@ not_null<Dialogs::MainList*> Forum::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() {
if (_allLoaded || _requestId) {
return;

View file

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

View file

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

View file

@ -55,6 +55,7 @@ public:
[[nodiscard]] not_null<ChannelData*> channel() const;
[[nodiscard]] not_null<History*> history() const;
[[nodiscard]] not_null<Forum*> forum() const;
[[nodiscard]] rpl::producer<> destroyed() const;
[[nodiscard]] MsgId rootId() const;
[[nodiscard]] bool isGeneral() const {
return (_rootId == kGeneralId);
@ -131,7 +132,7 @@ private:
int count,
bool known) const;
const not_null<History*> _history;
const not_null<Data::Forum*> _forum;
const not_null<Dialogs::MainList*> _list;
std::shared_ptr<RepliesList> _replies;
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_photo.h"
#include "data/data_folder.h"
#include "data/data_forum.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_histories.h"
@ -889,6 +890,22 @@ Data::Forum *PeerData::forum() const {
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 {
if (const auto user = asUser()) {
return user->canWrite();

View file

@ -33,6 +33,7 @@ class Session;
namespace Data {
class Forum;
class ForumTopic;
class Session;
class GroupCall;
class CloudImageView;
@ -197,6 +198,9 @@ public:
}
[[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 {
return _notify.muteUntil();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peer_list_box.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_forum_topic.h"
#include "data/data_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)
: _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(

View file

@ -58,6 +58,10 @@ public:
not_null<Window::SessionController*> controller,
const QRect &geometry) override;
rpl::producer<> removeRequests() const override {
return _removeRequests.events();
}
int stackSize() const {
return int(_stack.size());
}
@ -96,6 +100,8 @@ private:
Section section);
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);
}
rpl::producer<> SectionWidget::removeRequests() const {
return _content->removeRequests();
}
bool SectionWidget::floatPlayerHandleWheelEvent(QEvent *e) {
return _content->floatPlayerHandleWheelEvent(e);
}

View file

@ -53,6 +53,8 @@ public:
object_ptr<Ui::LayerWidget> moveContentToLayer(
QRect bodyGeometry) override;
rpl::producer<> removeRequests() const override;
// Float player interface.
bool floatPlayerHandleWheelEvent(QEvent *e) 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_changes.h"
#include "data/data_user.h"
#include "data/data_forum_topic.h"
#include "mainwidget.h"
#include "lang/lang_keys.h"
#include "styles/style_chat.h" // popupMenuExpandedSeparator
@ -104,6 +105,22 @@ WrapWidget::WrapWidget(
});
}, lifetime());
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() {
@ -233,129 +250,16 @@ Dialogs::RowDescriptor WrapWidget::activeChat() const {
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() {
// WA_OpaquePaintEvent on TopBar creates render glitches when
// animating the LayerWidget's height :( Fixing by repainting.
// This was done for tabs support.
//
//if (_topTabs) {
// _topTabsBackground->update();
//}
if (_topBar) {
_topBar->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() {
// 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())) {
_topBar.destroy();
return;
@ -602,11 +506,6 @@ bool WrapWidget::requireTopBarSearch() const {
} else if (hasStackHistory()) {
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;
}
@ -618,7 +517,6 @@ bool WrapWidget::showBackFromStackInternal(
showNewContent(
last.section.get(),
params.withWay(Window::SectionShow::Way::Backward));
//_anotherTabMemento = std::move(last.anotherTab);
return true;
}
return (wrap() == Wrap::Layer);
@ -645,11 +543,6 @@ void WrapWidget::removeFromStack(const std::vector<Section> &sections) {
}
not_null<Ui::RpWidget*> WrapWidget::topWidget() const {
// This was done for tabs support.
//
//if (_topTabs) {
// return _topTabsBackground;
//}
return _topBar;
}
@ -670,7 +563,6 @@ void WrapWidget::showContent(object_ptr<ContentWidget> content) {
}
_additionalScroll = 0;
_content->show();
//_anotherTabMemento = nullptr;
finishShowContent();
}
@ -696,23 +588,9 @@ void WrapWidget::finishShowContent() {
) | rpl::start_with_next([=] {
updateContentGeometry();
}, _content->lifetime());
// This was done for tabs support.
//
//if (_topTabs) {
// _topTabs->raise();
//}
}
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()
| rpl::flatten_latest(
) | rpl::map([=](bool v) { return v && (_topBar != nullptr); });
@ -730,22 +608,6 @@ rpl::producer<SelectedItems> WrapWidget::selectedListValue() const {
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(
not_null<ContentMemento*> memento,
not_null<Controller*> controller) {
@ -755,43 +617,11 @@ object_ptr<ContentWidget> WrapWidget::createContent(
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 {
return _wrap.value();
}
void WrapWidget::setWrap(Wrap wrap) {
// Was done for top level tabs support.
//
//if (_wrap.current() != Wrap::Side && wrap == Wrap::Side) {
// convertProfileFromStackToTab();
//}
_wrap = wrap;
}
@ -810,9 +640,6 @@ QPixmap WrapWidget::grabForShowAnimation(
} else {
_topShadow->setVisible(_topShadow->toggled());
}
//if (params.withTabs && _topTabs) {
// _topTabs->hide();
//}
const auto expanding = _expanding;
if (expanding) {
_grabbingForExpanding = true;
@ -824,18 +651,11 @@ QPixmap WrapWidget::grabForShowAnimation(
if (params.withTopBarShadow) {
_topShadow->setVisible(true);
}
//if (params.withTabs && _topTabs) {
// _topTabs->show();
//}
return result;
}
void WrapWidget::showAnimatedHook(
const Window::SectionSlideParams &params) {
//if (params.withTabs && _topTabs) {
// _topTabs->show();
// _topTabsBackground->show();
//}
if (params.withTopBarShadow) {
_topShadow->setVisible(true);
}
@ -870,25 +690,6 @@ bool WrapWidget::showInternal(
if (!skipInternal && _content->showInternal(content)) {
highlightTopBar();
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;
}
showNewContent(
content,
params);
showNewContent(content, params);
return true;
}
return false;
@ -997,9 +796,6 @@ void WrapWidget::showNewContent(
if (saveToStack) {
auto item = StackItem();
item.section = _content->createMemento();
//if (_anotherTabMemento) {
// item.anotherTab = std::move(_anotherTabMemento);
//}
_historyStack.push_back(std::move(item));
} else if (params.way == Window::SectionShow::Way::ClearStack) {
_historyStack.clear();
@ -1041,29 +837,7 @@ void WrapWidget::showNewContent(not_null<ContentMemento*> memento) {
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) {
// This was done for tabs support.
//
//if (_topTabs) {
// _topTabs->resizeToWidth(width());
// _topTabsBackground->resize(
// width(),
// _topTabs->height() - st::lineWidth);
//}
if (_topBar) {
_topBar->resizeToWidth(width());
}

View file

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

View file

@ -93,8 +93,15 @@ inline auto AddButton(
MediaText(type),
tracker)->entity();
result->addClickHandler([=] {
navigation->showSection(
std::make_shared<Info::Memento>(peer, Section(type)));
const auto topic = topicRootId
? 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;
};

View file

@ -41,8 +41,7 @@ InnerWidget::InnerWidget(
}
// Allows showing additional shared media links and tabs.
// Was done for top level tabs support.
// Now used for shared media in Saved Messages.
// Used for shared media in Saved Messages.
void InnerWidget::setupOtherTypes() {
if (_controller->key().peer()->isSelf() && _isStackBottom) {
createOtherTypes();
@ -50,26 +49,14 @@ void InnerWidget::setupOtherTypes() {
_otherTypes.destroy();
refreshHeight();
}
//rpl::combine(
// _controller->wrapValue(),
// _controller->searchEnabledByContent()
//) | rpl::start_with_next([this](Wrap wrap, bool enabled) {
// _searchEnabled = enabled;
// refreshSearchField();
//}, lifetime());
}
void InnerWidget::createOtherTypes() {
//_otherTabsShadow.create(this);
//_otherTabsShadow->show();
//_otherTabs = nullptr;
_otherTypes.create(this);
_otherTypes->show();
createTypeButtons();
_otherTypes->add(object_ptr<Ui::BoxContentDivider>(_otherTypes));
//createTabs();
_otherTypes->resizeToWidth(width());
_otherTypes->heightValue(
@ -111,19 +98,6 @@ void InnerWidget::createTypeButtons() {
icon,
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::Video, st::infoIconMediaVideo);
@ -132,9 +106,6 @@ void InnerWidget::createTypeButtons() {
addMediaButton(Type::Link, st::infoIconMediaLink);
addMediaButton(Type::RoundVoiceFile, st::infoIconMediaVoice);
addMediaButton(Type::GIF, st::infoIconMediaGif);
// if (auto user = _controller->key().peer()->asUser()) {
// addCommonGroupsButton(user, st::infoIconMediaGroup);
// }
content->add(object_ptr<Ui::FixedHeightWidget>(
content,
@ -143,33 +114,6 @@ void InnerWidget::createTypeButtons() {
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 {
return _controller->section().mediaType();
}
@ -188,63 +132,10 @@ bool InnerWidget::showInternal(not_null<Memento*> memento) {
if (mementoType == type()) {
restoreState(memento);
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;
}
// 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() {
auto result = object_ptr<ListWidget>(
this,
@ -299,11 +190,7 @@ int InnerWidget::resizeGetHeight(int newWidth) {
if (_otherTypes) {
_otherTypes->resizeToWidth(newWidth);
//_otherTabsShadow->resizeToWidth(newWidth);
}
//if (_searchField) {
// _searchField->resizeToWidth(newWidth);
//}
_list->resizeToWidth(newWidth);
_empty->resizeToWidth(newWidth);
return recountHeight();
@ -321,12 +208,7 @@ int InnerWidget::recountHeight() {
if (_otherTypes) {
_otherTypes->moveToLeft(0, top);
top += _otherTypes->heightNoMargins() - st::lineWidth;
// _otherTabsShadow->moveToLeft(0, top);
}
//if (_searchField) {
// _searchField->moveToLeft(0, top);
// top += _searchField->heightNoMargins() - st::lineWidth;
//}
auto listHeight = 0;
if (_list) {
_list->moveToLeft(0, top);

View file

@ -62,18 +62,10 @@ private:
int recountHeight();
void refreshHeight();
// Allows showing additional shared media links and tabs.
// Was done for top level tabs support.
// Now used for shared media in Saved Messages.
// Used for shared media in Saved Messages.
void setupOtherTypes();
void createOtherTypes();
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;
@ -81,13 +73,9 @@ private:
const not_null<Controller*> _controller;
//Ui::SettingsSlider *_otherTabs = 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<EmptyWidget> _empty;
//bool _searchEnabled = false;
bool _inResize = false;
bool _isStackBottom = false;

View file

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

View file

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

View file

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

View file

@ -73,8 +73,9 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
_topic ? TitleValue(_topic) : NameValue(_peer)));
_cover->showSection(
) | rpl::start_with_next([=](Section section) {
_controller->showSection(
std::make_shared<Info::Memento>(_peer, section));
_controller->showSection(_topic
? std::make_shared<Info::Memento>(_topic, section)
: std::make_shared<Info::Memento>(_peer, section));
}, _cover->lifetime());
_cover->setOnlineCount(rpl::single(0));
if (_topic) {
@ -166,34 +167,6 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
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(
st::infoSlideDuration
)->toggleOn(

View file

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

View file

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

View file

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

View file

@ -1902,9 +1902,19 @@ void OverlayWidget::showMediaOverview() {
close();
if (SharedMediaOverviewType(*overviewType)) {
if (const auto window = findWindow()) {
window->showSection(std::make_shared<Info::Memento>(
_history->peer,
Info::Section(*overviewType)));
const auto topic = _topicRootId
? _history->peer->forumTopicFor(_topicRootId)
: 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 },
};
reactionExpandPanel: icon{
{ "chat/reactions_round_big", windowSubTextFg },
{ "chat/reactions_round_big", windowBgRipple },
{ "chat/reactions_expand_panel", windowBg },
};
reactionsExpandDropdown: icon{
{ "chat/reactions_round_small", windowSubTextFg },
{ "chat/reactions_round_small", windowBgRipple },
{ "chat/reactions_expand_panel", windowBg },
};

View file

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

View file

@ -139,7 +139,8 @@ public:
return false;
}
virtual bool preventsClose(Fn<void()> &&continueCallback) const {
[[nodiscard]] virtual bool preventsClose(
Fn<void()> &&continueCallback) const {
return false;
}
@ -157,10 +158,13 @@ public:
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.
virtual object_ptr<Ui::LayerWidget> moveContentToLayer(
[[nodiscard]] virtual object_ptr<Ui::LayerWidget> moveContentToLayer(
QRect bodyGeometry) {
return nullptr;
}

View file

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