Allow hiding members list in groups.
This commit is contained in:
parent
b0a24238e8
commit
af350e2daa
|
@ -184,6 +184,8 @@ PRIVATE
|
|||
boxes/peers/edit_forum_topic_box.h
|
||||
boxes/peers/edit_linked_chat_box.cpp
|
||||
boxes/peers/edit_linked_chat_box.h
|
||||
boxes/peers/edit_members_visible.cpp
|
||||
boxes/peers/edit_members_visible.h
|
||||
boxes/peers/edit_participant_box.cpp
|
||||
boxes/peers/edit_participant_box.h
|
||||
boxes/peers/edit_participants_box.cpp
|
||||
|
|
|
@ -1141,6 +1141,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_profile_set_group_photo" = "Set Photo";
|
||||
"lng_profile_add_participant" = "Add Members";
|
||||
"lng_profile_add_via_link" = "Invite via Link";
|
||||
"lng_profile_hide_participants" = "Hide Members";
|
||||
"lng_profile_hide_participants_about" = "Switch this on to hide the list of members in this group. Admins will remain visible.";
|
||||
"lng_profile_view_channel" = "View Channel";
|
||||
"lng_profile_view_discussion" = "View discussion";
|
||||
"lng_profile_join_channel" = "Join Channel";
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
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_members_visible.h"
|
||||
|
||||
#include "boxes/peers/edit_peer_info_box.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_info.h"
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> CreateMembersVisibleButton(
|
||||
not_null<ChannelData*> megagroup) {
|
||||
auto result = object_ptr<Ui::VerticalLayout>((QWidget*)nullptr);
|
||||
const auto container = result.data();
|
||||
|
||||
struct State {
|
||||
rpl::event_stream<bool> toggled;
|
||||
};
|
||||
Settings::AddSkip(container);
|
||||
const auto state = container->lifetime().make_state<State>();
|
||||
const auto button = container->add(
|
||||
EditPeerInfoBox::CreateButton(
|
||||
container,
|
||||
tr::lng_profile_hide_participants(),
|
||||
rpl::single(QString()),
|
||||
[] {},
|
||||
st::manageGroupTopicsButton,
|
||||
{ &st::infoRoundedIconAntiSpam, Settings::kIconPurple }
|
||||
))->toggleOn(rpl::single(
|
||||
(megagroup->flags() & ChannelDataFlag::ParticipantsHidden) != 0
|
||||
) | rpl::then(state->toggled.events()));
|
||||
Settings::AddSkip(container);
|
||||
Settings::AddDividerText(
|
||||
container,
|
||||
tr::lng_profile_hide_participants_about());
|
||||
|
||||
button->toggledValue(
|
||||
) | rpl::start_with_next([=](bool toggled) {
|
||||
megagroup->session().api().request(
|
||||
MTPchannels_ToggleParticipantsHidden(
|
||||
megagroup->inputChannel,
|
||||
MTP_bool(toggled)
|
||||
)
|
||||
).done([=](const MTPUpdates &result) {
|
||||
megagroup->session().api().applyUpdates(result);
|
||||
}).send();
|
||||
}, button->lifetime());
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
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 "base/object_ptr.h"
|
||||
|
||||
class ChannelData;
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
} // namespace Ui
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> CreateMembersVisibleButton(
|
||||
not_null<ChannelData*> megagroup);
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/peers/edit_participant_box.h"
|
||||
#include "boxes/peers/add_participants_box.h"
|
||||
#include "boxes/peers/prepare_short_info_box.h" // PrepareShortInfoBox
|
||||
#include "boxes/peers/edit_members_visible.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/max_invite_box.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
|
@ -1188,11 +1189,14 @@ void ParticipantsBoxController::prepare() {
|
|||
Unexpected("Role in ParticipantsBoxController::prepare()");
|
||||
}();
|
||||
if (const auto megagroup = _peer->asMegagroup()) {
|
||||
if ((_role == Role::Admins)
|
||||
if ((_role == Role::Members) && megagroup->canBanMembers()) {
|
||||
delegate()->peerListSetAboveWidget(CreateMembersVisibleButton(
|
||||
megagroup));
|
||||
} else if ((_role == Role::Admins)
|
||||
&& (megagroup->amCreator() || megagroup->hasAdminRights())) {
|
||||
const auto validator = AntiSpamMenu::AntiSpamValidator(
|
||||
_navigation->parentController(),
|
||||
_peer->asChannel());
|
||||
megagroup);
|
||||
delegate()->peerListSetAboveWidget(validator.createButton());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -577,7 +577,10 @@ bool ChannelData::allowsForwarding() const {
|
|||
}
|
||||
|
||||
bool ChannelData::canViewMembers() const {
|
||||
return flags() & Flag::CanViewParticipants;
|
||||
return (flags() & Flag::CanViewParticipants)
|
||||
&& (!(flags() & Flag::ParticipantsHidden)
|
||||
|| amCreator()
|
||||
|| hasAdminRights());
|
||||
}
|
||||
|
||||
bool ChannelData::canViewAdmins() const {
|
||||
|
@ -944,14 +947,20 @@ void ApplyChannelUpdate(
|
|||
| Flag::CanSetStickers
|
||||
| Flag::PreHistoryHidden
|
||||
| Flag::AntiSpam
|
||||
| Flag::Location;
|
||||
| Flag::Location
|
||||
| Flag::ParticipantsHidden;
|
||||
channel->setFlags((channel->flags() & ~mask)
|
||||
| (update.is_can_set_username() ? Flag::CanSetUsername : Flag())
|
||||
| (update.is_can_view_participants() ? Flag::CanViewParticipants : Flag())
|
||||
| (update.is_can_view_participants()
|
||||
? Flag::CanViewParticipants
|
||||
: Flag())
|
||||
| (update.is_can_set_stickers() ? Flag::CanSetStickers : Flag())
|
||||
| (update.is_hidden_prehistory() ? Flag::PreHistoryHidden : Flag())
|
||||
| (update.is_antispam() ? Flag::AntiSpam : Flag())
|
||||
| (update.vlocation() ? Flag::Location : Flag()));
|
||||
| (update.vlocation() ? Flag::Location : Flag())
|
||||
| (update.is_participants_hidden()
|
||||
? Flag::ParticipantsHidden
|
||||
: Flag()));
|
||||
channel->setUserpicPhoto(update.vchat_photo());
|
||||
if (const auto migratedFrom = update.vmigrated_from_chat_id()) {
|
||||
channel->addFlags(Flag::Megagroup);
|
||||
|
|
|
@ -58,6 +58,7 @@ enum class ChannelDataFlag {
|
|||
RequestToJoin = (1 << 22),
|
||||
Forum = (1 << 23),
|
||||
AntiSpam = (1 << 24),
|
||||
ParticipantsHidden = (1 << 25),
|
||||
};
|
||||
inline constexpr bool is_flag_type(ChannelDataFlag) { return true; };
|
||||
using ChannelDataFlags = base::flags<ChannelDataFlag>;
|
||||
|
|
|
@ -929,9 +929,12 @@ void ActionsFiller::addBlockAction(not_null<UserData*> user) {
|
|||
|
||||
void ActionsFiller::addLeaveChannelAction(not_null<ChannelData*> channel) {
|
||||
Expects(_controller->parentController());
|
||||
|
||||
AddActionButton(
|
||||
_wrap,
|
||||
tr::lng_profile_leave_channel(),
|
||||
(channel->isMegagroup()
|
||||
? tr::lng_profile_leave_group()
|
||||
: tr::lng_profile_leave_channel()),
|
||||
AmInChannelValue(channel),
|
||||
Window::DeleteAndLeaveHandler(
|
||||
_controller->parentController(),
|
||||
|
@ -947,7 +950,9 @@ void ActionsFiller::addJoinChannelAction(
|
|||
| rpl::start_spawning(_wrap->lifetime());
|
||||
AddActionButton(
|
||||
_wrap,
|
||||
tr::lng_profile_join_channel(),
|
||||
(channel->isMegagroup()
|
||||
? tr::lng_profile_join_group()
|
||||
: tr::lng_profile_join_channel()),
|
||||
rpl::duplicate(joinVisible),
|
||||
[=] { channel->session().api().joinChannel(channel); },
|
||||
&st::infoIconAddMember);
|
||||
|
@ -998,7 +1003,14 @@ void ActionsFiller::fillChannelActions(
|
|||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> ActionsFiller::fill() {
|
||||
auto wrapResult = [=](auto &&callback) {
|
||||
const auto wrapToggled = [=](
|
||||
object_ptr<Ui::RpWidget> content,
|
||||
rpl::producer<bool> shown) {
|
||||
auto result = object_ptr<Ui::SlideWrap<>>(_parent, std::move(content));
|
||||
result->setDuration(0)->toggleOn(std::move(shown));
|
||||
return result;
|
||||
};
|
||||
const auto wrapResult = [=](auto &&callback) {
|
||||
_wrap = object_ptr<Ui::VerticalLayout>(_parent);
|
||||
_wrap->add(CreateSkipWidget(_wrap));
|
||||
callback();
|
||||
|
@ -1010,8 +1022,11 @@ object_ptr<Ui::RpWidget> ActionsFiller::fill() {
|
|||
fillUserActions(user);
|
||||
});
|
||||
} else if (auto channel = _peer->asChannel()) {
|
||||
if (channel->isMegagroup()) {
|
||||
return { nullptr };
|
||||
if (const auto megagroup = channel->asMegagroup()) {
|
||||
using namespace rpl::mappers;
|
||||
return wrapToggled(wrapResult([=] {
|
||||
fillChannelActions(megagroup);
|
||||
}), CanViewParticipantsValue(megagroup) | rpl::map(!_1));
|
||||
}
|
||||
return wrapResult([=] {
|
||||
fillChannelActions(channel);
|
||||
|
|
|
@ -359,12 +359,7 @@ void Cover::setupChildGeometry() {
|
|||
}
|
||||
|
||||
Cover *Cover::setOnlineCount(rpl::producer<int> &&count) {
|
||||
std::move(
|
||||
count
|
||||
) | rpl::start_with_next([this](int count) {
|
||||
_onlineCount = count;
|
||||
refreshStatusText();
|
||||
}, lifetime());
|
||||
_onlineCount = std::move(count);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -377,18 +372,21 @@ void Cover::initViewers(rpl::producer<QString> title) {
|
|||
refreshNameGeometry(width());
|
||||
}, lifetime());
|
||||
|
||||
_peer->session().changes().peerFlagsValue(
|
||||
_peer,
|
||||
Flag::OnlineStatus | Flag::Members
|
||||
) | rpl::start_with_next(
|
||||
[=] { refreshStatusText(); },
|
||||
lifetime());
|
||||
rpl::combine(
|
||||
_peer->session().changes().peerFlagsValue(
|
||||
_peer,
|
||||
Flag::OnlineStatus | Flag::Members),
|
||||
_onlineCount.value()
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshStatusText();
|
||||
}, lifetime());
|
||||
|
||||
_peer->session().changes().peerFlagsValue(
|
||||
_peer,
|
||||
(_peer->isUser() ? Flag::IsContact : Flag::Rights)
|
||||
) | rpl::start_with_next(
|
||||
[=] { refreshUploadPhotoOverlay(); },
|
||||
lifetime());
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshUploadPhotoOverlay();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void Cover::refreshUploadPhotoOverlay() {
|
||||
|
@ -451,15 +449,17 @@ void Cover::refreshStatusText() {
|
|||
if (!chat->amIn()) {
|
||||
return tr::lng_chat_status_unaccessible({}, WithEntities);
|
||||
}
|
||||
auto fullCount = std::max(
|
||||
const auto onlineCount = _onlineCount.current();
|
||||
const auto fullCount = std::max(
|
||||
chat->count,
|
||||
int(chat->participants.size()));
|
||||
return { .text = ChatStatusText(fullCount, _onlineCount, true) };
|
||||
return { .text = ChatStatusText(fullCount, onlineCount, true) };
|
||||
} else if (auto channel = _peer->asChannel()) {
|
||||
auto fullCount = qMax(channel->membersCount(), 1);
|
||||
const auto onlineCount = _onlineCount.current();
|
||||
const auto fullCount = qMax(channel->membersCount(), 1);
|
||||
auto result = ChatStatusText(
|
||||
fullCount,
|
||||
_onlineCount,
|
||||
onlineCount,
|
||||
channel->isMegagroup());
|
||||
return hasMembersLink
|
||||
? PlainLink(result)
|
||||
|
|
|
@ -131,7 +131,7 @@ private:
|
|||
const not_null<PeerData*> _peer;
|
||||
const std::unique_ptr<EmojiStatusPanel> _emojiStatusPanel;
|
||||
const std::unique_ptr<Badge> _badge;
|
||||
int _onlineCount = 0;
|
||||
rpl::variable<int> _onlineCount;
|
||||
|
||||
object_ptr<Ui::UserpicButton> _userpic;
|
||||
object_ptr<TopicIconButton> _iconButton;
|
||||
|
|
|
@ -7,9 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "info/profile/info_profile_inner_widget.h"
|
||||
|
||||
#include <rpl/combine.h>
|
||||
#include <rpl/combine_previous.h>
|
||||
#include <rpl/flatten_latest.h>
|
||||
#include "info/info_memento.h"
|
||||
#include "info/info_controller.h"
|
||||
#include "info/profile/info_profile_widget.h"
|
||||
|
@ -31,8 +28,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_session_controller.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
|
@ -40,7 +35,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/box_content_divider.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_shared_media.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace Info {
|
||||
namespace Profile {
|
||||
|
@ -102,27 +100,42 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
|
|||
result->add(std::move(actions));
|
||||
}
|
||||
|
||||
if (_peer->isChat() || _peer->isMegagroup()) {
|
||||
_members = result->add(object_ptr<Members>(
|
||||
result,
|
||||
_controller));
|
||||
_members->scrollToRequests(
|
||||
) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
|
||||
auto min = (request.ymin < 0)
|
||||
? request.ymin
|
||||
: MapFrom(this, _members, QPoint(0, request.ymin)).y();
|
||||
auto max = (request.ymin < 0)
|
||||
? MapFrom(this, _members, QPoint()).y()
|
||||
: (request.ymax < 0)
|
||||
? request.ymax
|
||||
: MapFrom(this, _members, QPoint(0, request.ymax)).y();
|
||||
_scrollToRequests.fire({ min, max });
|
||||
}, _members->lifetime());
|
||||
_cover->setOnlineCount(_members->onlineCountValue());
|
||||
if (_peer->isChat()) {
|
||||
setupMembers(result.data());
|
||||
} else if (const auto megagroup = _peer->asMegagroup()) {
|
||||
CanViewParticipantsValue(
|
||||
megagroup
|
||||
) | rpl::start_with_next([=, raw = result.data()](bool can) {
|
||||
if (can) {
|
||||
setupMembers(raw);
|
||||
} else {
|
||||
_cover->setOnlineCount(rpl::single(0));
|
||||
delete base::take(_members);
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void InnerWidget::setupMembers(not_null<Ui::VerticalLayout*> container) {
|
||||
_members = container->add(object_ptr<Members>(
|
||||
container,
|
||||
_controller));
|
||||
_members->scrollToRequests(
|
||||
) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
|
||||
auto min = (request.ymin < 0)
|
||||
? request.ymin
|
||||
: MapFrom(this, _members, QPoint(0, request.ymin)).y();
|
||||
auto max = (request.ymin < 0)
|
||||
? MapFrom(this, _members, QPoint()).y()
|
||||
: (request.ymax < 0)
|
||||
? request.ymax
|
||||
: MapFrom(this, _members, QPoint(0, request.ymax)).y();
|
||||
_scrollToRequests.fire({ min, max });
|
||||
}, _members->lifetime());
|
||||
_cover->setOnlineCount(_members->onlineCountValue());
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
|
||||
not_null<RpWidget*> parent) {
|
||||
using namespace rpl::mappers;
|
||||
|
|
|
@ -58,6 +58,7 @@ protected:
|
|||
private:
|
||||
object_ptr<RpWidget> setupContent(not_null<RpWidget*> parent);
|
||||
object_ptr<RpWidget> setupSharedMedia(not_null<RpWidget*> parent);
|
||||
void setupMembers(not_null<Ui::VerticalLayout*> container);
|
||||
|
||||
int countDesiredHeight() const;
|
||||
void updateDesiredHeight() {
|
||||
|
|
|
@ -549,6 +549,20 @@ rpl::producer<int> FullReactionsCountValue(
|
|||
}) | rpl::distinct_until_changed();
|
||||
}
|
||||
|
||||
rpl::producer<bool> CanViewParticipantsValue(
|
||||
not_null<ChannelData*> megagroup) {
|
||||
if (megagroup->amCreator()) {
|
||||
return rpl::single(true);
|
||||
}
|
||||
return rpl::combine(
|
||||
megagroup->session().changes().peerFlagsValue(
|
||||
megagroup,
|
||||
UpdateFlag::Rights),
|
||||
megagroup->flagsValue(),
|
||||
[=] { return megagroup->canViewMembers(); }
|
||||
) | rpl::distinct_until_changed();
|
||||
}
|
||||
|
||||
template <typename Flag, typename Peer>
|
||||
rpl::producer<BadgeType> BadgeValueFromFlags(Peer peer) {
|
||||
return rpl::combine(
|
||||
|
|
|
@ -106,6 +106,8 @@ rpl::producer<not_null<PeerData*>> MigratedOrMeValue(
|
|||
not_null<PeerData*> peer);
|
||||
[[nodiscard]] rpl::producer<int> FullReactionsCountValue(
|
||||
not_null<Main::Session*> peer);
|
||||
[[nodiscard]] rpl::producer<bool> CanViewParticipantsValue(
|
||||
not_null<ChannelData*> megagroup);
|
||||
|
||||
enum class BadgeType;
|
||||
[[nodiscard]] rpl::producer<BadgeType> BadgeValue(not_null<PeerData*> peer);
|
||||
|
|
Loading…
Reference in New Issue