2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 14:45:14 +00:00

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

@@ -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