Allow editing topic title and icon.

This commit is contained in:
John Preston 2022-09-27 16:05:47 +04:00
parent c90f879c96
commit 3b3792ef75
42 changed files with 603 additions and 190 deletions

View File

@ -178,6 +178,8 @@ PRIVATE
boxes/peers/add_participants_box.h
boxes/peers/edit_contact_box.cpp
boxes/peers/edit_contact_box.h
boxes/peers/edit_forum_topic_box.cpp
boxes/peers/edit_forum_topic_box.h
boxes/peers/edit_linked_chat_box.cpp
boxes/peers/edit_linked_chat_box.h
boxes/peers/edit_participant_box.cpp

View File

@ -0,0 +1,223 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/peers/edit_forum_topic_box.h"
#include "ui/widgets/input_fields.h"
#include "ui/abstract_button.h"
#include "data/data_channel.h"
#include "data/data_forum.h"
#include "data/data_forum_topic.h"
#include "data/data_session.h"
#include "data/stickers/data_custom_emoji.h"
#include "main/main_session.h"
#include "history/history.h"
#include "lang/lang_keys.h"
#include "info/profile/info_profile_emoji_status_panel.h"
#include "window/window_session_controller.h"
#include "settings/settings_common.h"
#include "apiwrap.h"
namespace {
[[nodiscard]] int EditIconSize() {
const auto tag = Data::CustomEmojiManager::SizeTag::Large;
return Data::FrameSizeFromTag(tag) / style::DevicePixelRatio();
}
[[nodiscard]] rpl::producer<DocumentId> EditIconButton(
not_null<Window::SessionController*> controller,
not_null<QWidget*> parent,
DocumentId id) {
using namespace Info::Profile;
struct State {
rpl::variable<DocumentId> id;
EmojiStatusPanel panel;
std::unique_ptr<Ui::Text::CustomEmoji> chosen;
};
const auto tag = Data::CustomEmojiManager::SizeTag::Large;
const auto size = EditIconSize();
const auto result = Ui::CreateChild<Ui::AbstractButton>(parent.get());
const auto state = result->lifetime().make_state<State>();
state->id.value(
) | rpl::start_with_next([=](DocumentId id) {
const auto owner = &controller->session().data();
state->chosen = id
? owner->customEmojiManager().create(
id,
[=] { result->update(); },
tag)
: nullptr;
result->update();
}, result->lifetime());
state->id = id;
state->panel.setChooseFilter([=](DocumentId) {
return true;
});
state->panel.setChooseCallback([=](DocumentId id) {
state->id = id;
});
result->resize(size, size);
result->paintRequest(
) | rpl::filter([=] {
return !state->panel.paintBadgeFrame(result);
}) | rpl::start_with_next([=](QRect clip) {
auto args = Ui::Text::CustomEmoji::Context{
.preview = st::windowBgOver->c,
.now = crl::now(),
.paused = controller->isGifPausedAtLeastFor(
Window::GifPauseReason::Layer),
};
auto p = QPainter(result);
if (state->chosen) {
state->chosen->paint(p, args);
} else {
p.fillRect(clip, Qt::red);
}
}, result->lifetime());
result->setClickedCallback([=] {
state->panel.show(controller, result, tag);
});
return state->id.value();
}
} // namespace
void NewForumTopicBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
not_null<History*> forum) {
EditForumTopicBox(box, controller, forum, MsgId(0));
}
void EditForumTopicBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
not_null<History*> forum,
MsgId rootId) {
const auto creating = !rootId;
const auto topic = (!creating && forum->peer->forum())
? forum->peer->forum()->topicFor(rootId)
: nullptr;
// #TODO forum lang
box->setTitle(rpl::single(creating ? u"New topic"_q : u"Edit topic"_q));
struct State {
DocumentId iconId = 0;
mtpRequestId titleRequestId = 0;
mtpRequestId iconRequestId = 0;
};
const auto state = box->lifetime().make_state<State>();
// #TODO forum lang and design
Settings::AddSubsectionTitle(
box->verticalLayout(),
rpl::single(u"Topic Icon"_q));
const auto badgeWrap = box->addRow(
object_ptr<Ui::FixedHeightWidget>(box, EditIconSize()));
EditIconButton(
controller,
badgeWrap,
topic ? topic->iconId() : 0
) | rpl::start_with_next([=](DocumentId id) {
state->iconId = id;
}, box->lifetime());
const auto title = box->addRow(
object_ptr<Ui::InputField>(
box,
st::defaultInputField,
rpl::single(u"Topic Title"_q),
topic ? topic->title() : QString())); // #TODO forum lang
box->setFocusCallback([=] {
title->setFocusFast();
});
const auto requestId = std::make_shared<mtpRequestId>();
const auto create = [=] {
if (!forum->peer->isForum()) {
box->closeBox();
return;
} else if (title->getLastText().trimmed().isEmpty()) {
title->setFocus();
return;
}
#if 0 // #TODO forum create
const auto randomId = base::RandomValue<uint64>();
const auto api = &forum->session().api();
api->request(MTPchannels_CreateForumTopic(
MTP_flags(0),
forum->inputChannel,
MTP_string(title->getLastText().trimmed()),
MTPlong(), // icon_emoji_id
MTPInputMedia(),
MTP_string(message->getLastText().trimmed()),
MTP_long(randomId),
MTPVector<MTPMessageEntity>(),
MTPInputPeer() // send_as
)).done([=](const MTPUpdates &result) {
api->applyUpdates(result, randomId);
box->closeBox();
}).fail([=](const MTP::Error &error) {
api->sendMessageFail(error, forum, randomId);
}).send();
#endif
};
const auto save = [=] {
const auto topic = forum->peer->forum()
? forum->peer->forum()->topicFor(rootId)
: nullptr;
if (!topic) {
box->closeBox();
return;
}
const auto api = &forum->session().api();
if (state->titleRequestId <= 0) {
if (title->getLastText().trimmed().isEmpty()) {
title->setFocus();
return;
}
state->titleRequestId = api->request(MTPchannels_EditForumTitle(
topic->channel()->inputChannel,
MTP_int(rootId),
MTP_string(title->getLastText().trimmed())
)).done([=](const MTPUpdates &result) {
api->applyUpdates(result);
state->titleRequestId = 0;
if (!state->iconRequestId) {
box->closeBox();
}
}).fail([=](const MTP::Error &error) {
state->titleRequestId = -1;
}).send();
}
if (state->iconRequestId <= 0) {
state->iconRequestId = api->request(MTPchannels_EditForumIcon(
topic->channel()->inputChannel,
MTP_int(rootId),
MTP_long(state->iconId)
)).done([=](const MTPUpdates &result) {
api->applyUpdates(result);
state->iconRequestId = 0;
if (!state->titleRequestId) {
box->closeBox();
}
}).fail([=](const MTP::Error &error) {
state->iconRequestId = -1;
}).send();
}
};
if (creating) {
box->addButton(tr::lng_create_group_create(), create);
} else {
box->addButton(tr::lng_settings_save(), save);
}
box->addButton(tr::lng_cancel(), [=] {
box->closeBox();
});
}

View File

@ -0,0 +1,27 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "ui/layers/generic_box.h"
class History;
namespace Window {
class SessionController;
} // namespace Window
void NewForumTopicBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
not_null<History*> forum);
void EditForumTopicBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
not_null<History*> forum,
MsgId rootId);

View File

@ -818,7 +818,7 @@ void Controller::fillForumButton() {
AddButtonWithText(
_controls.buttonsLayout,
rpl::single(u"Forum"_q), // #TODO forum lang
rpl::single(u"Topics"_q), // #TODO forum lang
rpl::single(QString()),
[] {},
{ &st::settingsIconGroup, Settings::kIconPurple }

View File

@ -1258,9 +1258,7 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
result->menu(),
st::groupCallPopupCoverMenu,
st::groupCallMenuCover,
Info::Profile::NameValue(
participantPeer
) | rpl::map([](const auto &text) { return text.text; }),
Info::Profile::NameValue(participantPeer),
PrepareShortInfoStatus(participantPeer),
PrepareShortInfoUserpic(
participantPeer,

View File

@ -182,10 +182,10 @@ void JoinAsAction::prepare() {
rpl::combine(
tr::lng_group_call_display_as_header(),
Info::Profile::NameValue(_peer)
) | rpl::start_with_next([=](QString text, TextWithEntities name) {
) | rpl::start_with_next([=](QString text, QString name) {
const auto &padding = st::groupCallJoinAsPadding;
_text.setMarkedText(_st.itemStyle, { text }, MenuTextOptions);
_name.setMarkedText(_st.itemStyle, name, MenuTextOptions);
_name.setMarkedText(_st.itemStyle, { name }, MenuTextOptions);
const auto textWidth = _text.maxWidth();
const auto nameWidth = _name.maxWidth();
const auto textLeft = padding.left()

View File

@ -221,8 +221,8 @@ void Panel::migrate(not_null<ChannelData*> channel) {
void Panel::subscribeToPeerChanges() {
Info::Profile::NameValue(
_peer
) | rpl::start_with_next([=](const TextWithEntities &name) {
window()->setTitle(name.text);
) | rpl::start_with_next([=](const QString &name) {
window()->setTitle(name);
}, _peerLifetime);
}
@ -2336,10 +2336,8 @@ void Panel::refreshTitle() {
) | rpl::map([=](not_null<Data::GroupCall*> real) {
return real->titleValue();
}) | rpl::flatten_latest())
) | rpl::map([=](
const TextWithEntities &name,
const QString &title) {
return title.isEmpty() ? name.text : title;
) | rpl::map([=](const QString &name, const QString &title) {
return title.isEmpty() ? name : title;
}) | rpl::after_next([=] {
refreshTitleGeometry();
});

View File

@ -165,60 +165,4 @@ rpl::producer<> Forum::chatsListLoadedEvents() const {
return _chatsListLoadedEvents.events();
}
void ShowAddForumTopic(
not_null<Window::SessionController*> controller,
not_null<ChannelData*> forum) {
controller->show(Box([=](not_null<Ui::GenericBox*> box) {
box->setTitle(rpl::single(u"New Topic"_q));
const auto title = box->addRow(
object_ptr<Ui::InputField>(
box,
st::defaultInputField,
rpl::single(u"Topic Title"_q))); // #TODO forum lang
const auto message = box->addRow(
object_ptr<Ui::InputField>(
box,
st::newGroupDescription,
Ui::InputField::Mode::MultiLine,
rpl::single(u"Message"_q))); // #TODO forum lang
box->setFocusCallback([=] {
title->setFocusFast();
});
box->addButton(tr::lng_create_group_create(), [=] {
if (!forum->isForum()) {
box->closeBox();
return;
} else if (title->getLastText().trimmed().isEmpty()) {
title->setFocus();
return;
} else if (message->getLastText().trimmed().isEmpty()) {
message->setFocus();
return;
}
const auto randomId = base::RandomValue<uint64>();
const auto api = &forum->session().api();
api->request(MTPchannels_CreateForumTopic(
MTP_flags(0),
forum->inputChannel,
MTP_string(title->getLastText().trimmed()),
MTPlong(), // icon_emoji_id
MTPInputMedia(),
MTP_string(message->getLastText().trimmed()),
MTP_long(randomId),
MTPVector<MTPMessageEntity>(),
MTPInputPeer() // send_as
)).done([=](const MTPUpdates &result) {
api->applyUpdates(result, randomId);
box->closeBox();
}).fail([=](const MTP::Error &error) {
api->sendMessageFail(error, forum, randomId);
}).send();
});
box->addButton(tr::lng_cancel(), [=] {
box->closeBox();
});
}), Ui::LayerOption::KeepOther);
}
} // namespace Data

View File

@ -59,8 +59,4 @@ private:
};
void ShowAddForumTopic(
not_null<Window::SessionController*> controller,
not_null<ChannelData*> forum);
} // namespace Data

View File

@ -25,6 +25,10 @@ ForumTopic::ForumTopic(not_null<History*> forum, MsgId rootId)
, _rootId(rootId) {
}
not_null<ChannelData*> ForumTopic::channel() const {
return _forum->peer->asChannel();
}
not_null<History*> ForumTopic::forum() const {
return _forum;
}
@ -38,6 +42,11 @@ void ForumTopic::applyTopic(const MTPForumTopic &topic) {
const auto &data = topic.data();
applyTitle(qs(data.vtitle()));
if (const auto iconId = data.vicon_emoji_id()) {
applyIconId(iconId->v);
} else {
applyIconId(0);
}
const auto pinned = _list->pinned();
#if 0 // #TODO forum pinned
@ -242,6 +251,10 @@ bool ForumTopic::lastServerMessageKnown() const {
return _lastServerMessage.has_value();
}
QString ForumTopic::title() const {
return _title;
}
void ForumTopic::applyTitle(const QString &title) {
if (_title == title || (isGeneral() && !_title.isEmpty())) {
return;
@ -252,6 +265,15 @@ void ForumTopic::applyTitle(const QString &title) {
updateChatListEntry();
}
DocumentId ForumTopic::iconId() const {
return _iconId;
}
void ForumTopic::applyIconId(DocumentId iconId) {
_iconId = iconId;
updateChatListEntry();
}
void ForumTopic::applyItemAdded(not_null<HistoryItem*> item) {
setLastMessage(item);
}

View File

@ -33,6 +33,7 @@ public:
ForumTopic(const ForumTopic &) = delete;
ForumTopic &operator=(const ForumTopic &) = delete;
[[nodiscard]] not_null<ChannelData*> channel() const;
[[nodiscard]] not_null<History*> forum() const;
[[nodiscard]] MsgId rootId() const;
[[nodiscard]] bool isGeneral() const {
@ -62,7 +63,10 @@ public:
[[nodiscard]] bool lastMessageKnown() const;
[[nodiscard]] bool lastServerMessageKnown() const;
[[nodiscard]] QString title() const;
void applyTitle(const QString &title);
[[nodiscard]] DocumentId iconId() const;
void applyIconId(DocumentId iconId);
void applyItemAdded(not_null<HistoryItem*> item);
void applyItemRemoved(MsgId id);
@ -108,6 +112,7 @@ private:
const MsgId _rootId = 0;
QString _title;
DocumentId _iconId = 0;
base::flat_set<QString> _titleWords;
base::flat_set<QChar> _titleFirstLetters;
int _titleVersion = 0;

View File

@ -54,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/empty_userpic.h"
#include "ui/unread_badge.h"
#include "boxes/filters/edit_filter_box.h"
#include "boxes/peers/edit_forum_topic_box.h"
#include "api/api_chat_filters.h"
#include "base/qt/qt_common_adapters.h"
#include "styles/style_dialogs.h"
@ -2411,7 +2412,8 @@ void InnerWidget::refreshEmptyLabel() {
} else if (_emptyState == EmptyState::EmptyFolder) {
editOpenedFilter();
} else if (_emptyState == EmptyState::EmptyForum) {
Data::ShowAddForumTopic(_controller, _openedForum->channel());
_controller->show(
Box(NewForumTopicBox, _controller, _openedForum->history()));
}
});
_empty->setVisible(_state == WidgetState::Default);
@ -3287,9 +3289,10 @@ void InnerWidget::setupShortcuts() {
});
request->check(Command::ChatSelf) && request->handle([=] {
if (_openedForum) {
Data::ShowAddForumTopic(
_controller->show(Box(
NewForumTopicBox,
_controller,
_openedForum->channel());
_openedForum->history()));
} else {
_controller->content()->choosePeer(
session().userPeerId(),

View File

@ -55,8 +55,17 @@ ForumTopic *Key::topic() const {
return _value ? _value->asTopic() : nullptr;
}
History *Key::parentHistory() const {
if (const auto result = history()) {
return result;
} else if (const auto child = topic()) {
return child->forum();
}
return nullptr;
}
PeerData *Key::peer() const {
if (const auto history = this->history()) {
if (const auto history = parentHistory()) {
return history->peer;
}
return nullptr;

View File

@ -42,6 +42,7 @@ public:
History *history() const;
Data::Folder *folder() const;
Data::ForumTopic *topic() const;
History *parentHistory() const;
PeerData *peer() const;
inline bool operator<(const Key &other) const {

View File

@ -386,7 +386,9 @@ void Widget::chosenRow(const ChosenRow &row) {
if (const auto topic = row.key.topic()) {
controller()->showRepliesForMessage(
topic->forum(),
topic->rootId());
topic->rootId(),
ShowAtUnreadMsgId,
Window::SectionShow::Way::ClearStack);
} else if (history && history->peer->isForum()) {
controller()->openForum(history->peer->asChannel());
} else if (history) {

View File

@ -453,7 +453,9 @@ Data::ForumTopic *RepliesWidget::lookupTopic() {
).done([=](const MTPmessages_ForumTopics &result) {
if (const auto forum = _history->peer->forum()) {
forum->applyReceivedTopics(result);
_topic = forum->topicFor(_rootId);
if ((_topic = forum->topicFor(_rootId))) {
refreshTopBarActiveChat();
}
}
_resolveTopicRequestId = 0;
}).fail([=] {
@ -1310,9 +1312,10 @@ SendMenu::Type RepliesWidget::sendMenuType() const {
}
void RepliesWidget::refreshTopBarActiveChat() {
const auto state = Dialogs::EntryState{
.key = _history,
.section = Dialogs::EntryState::Section::Replies,
using namespace Dialogs;
const auto state = EntryState{
.key = (_topic ? Key{ _topic } : Key{ _history }),
.section = EntryState::Section::Replies,
.rootId = _rootId,
.currentReplyToId = _composeControls->replyingToMessage().msg,
};

View File

@ -7,8 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_top_bar_widget.h"
#include <rpl/combine.h>
#include <rpl/combine_previous.h>
#include "history/history.h"
#include "history/view/history_view_send_action.h"
#include "boxes/add_contact_box.h"
@ -48,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat.h"
#include "data/data_user.h"
#include "data/data_changes.h"
#include "data/data_forum_topic.h"
#include "data/data_send_action.h"
#include "chat_helpers/emoji_interactions.h"
#include "base/unixtime.h"
@ -474,7 +473,27 @@ void TopBarWidget::paintTopBar(Painter &p) {
const auto now = crl::now();
const auto history = _activeChat.key.history();
const auto folder = _activeChat.key.folder();
if (folder
if (const auto topic = _activeChat.key.topic()) {
p.setPen(st::dialogsNameFg);
topic->chatListNameText().drawElided(
p,
nameleft,
nametop,
availableWidth);
p.setFont(st::dialogsTextFont);
if (!paintConnectingState(p, nameleft, statustop, width())
&& !paintSendAction(
p,
nameleft,
statustop,
availableWidth,
width(),
st::historyStatusFgTyping,
now)) {
paintStatus(p, nameleft, statustop, availableWidth, width());
}
} else if (folder
|| history->peer->sharedMediaInfo()
|| (_activeChat.section == Section::Scheduled)
|| (_activeChat.section == Section::Pinned)
@ -673,6 +692,8 @@ void TopBarWidget::infoClicked() {
return;
} else if (key.folder()) {
_controller->closeFolder();
} else if (const auto topic = key.topic()) {
_controller->showSection(std::make_shared<Info::Memento>(topic));
} else if (key.peer()->isSelf()) {
_controller->showSection(std::make_shared<Info::Memento>(
key.peer(),
@ -706,6 +727,8 @@ void TopBarWidget::setActiveChat(
_activeChat = activeChat;
return;
}
const auto topicChanged = (_activeChat.key.topic()
!= activeChat.key.topic());
const auto peerChanged = (_activeChat.key.history()
!= activeChat.key.history());
@ -715,12 +738,12 @@ void TopBarWidget::setActiveChat(
_back->clearState();
update();
if (peerChanged) {
if (peerChanged || topicChanged) {
_titleBadge.unload();
_titleNameVersion = 0;
_emojiInteractionSeen = nullptr;
_activeChatLifetime.destroy();
if (const auto history = _activeChat.key.history()) {
if (const auto history = _activeChat.key.parentHistory()) {
session().changes().peerFlagsValue(
history->peer,
Data::PeerUpdate::Flag::GroupCall
@ -737,7 +760,9 @@ void TopBarWidget::setActiveChat(
updateControlsVisibility();
updateControlsGeometry();
}, _activeChatLifetime);
}
if (const auto history = _activeChat.key.history()) {
using InteractionSeen = ChatHelpers::EmojiInteractionSeen;
_controller->emojiInteractions().seen(
) | rpl::filter([=](const InteractionSeen &seen) {

View File

@ -7,9 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "info/info_content_widget.h"
#include <rpl/never.h>
#include <rpl/combine.h>
#include <rpl/range.h>
#include "window/window_session_controller.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/input_fields.h"
@ -23,7 +20,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/info_section_widget.h"
#include "info/info_controller.h"
#include "boxes/peer_list_box.h"
#include "data/data_chat.h"
#include "data/data_session.h"
#include "data/data_forum_topic.h"
#include "history/history.h"
#include "main/main_session.h"
#include "styles/style_info.h"
#include "styles/style_profile.h"
@ -323,7 +323,9 @@ rpl::producer<bool> ContentWidget::desiredBottomShadowVisibility() const {
}
Key ContentMemento::key() const {
if (const auto peer = this->peer()) {
if (const auto topic = this->topic()) {
return Key(topic);
} else if (const auto peer = this->peer()) {
return Key(peer);
} else if (const auto poll = this->poll()) {
return Key(poll, pollContextId());
@ -334,6 +336,12 @@ Key ContentMemento::key() const {
}
}
ContentMemento::ContentMemento(not_null<Data::ForumTopic*> topic)
: _peer(topic->forum()->peer)
, _migratedPeerId(_peer->migrateFrom() ? _peer->migrateFrom()->id : 0)
, _topic(topic) {
}
ContentMemento::ContentMemento(Settings::Tag settings)
: _settingsSelf(settings.self.get()) {
}

View File

@ -148,6 +148,7 @@ public:
: _peer(peer)
, _migratedPeerId(migratedPeerId) {
}
explicit ContentMemento(not_null<Data::ForumTopic*> topic);
explicit ContentMemento(Settings::Tag settings);
explicit ContentMemento(Downloads::Tag downloads);
ContentMemento(not_null<PollData*> poll, FullMsgId contextId)
@ -166,6 +167,9 @@ public:
PeerId migratedPeerId() const {
return _migratedPeerId;
}
Data::ForumTopic *topic() const {
return _topic;
}
UserData *settingsSelf() const {
return _settingsSelf;
}
@ -209,6 +213,7 @@ public:
private:
PeerData * const _peer = nullptr;
const PeerId _migratedPeerId = 0;
Data::ForumTopic * const _topic = nullptr;
UserData * const _settingsSelf = nullptr;
PollData * const _poll = nullptr;
const FullMsgId _pollContextId;

View File

@ -7,8 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "info/info_controller.h"
#include <rpl/range.h>
#include <rpl/then.h>
#include "ui/search_field_controller.h"
#include "data/data_shared_media.h"
#include "info/info_content_widget.h"
@ -19,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_peer.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_forum_topic.h"
#include "data/data_session.h"
#include "data/data_media_types.h"
#include "data/data_download_manager.h"
@ -32,6 +31,9 @@ namespace Info {
Key::Key(not_null<PeerData*> peer) : _value(peer) {
}
Key::Key(not_null<Data::ForumTopic*> topic) : _value(topic) {
}
Key::Key(Settings::Tag settings) : _value(settings) {
}
@ -45,6 +47,16 @@ Key::Key(not_null<PollData*> poll, FullMsgId contextId)
PeerData *Key::peer() const {
if (const auto peer = std::get_if<not_null<PeerData*>>(&_value)) {
return *peer;
} else if (const auto topic = this->topic()) {
return topic->forum()->peer;
}
return nullptr;
}
Data::ForumTopic *Key::topic() const {
if (const auto topic = std::get_if<not_null<Data::ForumTopic*>>(
&_value)) {
return *topic;
}
return nullptr;
}

View File

@ -7,16 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <rpl/variable.h>
#include "data/data_search_controller.h"
#include "window/window_session_controller.h"
namespace Data {
class ForumTopic;
} // namespace Data
namespace Ui {
class SearchFieldController;
} // namespace Ui
namespace Info {
namespace Settings {
namespace Info::Settings {
struct Tag {
explicit Tag(not_null<UserData*> self) : self(self) {
@ -25,23 +27,27 @@ struct Tag {
not_null<UserData*> self;
};
} // namespace Settings
} // namespace Info::Settings
namespace Downloads {
namespace Info::Downloads {
struct Tag {
};
} // namespace Downloads
} // namespace Info::Downloads
namespace Info {
class Key {
public:
Key(not_null<PeerData*> peer);
explicit Key(not_null<PeerData*> peer);
explicit Key(not_null<Data::ForumTopic*> topic);
Key(Settings::Tag settings);
Key(Downloads::Tag downloads);
Key(not_null<PollData*> poll, FullMsgId contextId);
PeerData *peer() const;
Data::ForumTopic *topic() const;
UserData *settingsSelf() const;
bool isDownloads() const;
PollData *poll() const;
@ -54,6 +60,7 @@ private:
};
std::variant<
not_null<PeerData*>,
not_null<Data::ForumTopic*>,
Settings::Tag,
Downloads::Tag,
PollKey> _value;

View File

@ -33,6 +33,14 @@ Memento::Memento(not_null<PeerData*> peer, Section section)
: Memento(DefaultStack(peer, section)) {
}
Memento::Memento(not_null<Data::ForumTopic*> topic)
: Memento(topic, Section::Type::Profile) {
}
Memento::Memento(not_null<Data::ForumTopic*> topic, Section section)
: Memento(DefaultStack(topic, section)) {
}
Memento::Memento(Settings::Tag settings, Section section)
: Memento(DefaultStack(settings, section)) {
}
@ -53,6 +61,14 @@ std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack(
return result;
}
std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack(
not_null<Data::ForumTopic*> topic,
Section section) {
auto result = std::vector<std::shared_ptr<ContentMemento>>();
result.push_back(DefaultContent(topic, section));
return result;
}
std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack(
Settings::Tag settings,
Section section) {
@ -111,6 +127,18 @@ std::shared_ptr<ContentMemento> Memento::DefaultContent(
Unexpected("Wrong section type in Info::Memento::DefaultContent()");
}
std::shared_ptr<ContentMemento> Memento::DefaultContent(
not_null<Data::ForumTopic*> topic,
Section section) {
switch (section.type()) {
case Section::Type::Profile:
return std::make_shared<Profile::Memento>(topic);
case Section::Type::Media:
return std::make_shared<Media::Memento>(topic, section.mediaType());
}
Unexpected("Wrong section type in Info::Memento::DefaultContent()");
}
object_ptr<Window::SectionWidget> Memento::createWidget(
QWidget *parent,
not_null<Window::SessionController*> controller,

View File

@ -17,6 +17,10 @@ namespace Storage {
enum class SharedMediaType : signed char;
} // namespace Storage
namespace Data {
class ForumTopic;
} // namespace Data
namespace Ui {
class ScrollArea;
struct ScrollToRequest;
@ -38,6 +42,8 @@ class Memento final : public Window::SectionMemento {
public:
explicit Memento(not_null<PeerData*> peer);
Memento(not_null<PeerData*> peer, Section section);
explicit Memento(not_null<Data::ForumTopic*> topic);
Memento(not_null<Data::ForumTopic*> topic, Section section);
Memento(Settings::Tag settings, Section section);
Memento(not_null<PollData*> poll, FullMsgId contextId);
explicit Memento(std::vector<std::shared_ptr<ContentMemento>> stack);
@ -72,6 +78,9 @@ private:
static std::vector<std::shared_ptr<ContentMemento>> DefaultStack(
not_null<PeerData*> peer,
Section section);
static std::vector<std::shared_ptr<ContentMemento>> DefaultStack(
not_null<Data::ForumTopic*> topic,
Section section);
static std::vector<std::shared_ptr<ContentMemento>> DefaultStack(
Settings::Tag settings,
Section section);
@ -82,6 +91,9 @@ private:
static std::shared_ptr<ContentMemento> DefaultContent(
not_null<PeerData*> peer,
Section section);
static std::shared_ptr<ContentMemento> DefaultContent(
not_null<Data::ForumTopic*> topic,
Section section);
std::vector<std::shared_ptr<ContentMemento>> _stack;

View File

@ -541,10 +541,13 @@ void WrapWidget::showTopBarMenu(bool check) {
[=] { deleteAllDownloads(); },
&st::menuIconDelete);
} else if (const auto peer = key().peer()) {
const auto topic = key().topic();
Window::FillDialogsEntryMenu(
_controller->parentController(),
Dialogs::EntryState{
.key = peer->owner().history(peer),
.key = (topic
? Dialogs::Key{ topic }
: Dialogs::Key{ peer->owner().history(peer) }),
.section = Dialogs::EntryState::Section::Profile,
},
addAction);

View File

@ -18,8 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "styles/style_info.h"
namespace Info {
namespace Media {
namespace Info::Media {
std::optional<int> TypeToTabIndex(Type type) {
switch (type) {
@ -61,6 +60,17 @@ Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId, Type type)
}
}
Memento::Memento(not_null<Data::ForumTopic*> topic, Type type)
: ContentMemento(topic)
, _type(type) {
_searchState.query.type = type; // #TODO forum search
_searchState.query.peerId = peer()->id;
_searchState.query.migratedPeerId = migratedPeerId();
if (migratedPeerId()) {
_searchState.migratedList = Storage::SparseIdsList();
}
}
Section Memento::section() const {
return Section(_type);
}
@ -162,5 +172,4 @@ void Widget::restoreState(not_null<Memento*> memento) {
_inner->restoreState(memento);
}
} // namespace Media
} // namespace Info
} // namespace Info::Media

View File

@ -7,13 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <rpl/producer.h>
#include "info/info_content_widget.h"
#include "storage/storage_shared_media.h"
#include "data/data_search_controller.h"
namespace Info {
namespace Media {
namespace Data {
class ForumTopic;
} // namespace Data
namespace Info::Media {
using Type = Storage::SharedMediaType;
@ -24,8 +26,9 @@ class InnerWidget;
class Memento final : public ContentMemento {
public:
Memento(not_null<Controller*> controller);
explicit Memento(not_null<Controller*> controller);
Memento(not_null<PeerData*> peer, PeerId migratedPeerId, Type type);
Memento(not_null<Data::ForumTopic*> peer, Type type);
using SearchState = Api::DelayedSearchController::SavedState;
@ -120,5 +123,4 @@ private:
};
} // namespace Media
} // namespace Info
} // namespace Info::Media

View File

@ -70,11 +70,7 @@ Cover::Cover(
QWidget *parent,
not_null<PeerData*> peer,
not_null<Window::SessionController*> controller)
: Cover(parent, peer, controller, NameValue(
peer
) | rpl::map([=](const TextWithEntities &name) {
return name.text;
})) {
: Cover(parent, peer, controller, NameValue(peer)) {
}
Cover::Cover(

View File

@ -171,6 +171,14 @@ EmojiStatusPanel::EmojiStatusPanel() = default;
EmojiStatusPanel::~EmojiStatusPanel() = default;
void EmojiStatusPanel::setChooseFilter(Fn<bool(DocumentId)> filter) {
_chooseFilter = std::move(filter);
}
void EmojiStatusPanel::setChooseCallback(Fn<void(DocumentId)> callback) {
_chooseCallback = std::move(callback);
}
void EmojiStatusPanel::show(
not_null<Window::SessionController*> controller,
not_null<QWidget*> button,
@ -278,32 +286,48 @@ void EmojiStatusPanel::create(
return Chosen{ .animation = data.messageSendingFrom };
});
const auto set = [=](Chosen chosen) {
const auto accept = [=](Chosen chosen) {
Expects(chosen.until != Selector::kPickCustomTimeId);
const auto owner = &controller->session().data();
startAnimation(owner, body, chosen.id, chosen.animation);
owner->emojiStatuses().set(chosen.id, chosen.until);
if (_chooseCallback) {
_chooseCallback(chosen.id);
} else {
owner->emojiStatuses().set(chosen.id, chosen.until);
}
};
rpl::merge(
std::move(statusChosen),
std::move(emojiChosen)
) | rpl::start_with_next([=](const Chosen chosen) {
if (chosen.id && !controller->session().premium()) {
ShowPremiumPreviewBox(controller, PremiumPreview::EmojiStatus);
} else if (chosen.until == Selector::kPickCustomTimeId) {
) | rpl::filter([=](const Chosen &chosen) {
return filter(controller, chosen.id);
}) | rpl::start_with_next([=](const Chosen &chosen) {
if (chosen.until == Selector::kPickCustomTimeId) {
_panel->hideAnimated();
controller->show(Box(PickUntilBox, [=](TimeId seconds) {
set({ chosen.id, base::unixtime::now() + seconds });
accept({ chosen.id, base::unixtime::now() + seconds });
}));
} else {
set(chosen);
accept(chosen);
_panel->hideAnimated();
}
}, _panel->lifetime());
}
bool EmojiStatusPanel::filter(
not_null<Window::SessionController*> controller,
DocumentId chosenId) const {
if (_chooseFilter) {
return _chooseFilter(chosenId);
} else if (chosenId && !controller->session().premium()) {
ShowPremiumPreviewBox(controller, PremiumPreview::EmojiStatus);
return false;
}
return true;
}
void EmojiStatusPanel::startAnimation(
not_null<Data::Session*> owner,
not_null<Ui::RpWidget*> body,

View File

@ -39,6 +39,9 @@ public:
EmojiStatusPanel();
~EmojiStatusPanel();
void setChooseFilter(Fn<bool(DocumentId)> filter);
void setChooseCallback(Fn<void(DocumentId)> callback);
void show(
not_null<Window::SessionController*> controller,
not_null<QWidget*> button,
@ -50,6 +53,9 @@ private:
class Animation;
void create(not_null<Window::SessionController*> controller);
[[nodiscard]] bool filter(
not_null<Window::SessionController*> controller,
DocumentId chosenId) const;
void startAnimation(
not_null<Data::Session*> owner,
@ -58,6 +64,8 @@ private:
Ui::MessageSendingAnimationFrom from);
base::unique_qptr<ChatHelpers::TabbedPanel> _panel;
Fn<bool(DocumentId)> _chooseFilter;
Fn<void(DocumentId)> _chooseCallback;
QPointer<QWidget> _panelButton;
std::unique_ptr<Animation> _animation;
Data::CustomEmojiSizeTag _animationSizeTag = {};

View File

@ -51,6 +51,7 @@ InnerWidget::InnerWidget(
, _controller(controller)
, _peer(_controller->key().peer())
, _migrated(_controller->migrated())
, _topic(_controller->key().topic())
, _content(setupContent(this)) {
_content->heightValue(
) | rpl::start_with_next([this](int height) {
@ -67,15 +68,21 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
_cover = result->add(object_ptr<Cover>(
result,
_peer,
_controller->parentController()));
_controller->parentController(),
_topic ? TitleValue(_topic) : NameValue(_peer)));
_cover->showSection(
) | rpl::start_with_next([=](Section section) {
_controller->showSection(
std::make_shared<Info::Memento>(_peer, section));
}, _cover->lifetime());
_cover->setOnlineCount(rpl::single(0));
auto details = SetupDetails(_controller, parent, _peer);
result->add(std::move(details));
if (_topic) {
// #TODO forum
//result->add(setupSharedMedia(result.data()));
return result;
}
result->add(SetupDetails(_controller, parent, _peer));
result->add(setupSharedMedia(result.data()));
if (auto members = SetupChannelMembers(_controller, result.data(), _peer)) {
result->add(std::move(members));

View File

@ -10,7 +10,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/rp_widget.h"
#include "base/object_ptr.h"
#include <rpl/variable.h>
namespace Data {
class ForumTopic;
} // namespace Data
namespace Window {
class SessionController;
@ -65,6 +67,7 @@ private:
const not_null<Controller*> _controller;
const not_null<PeerData*> _peer;
PeerData * const _migrated = nullptr;
Data::ForumTopic * const _topic = nullptr;
Members *_members = nullptr;
Cover *_cover = nullptr;

View File

@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "data/data_forum_topic.h"
#include "data/data_session.h"
#include "data/data_premium_limits.h"
#include "boxes/peers/edit_peer_permissions_box.h"
@ -74,13 +75,15 @@ void StripExternalLinks(TextWithEntities &text) {
} // namespace
rpl::producer<TextWithEntities> NameValue(not_null<PeerData*> peer) {
rpl::producer<QString> NameValue(not_null<PeerData*> peer) {
return peer->session().changes().peerFlagsValue(
peer,
UpdateFlag::Name
) | rpl::map([=] {
return peer->name();
}) | Ui::Text::ToWithEntities();
) | rpl::map([=] { return peer->name(); });
}
rpl::producer<QString> TitleValue(not_null<Data::ForumTopic*> topic) {
return rpl::single(topic->title()); // #TODO forum title changes
}
rpl::producer<TextWithEntities> PhoneValue(not_null<UserData*> user) {

View File

@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
struct ChannelLocation;
namespace Data {
class ForumTopic;
} // namespace Data
namespace Main {
class Session;
} // namespace Main
@ -28,8 +32,7 @@ namespace Storage {
enum class SharedMediaType : signed char;
} // namespace Storage
namespace Info {
namespace Profile {
namespace Info::Profile {
inline auto ToSingleLine() {
return rpl::map([](const QString &text) {
@ -40,8 +43,9 @@ inline auto ToSingleLine() {
rpl::producer<not_null<PeerData*>> MigratedOrMeValue(
not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<TextWithEntities> NameValue(
not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<QString> NameValue(not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<QString> TitleValue(
not_null<Data::ForumTopic*> topic);
[[nodiscard]] rpl::producer<TextWithEntities> PhoneValue(
not_null<UserData*> user);
[[nodiscard]] rpl::producer<TextWithEntities> PhoneOrHiddenValue(
@ -95,5 +99,4 @@ enum class BadgeType;
[[nodiscard]] rpl::producer<DocumentId> EmojiStatusIdValue(
not_null<PeerData*> peer);
} // namespace Profile
} // namespace Info
} // namespace Info::Profile

View File

@ -17,8 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "info/info_controller.h"
namespace Info {
namespace Profile {
namespace Info::Profile {
Memento::Memento(not_null<Controller*> controller)
: Memento(
@ -30,6 +29,10 @@ Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId)
: ContentMemento(peer, migratedPeerId) {
}
Memento::Memento(not_null<Data::ForumTopic*> topic)
: ContentMemento(topic) {
}
Section Memento::section() const {
return Section(Section::Type::Profile);
}
@ -38,9 +41,7 @@ object_ptr<ContentWidget> Memento::createWidget(
QWidget *parent,
not_null<Controller*> controller,
const QRect &geometry) {
auto result = object_ptr<Widget>(
parent,
controller);
auto result = object_ptr<Widget>(parent, controller);
result->setInternalState(geometry, this);
return result;
}
@ -55,9 +56,7 @@ std::unique_ptr<MembersState> Memento::membersState() {
Memento::~Memento() = default;
Widget::Widget(
QWidget *parent,
not_null<Controller*> controller)
Widget::Widget(QWidget *parent, not_null<Controller*> controller)
: ContentWidget(parent, controller) {
controller->setSearchEnabledByContent(false);
@ -81,6 +80,9 @@ void Widget::setInnerFocus() {
}
rpl::producer<QString> Widget::title() {
if (const auto topic = controller()->key().topic()) {
return rpl::single(u"Topic Info"_q); // #TODO forum lang
}
const auto peer = controller()->key().peer();
if (const auto user = peer->asUser()) {
return (user->isBot() && !user->isSupport())
@ -132,5 +134,4 @@ void Widget::restoreState(not_null<Memento*> memento) {
scrollTopRestore(memento->scrollTop());
}
} // namespace Profile
} // namespace Info
} // namespace Info::Profile

View File

@ -7,19 +7,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <rpl/producer.h>
#include "info/info_content_widget.h"
namespace Info {
namespace Profile {
namespace Data {
class ForumTopic;
} // namespace Data
namespace Info::Profile {
class InnerWidget;
struct MembersState;
class Memento final : public ContentMemento {
public:
Memento(not_null<Controller*> controller);
explicit Memento(not_null<Controller*> controller);
Memento(not_null<PeerData*> peer, PeerId migratedPeerId);
explicit Memento(not_null<Data::ForumTopic*> topic);
object_ptr<ContentWidget> createWidget(
QWidget *parent,
@ -40,9 +43,7 @@ private:
class Widget final : public ContentWidget {
public:
Widget(
QWidget *parent,
not_null<Controller*> controller);
Widget(QWidget *parent, not_null<Controller*> controller);
bool showInternal(
not_null<ContentMemento*> memento) override;
@ -65,5 +66,4 @@ private:
};
} // namespace Profile
} // namespace Info
} // namespace Info::Profile

View File

@ -818,11 +818,7 @@ void AttachWebView::show(
}
Payments::CheckoutProcess::Start(session, slug, reactivate);
};
auto title = Info::Profile::NameValue(
_bot
) | rpl::map([](const TextWithEntities &value) {
return value.text;
});
auto title = Info::Profile::NameValue(_bot);
ActiveWebViews().emplace(this);
using Button = Ui::BotWebView::MenuButton;

View File

@ -2409,6 +2409,8 @@ auto MainWidget::thirdSectionForCurrentMainSection(
-> std::shared_ptr<Window::SectionMemento> {
if (_thirdSectionFromStack) {
return std::move(_thirdSectionFromStack);
} else if (const auto topic = key.topic()) {
return std::make_shared<Info::Memento>(topic);
} else if (const auto peer = key.peer()) {
return std::make_shared<Info::Memento>(
peer,

View File

@ -313,7 +313,7 @@ void SetupPhoto(
) | rpl::start_with_next([=](
int max,
int photoWidth,
const TextWithEntities&,
const QString&,
int statusWidth) {
photo->moveToLeft(
(max - photoWidth) / 2,
@ -398,7 +398,7 @@ void SetupRows(
AddRow(
container,
tr::lng_settings_name_label(),
Info::Profile::NameValue(self),
Info::Profile::NameValue(self) | Ui::Text::ToWithEntities(),
tr::lng_profile_copy_fullname(tr::now),
[=] { controller->show(Box<EditNameBox>(self)); },
{ &st::settingsIconUser, kIconLightBlue });

View File

@ -176,8 +176,8 @@ void Cover::setupChildGeometry() {
void Cover::initViewers() {
Info::Profile::NameValue(
_user
) | rpl::start_with_next([=](const TextWithEntities &value) {
_name->setText(value.text);
) | rpl::start_with_next([=](const QString &name) {
_name->setText(name);
refreshNameGeometry(width());
}, lifetime());

View File

@ -671,7 +671,7 @@ TopBarUser::TopBarUser(
Info::Profile::NameValue(peer)
) | rpl::start_with_next([=](
DocumentData *document,
TextWithEntities name) {
const QString &name) {
if (document) {
_emojiStatus = std::make_unique<EmojiStatusTopBar>(
document,
@ -713,7 +713,7 @@ TopBarUser::TopBarUser(
_emojiStatus = nullptr;
}
updateTitle(document, name, controller);
updateTitle(document, { name }, controller);
updateAbout(document);
auto event = QResizeEvent(size(), size());

View File

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/report_messages_box.h"
#include "boxes/peers/add_bot_to_chat_box.h"
#include "boxes/peers/add_participants_box.h"
#include "boxes/peers/edit_forum_topic_box.h"
#include "boxes/peers/edit_contact_box.h"
#include "ui/boxes/report_box.h"
#include "ui/toast/toast.h"
@ -63,6 +64,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_drafts.h"
#include "data/data_forum_topic.h"
#include "data/data_user.h"
#include "data/data_scheduled_messages.h"
#include "data/data_histories.h"
@ -188,6 +190,7 @@ private:
void addClearHistory();
void addDeleteChat();
void addLeaveChat();
void addManageTopic();
void addManageChat();
void addCreatePoll();
void addThemeEdit();
@ -207,6 +210,7 @@ private:
not_null<SessionController*> _controller;
Dialogs::EntryState _request;
PeerData *_peer = nullptr;
Data::ForumTopic *_topic = nullptr;
Data::Folder *_folder = nullptr;
const PeerMenuCallback &_addAction;
@ -326,12 +330,13 @@ Filler::Filler(
: _controller(controller)
, _request(request)
, _peer(request.key.peer())
, _topic(request.key.topic())
, _folder(request.key.folder())
, _addAction(addAction) {
}
void Filler::addHidePromotion() {
const auto history = _peer->owner().historyLoaded(_peer);
const auto history = _request.key.history();
if (!history
|| !history->useTopPromotion()
|| history->topPromotionType().isEmpty()) {
@ -346,6 +351,10 @@ void Filler::addHidePromotion() {
}
void Filler::addTogglePin() {
if (!_peer) {
// #TODO forum pin
return;
}
const auto controller = _controller;
const auto filterId = _request.filterId;
const auto peer = _peer;
@ -400,11 +409,12 @@ void Filler::addSupportInfo() {
}
void Filler::addInfo() {
if (_peer->isSelf() || _peer->isRepliesChat()) {
if (_peer && (_peer->isSelf() || _peer->isRepliesChat())) {
return;
} else if (_controller->adaptive().isThreeColumn()) {
const auto history = _controller->activeChatCurrent().history();
if (history && history->peer == _peer) {
const auto peer = _controller->activeChatCurrent().peer();
const auto topic = _controller->activeChatCurrent().topic();
if ((peer && peer == _peer) || (topic && topic == _topic)) {
if (Core::App().settings().thirdSectionInfoEnabled()
|| Core::App().settings().tabbedReplacedWithInfo()) {
return;
@ -412,6 +422,7 @@ void Filler::addInfo() {
}
}
const auto controller = _controller;
const auto id = _topic ? _topic->rootId() : 0;
const auto peer = _peer;
const auto text = (peer->isChat() || peer->isMegagroup())
? tr::lng_context_view_group(tr::now)
@ -468,6 +479,9 @@ void Filler::addToggleUnreadMark() {
}
void Filler::addToggleArchive() {
if (!_peer) {
return;
}
const auto peer = _peer;
const auto history = peer->owner().historyLoaded(peer);
if (history && history->useTopPromotion()) {
@ -533,7 +547,7 @@ void Filler::addDeleteChat() {
void Filler::addLeaveChat() {
const auto channel = _peer->asChannel();
if (!channel || !channel->amIn()) {
if (_topic || !channel || !channel->amIn()) {
return;
}
_addAction({
@ -618,7 +632,7 @@ void Filler::addViewDiscussion() {
}
void Filler::addExportChat() {
if (!_peer->canExportChatHistory()) {
if (_topic || !_peer->canExportChatHistory()) {
return;
}
const auto peer = _peer;
@ -733,6 +747,19 @@ void Filler::addDeleteContact() {
});
}
void Filler::addManageTopic() {
if (!_topic) {
return;
}
// #TODO forum lang
const auto history = _topic->forum();
const auto rootId = _topic->rootId();
const auto navigation = _controller;
_addAction(u"Edit topic"_q, [=] {
navigation->show(Box(EditForumTopicBox, navigation, history, rootId));
}, &st::menuIconEdit);
}
void Filler::addManageChat() {
if (!EditPeerInfoBox::Available(_peer)) {
return;
@ -794,6 +821,9 @@ void Filler::addThemeEdit() {
}
void Filler::addTTLSubmenu(bool addSeparator) {
if (_topic) {
return; // #TODO later forum
}
const auto validator = TTLMenu::TTLValidator(
std::make_shared<Window::Show>(_controller),
_peer);
@ -887,6 +917,7 @@ void Filler::fillProfileActions() {
addGiftPremium();
addBotToGroup();
addNewMembers();
addManageTopic();
addManageChat();
addViewDiscussion();
addExportChat();
@ -897,6 +928,11 @@ void Filler::fillProfileActions() {
}
void Filler::fillRepliesActions() {
if (_topic) {
addInfo();
addManageTopic();
addManageChat();
}
addCreatePoll();
}

View File

@ -478,17 +478,6 @@ void SessionNavigation::showRepliesForMessage(
_api.request(base::take(_showingRepliesRequestId)).cancel();
const auto postPeer = history->peer;
//const auto item = _session->data().message(postPeer, rootId);
//if (!commentId && (!item || !item->repliesAreComments())) {
// showSection(std::make_shared<HistoryView::RepliesMemento>(history, rootId));
// return;
//} else if (const auto id = item ? item->commentsItemId() : FullMsgId()) {
// if (const auto commentsItem = _session->data().message(id)) {
// showSection(
// std::make_shared<HistoryView::RepliesMemento>(commentsItem));
// return;
// }
//}
_showingRepliesHistory = history;
_showingRepliesRootId = rootId;
_showingRepliesRequestId = _api.request(
@ -537,9 +526,11 @@ void SessionNavigation::showRepliesForMessage(
post->setRepliesOutboxReadTill(
data.vread_outbox_max_id().value_or_empty());
}
showSection(std::make_shared<HistoryView::RepliesMemento>(
item,
commentId));
showSection(
std::make_shared<HistoryView::RepliesMemento>(
item,
commentId),
params);
}
});
}).fail([=](const MTP::Error &error) {
@ -1577,9 +1568,8 @@ void SessionController::cancelUploadLayer(not_null<HistoryItem*> item) {
void SessionController::showSection(
std::shared_ptr<SectionMemento> memento,
const SectionShow &params) {
if (!params.thirdColumn && widget()->showSectionInExistingLayer(
memento.get(),
params)) {
if (!params.thirdColumn
&& widget()->showSectionInExistingLayer(memento.get(), params)) {
return;
}
content()->showSection(std::move(memento), params);