mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Allow editing topic title and icon.
This commit is contained in:
parent
c90f879c96
commit
3b3792ef75
42 changed files with 603 additions and 190 deletions
|
@ -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
|
||||
|
|
223
Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp
Normal file
223
Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp
Normal 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();
|
||||
});
|
||||
}
|
27
Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.h
Normal file
27
Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.h
Normal 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);
|
|
@ -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 }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -59,8 +59,4 @@ private:
|
|||
|
||||
};
|
||||
|
||||
void ShowAddForumTopic(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<ChannelData*> forum);
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()) {
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ¶ms) {
|
||||
if (!params.thirdColumn && widget()->showSectionInExistingLayer(
|
||||
memento.get(),
|
||||
params)) {
|
||||
if (!params.thirdColumn
|
||||
&& widget()->showSectionInExistingLayer(memento.get(), params)) {
|
||||
return;
|
||||
}
|
||||
content()->showSection(std::move(memento), params);
|
||||
|
|
Loading…
Add table
Reference in a new issue