mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Allow choosing allowed reactions in groups / channels.
This commit is contained in:
parent
bfdbb64295
commit
9c18f7b0e3
13 changed files with 363 additions and 12 deletions
|
@ -180,6 +180,8 @@ PRIVATE
|
||||||
boxes/peers/edit_peer_history_visibility_box.h
|
boxes/peers/edit_peer_history_visibility_box.h
|
||||||
boxes/peers/edit_peer_permissions_box.cpp
|
boxes/peers/edit_peer_permissions_box.cpp
|
||||||
boxes/peers/edit_peer_permissions_box.h
|
boxes/peers/edit_peer_permissions_box.h
|
||||||
|
boxes/peers/edit_peer_reactions.cpp
|
||||||
|
boxes/peers/edit_peer_reactions.h
|
||||||
boxes/peers/edit_peer_requests_box.cpp
|
boxes/peers/edit_peer_requests_box.cpp
|
||||||
boxes/peers/edit_peer_requests_box.h
|
boxes/peers/edit_peer_requests_box.h
|
||||||
boxes/peers/edit_peer_type_box.cpp
|
boxes/peers/edit_peer_type_box.cpp
|
||||||
|
|
|
@ -1005,9 +1005,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_manage_peer_removed_users" = "Removed users";
|
"lng_manage_peer_removed_users" = "Removed users";
|
||||||
"lng_manage_peer_permissions" = "Permissions";
|
"lng_manage_peer_permissions" = "Permissions";
|
||||||
"lng_manage_peer_invite_links" = "Invite links";
|
"lng_manage_peer_invite_links" = "Invite links";
|
||||||
|
"lng_manage_peer_reactions" = "Reactions";
|
||||||
|
"lng_manage_peer_reactions_off" = "Off";
|
||||||
"lng_manage_peer_requests" = "Member Requests";
|
"lng_manage_peer_requests" = "Member Requests";
|
||||||
"lng_manage_peer_requests_channel" = "Subscriber Requests";
|
"lng_manage_peer_requests_channel" = "Subscriber Requests";
|
||||||
|
|
||||||
|
"lng_manage_peer_reactions_enable" = "Enable Reactions";
|
||||||
|
"lng_manage_peer_reactions_about" = "Allow members to react to group messages.";
|
||||||
|
"lng_manage_peer_reactions_about_channel" = "Allow subscribers to react to channel posts.";
|
||||||
|
"lng_manage_peer_reactions_available" = "Available reactions";
|
||||||
|
|
||||||
"lng_manage_peer_group_type" = "Group type";
|
"lng_manage_peer_group_type" = "Group type";
|
||||||
"lng_manage_peer_channel_type" = "Channel type";
|
"lng_manage_peer_channel_type" = "Channel type";
|
||||||
"lng_manage_peer_link_type" = "Link type";
|
"lng_manage_peer_link_type" = "Link type";
|
||||||
|
|
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/peers/edit_peer_invite_links.h"
|
#include "boxes/peers/edit_peer_invite_links.h"
|
||||||
#include "boxes/peers/edit_linked_chat_box.h"
|
#include "boxes/peers/edit_linked_chat_box.h"
|
||||||
#include "boxes/peers/edit_peer_requests_box.h"
|
#include "boxes/peers/edit_peer_requests_box.h"
|
||||||
|
#include "boxes/peers/edit_peer_reactions.h"
|
||||||
#include "boxes/stickers_box.h"
|
#include "boxes/stickers_box.h"
|
||||||
#include "ui/boxes/single_choice_box.h"
|
#include "ui/boxes/single_choice_box.h"
|
||||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||||
|
@ -31,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
#include "data/data_message_reactions.h"
|
||||||
#include "history/admin_log/history_admin_log_section.h"
|
#include "history/admin_log/history_admin_log_section.h"
|
||||||
#include "info/profile/info_profile_values.h"
|
#include "info/profile/info_profile_values.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
@ -288,7 +290,8 @@ private:
|
||||||
object_ptr<Ui::RpWidget> createManageGroupButtons();
|
object_ptr<Ui::RpWidget> createManageGroupButtons();
|
||||||
object_ptr<Ui::RpWidget> createStickersEdit();
|
object_ptr<Ui::RpWidget> createStickersEdit();
|
||||||
|
|
||||||
bool canEditInformation() const;
|
[[nodiscard]] bool canEditInformation() const;
|
||||||
|
[[nodiscard]] bool canEditReactions() const;
|
||||||
void refreshHistoryVisibility();
|
void refreshHistoryVisibility();
|
||||||
void showEditPeerTypeBox(
|
void showEditPeerTypeBox(
|
||||||
std::optional<rpl::producer<QString>> error = {});
|
std::optional<rpl::producer<QString>> error = {});
|
||||||
|
@ -596,6 +599,17 @@ bool Controller::canEditInformation() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Controller::canEditReactions() const {
|
||||||
|
if (const auto channel = _peer->asChannel()) {
|
||||||
|
return channel->amCreator()
|
||||||
|
|| (channel->adminRights() & ChatAdminRight::ChangeInfo);
|
||||||
|
} else if (const auto chat = _peer->asChat()) {
|
||||||
|
return chat->amCreator()
|
||||||
|
|| (chat->adminRights() & ChatAdminRight::ChangeInfo);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Controller::refreshHistoryVisibility() {
|
void Controller::refreshHistoryVisibility() {
|
||||||
if (!_controls.historyVisibilityWrap) {
|
if (!_controls.historyVisibilityWrap) {
|
||||||
return;
|
return;
|
||||||
|
@ -1017,6 +1031,39 @@ void Controller::fillManageSection() {
|
||||||
}, wrap->lifetime());
|
}, wrap->lifetime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (canEditReactions()) {
|
||||||
|
const auto session = &_peer->session();
|
||||||
|
auto reactionsCount = Info::Profile::MigratedOrMeValue(
|
||||||
|
_peer
|
||||||
|
) | rpl::map(
|
||||||
|
Info::Profile::AllowedReactionsCountValue
|
||||||
|
) | rpl::flatten_latest();
|
||||||
|
auto fullCount = Info::Profile::FullReactionsCountValue(session);
|
||||||
|
auto label = rpl::combine(
|
||||||
|
std::move(reactionsCount),
|
||||||
|
std::move(fullCount)
|
||||||
|
) | rpl::map([=](int allowed, int total) {
|
||||||
|
return allowed
|
||||||
|
? QString::number(allowed) + " / " + QString::number(total)
|
||||||
|
: tr::lng_manage_peer_reactions_off(tr::now);
|
||||||
|
});
|
||||||
|
const auto done = [=](const std::vector<QString> &chosen) {
|
||||||
|
SaveAllowedReactions(_peer, chosen);
|
||||||
|
};
|
||||||
|
AddButtonWithCount(
|
||||||
|
_controls.buttonsLayout,
|
||||||
|
tr::lng_manage_peer_reactions(),
|
||||||
|
std::move(label),
|
||||||
|
[=] {
|
||||||
|
_navigation->parentController()->show(Box(
|
||||||
|
EditAllowedReactionsBox,
|
||||||
|
!_peer->isBroadcast(),
|
||||||
|
session->data().reactions().list(),
|
||||||
|
session->data().reactions().list(_peer),
|
||||||
|
done));
|
||||||
|
},
|
||||||
|
st::infoIconReactions);
|
||||||
|
}
|
||||||
if (canViewAdmins) {
|
if (canViewAdmins) {
|
||||||
AddButtonWithCount(
|
AddButtonWithCount(
|
||||||
_controls.buttonsLayout,
|
_controls.buttonsLayout,
|
||||||
|
|
209
Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp
Normal file
209
Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
/*
|
||||||
|
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_peer_reactions.h"
|
||||||
|
|
||||||
|
#include "data/data_message_reactions.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
|
#include "data/data_peer.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "info/profile/info_profile_icon.h"
|
||||||
|
#include "settings/settings_common.h"
|
||||||
|
#include "styles/style_settings.h"
|
||||||
|
#include "styles/style_info.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using Data::Reaction;
|
||||||
|
|
||||||
|
void AddReactionIcon(
|
||||||
|
not_null<Ui::RpWidget*> button,
|
||||||
|
not_null<DocumentData*> document) {
|
||||||
|
struct State {
|
||||||
|
std::shared_ptr<Data::DocumentMedia> media;
|
||||||
|
QImage image;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto size = st::editPeerReactionsPreview;
|
||||||
|
const auto state = button->lifetime().make_state<State>(State{
|
||||||
|
.media = document->createMediaView(),
|
||||||
|
});
|
||||||
|
const auto icon = Ui::CreateChild<Ui::RpWidget>(button.get());
|
||||||
|
icon->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
icon->resize(size, size);
|
||||||
|
button->sizeValue(
|
||||||
|
) | rpl::start_with_next([=](QSize size) {
|
||||||
|
icon->moveToLeft(
|
||||||
|
st::settingsSectionIconLeft,
|
||||||
|
(size.height() - icon->height()) / 2,
|
||||||
|
size.width());
|
||||||
|
}, icon->lifetime());
|
||||||
|
|
||||||
|
const auto setImage = [=](not_null<Image*> image) {
|
||||||
|
state->image = Images::prepare(
|
||||||
|
image->original(),
|
||||||
|
size * style::DevicePixelRatio(),
|
||||||
|
size * style::DevicePixelRatio(),
|
||||||
|
Images::Option::Smooth | Images::Option::TransparentBackground,
|
||||||
|
size,
|
||||||
|
size);
|
||||||
|
icon->update();
|
||||||
|
};
|
||||||
|
if (const auto image = state->media->getStickerLarge()) {
|
||||||
|
setImage(image);
|
||||||
|
} else {
|
||||||
|
document->session().downloaderTaskFinished(
|
||||||
|
) | rpl::map([=] {
|
||||||
|
return state->media->getStickerLarge();
|
||||||
|
}) | rpl::filter([=](Image *image) {
|
||||||
|
return (image != nullptr);
|
||||||
|
}) | rpl::take(
|
||||||
|
1
|
||||||
|
) | rpl::start_with_next([=](not_null<Image*> image) {
|
||||||
|
setImage(image);
|
||||||
|
}, button->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
icon->paintRequest(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
Painter p(icon);
|
||||||
|
const auto width = icon->width();
|
||||||
|
if (!state->image.isNull()) {
|
||||||
|
p.drawImage(0, 0, state->image);
|
||||||
|
}
|
||||||
|
}, icon->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void EditAllowedReactionsBox(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
bool isGroup,
|
||||||
|
const std::vector<Reaction> &list,
|
||||||
|
const std::vector<Reaction> &selected,
|
||||||
|
Fn<void(const std::vector<QString> &)> callback) {
|
||||||
|
box->setTitle(tr::lng_manage_peer_reactions());
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
base::flat_map<QString, not_null<Ui::SettingsButton*>> toggles;
|
||||||
|
rpl::variable<bool> anyToggled;
|
||||||
|
rpl::event_stream<bool> forceToggleAll;
|
||||||
|
};
|
||||||
|
const auto state = box->lifetime().make_state<State>(State{
|
||||||
|
.anyToggled = !selected.empty(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto collect = [=] {
|
||||||
|
auto result = std::vector<QString>();
|
||||||
|
result.reserve(state->toggles.size());
|
||||||
|
for (const auto &[emoji, button] : state->toggles) {
|
||||||
|
if (button->toggled()) {
|
||||||
|
result.push_back(emoji);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto container = box->verticalLayout();
|
||||||
|
|
||||||
|
const auto enabled = Settings::AddButton(
|
||||||
|
container,
|
||||||
|
tr::lng_manage_peer_reactions_enable(),
|
||||||
|
st::manageGroupButton.button);
|
||||||
|
Ui::CreateChild<Info::Profile::FloatingIcon>(
|
||||||
|
enabled.get(),
|
||||||
|
st::infoIconReactions,
|
||||||
|
st::manageGroupButton.iconPosition);
|
||||||
|
enabled->toggleOn(state->anyToggled.value());
|
||||||
|
enabled->toggledChanges(
|
||||||
|
) | rpl::filter([=](bool value) {
|
||||||
|
return (value != state->anyToggled.current());
|
||||||
|
}) | rpl::start_to_stream(state->forceToggleAll, enabled->lifetime());
|
||||||
|
|
||||||
|
Settings::AddSkip(container);
|
||||||
|
Settings::AddDividerText(
|
||||||
|
container,
|
||||||
|
(isGroup
|
||||||
|
? tr::lng_manage_peer_reactions_about
|
||||||
|
: tr::lng_manage_peer_reactions_about_channel)());
|
||||||
|
|
||||||
|
Settings::AddSkip(container);
|
||||||
|
Settings::AddSubsectionTitle(
|
||||||
|
container,
|
||||||
|
tr::lng_manage_peer_reactions_available());
|
||||||
|
|
||||||
|
const auto active = [&](const Data::Reaction &entry) {
|
||||||
|
return ranges::contains(selected, entry.emoji, &Reaction::emoji);
|
||||||
|
};
|
||||||
|
const auto add = [&](const Data::Reaction &entry) {
|
||||||
|
const auto button = Settings::AddButton(
|
||||||
|
container,
|
||||||
|
rpl::single(entry.title),
|
||||||
|
st::manageGroupButton.button);
|
||||||
|
AddReactionIcon(button, entry.staticIcon);
|
||||||
|
state->toggles.emplace(entry.emoji, button);
|
||||||
|
button->toggleOn(rpl::single(
|
||||||
|
active(entry)
|
||||||
|
) | rpl::then(
|
||||||
|
state->forceToggleAll.events()
|
||||||
|
));
|
||||||
|
button->toggledChanges(
|
||||||
|
) | rpl::start_with_next([=](bool toggled) {
|
||||||
|
if (toggled) {
|
||||||
|
state->anyToggled = true;
|
||||||
|
} else if (collect().empty()) {
|
||||||
|
state->anyToggled = false;
|
||||||
|
}
|
||||||
|
}, button->lifetime());
|
||||||
|
};
|
||||||
|
for (const auto &entry : list) {
|
||||||
|
add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
box->addButton(tr::lng_settings_save(), [=] {
|
||||||
|
const auto ids = collect();
|
||||||
|
box->closeBox();
|
||||||
|
callback(ids);
|
||||||
|
});
|
||||||
|
box->addButton(tr::lng_cancel(), [=] {
|
||||||
|
box->closeBox();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveAllowedReactions(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
const std::vector<QString> &allowed) {
|
||||||
|
auto ids = allowed | ranges::views::transform([=](QString value) {
|
||||||
|
return MTP_string(value);
|
||||||
|
}) | ranges::to<QVector>;
|
||||||
|
|
||||||
|
peer->session().api().request(MTPmessages_SetChatAvailableReactions(
|
||||||
|
peer->input,
|
||||||
|
MTP_vector<MTPstring>(ids)
|
||||||
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
peer->session().api().applyUpdates(result);
|
||||||
|
if (const auto chat = peer->asChat()) {
|
||||||
|
chat->setAllowedReactions(allowed);
|
||||||
|
} else if (const auto channel = peer->asChannel()) {
|
||||||
|
channel->setAllowedReactions(allowed);
|
||||||
|
} else {
|
||||||
|
Unexpected("Invalid peer type in SaveAllowedReactions.");
|
||||||
|
}
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
if (error.type() == qstr("REACTION_INVALID")) {
|
||||||
|
peer->updateFullForced();
|
||||||
|
peer->owner().reactions().refresh();
|
||||||
|
}
|
||||||
|
}).send();
|
||||||
|
}
|
27
Telegram/SourceFiles/boxes/peers/edit_peer_reactions.h
Normal file
27
Telegram/SourceFiles/boxes/peers/edit_peer_reactions.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 PeerData;
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
struct Reaction;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
|
void EditAllowedReactionsBox(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
bool isGroup,
|
||||||
|
const std::vector<Data::Reaction> &list,
|
||||||
|
const std::vector<Data::Reaction> &selected,
|
||||||
|
Fn<void(const std::vector<QString> &)> callback);
|
||||||
|
|
||||||
|
void SaveAllowedReactions(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
const std::vector<QString> &allowed);
|
|
@ -86,17 +86,18 @@ struct PeerUpdate {
|
||||||
BannedUsers = (1ULL << 25),
|
BannedUsers = (1ULL << 25),
|
||||||
Rights = (1ULL << 26),
|
Rights = (1ULL << 26),
|
||||||
PendingRequests = (1ULL << 27),
|
PendingRequests = (1ULL << 27),
|
||||||
|
Reactions = (1ULL << 28),
|
||||||
|
|
||||||
// For channels
|
// For channels
|
||||||
ChannelAmIn = (1ULL << 28),
|
ChannelAmIn = (1ULL << 29),
|
||||||
StickersSet = (1ULL << 29),
|
StickersSet = (1ULL << 30),
|
||||||
ChannelLinkedChat = (1ULL << 30),
|
ChannelLinkedChat = (1ULL << 31),
|
||||||
ChannelLocation = (1ULL << 31),
|
ChannelLocation = (1ULL << 32),
|
||||||
Slowmode = (1ULL << 32),
|
Slowmode = (1ULL << 33),
|
||||||
GroupCall = (1ULL << 33),
|
GroupCall = (1ULL << 34),
|
||||||
|
|
||||||
// For iteration
|
// For iteration
|
||||||
LastUsedBit = (1ULL << 33),
|
LastUsedBit = (1ULL << 34),
|
||||||
};
|
};
|
||||||
using Flags = base::flags<Flag>;
|
using Flags = base::flags<Flag>;
|
||||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||||
|
|
|
@ -762,7 +762,10 @@ PeerId ChannelData::groupCallDefaultJoinAs() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelData::setAllowedReactions(std::vector<QString> list) {
|
void ChannelData::setAllowedReactions(std::vector<QString> list) {
|
||||||
_allowedReactions = std::move(list);
|
if (_allowedReactions != list) {
|
||||||
|
_allowedReactions = std::move(list);
|
||||||
|
session().changes().peerUpdated(this, UpdateFlag::Reactions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<QString> &ChannelData::allowedReactions() const {
|
const std::vector<QString> &ChannelData::allowedReactions() const {
|
||||||
|
|
|
@ -288,7 +288,10 @@ void ChatData::setPendingRequestsCount(
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatData::setAllowedReactions(std::vector<QString> list) {
|
void ChatData::setAllowedReactions(std::vector<QString> list) {
|
||||||
_allowedReactions = std::move(list);
|
if (_allowedReactions != list) {
|
||||||
|
_allowedReactions = std::move(list);
|
||||||
|
session().changes().peerUpdated(this, UpdateFlag::Reactions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<QString> &ChatData::allowedReactions() const {
|
const std::vector<QString> &ChatData::allowedReactions() const {
|
||||||
|
|
|
@ -24,15 +24,19 @@ constexpr auto kRefreshEach = 60 * 60 * crl::time(1000);
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Reactions::Reactions(not_null<Session*> owner) : _owner(owner) {
|
Reactions::Reactions(not_null<Session*> owner) : _owner(owner) {
|
||||||
request();
|
refresh();
|
||||||
|
|
||||||
base::timer_each(
|
base::timer_each(
|
||||||
kRefreshEach
|
kRefreshEach
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
request();
|
refresh();
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Reactions::refresh() {
|
||||||
|
request();
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<Reaction> &Reactions::list() const {
|
const std::vector<Reaction> &Reactions::list() const {
|
||||||
return _available;
|
return _available;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +51,10 @@ std::vector<Reaction> Reactions::list(not_null<PeerData*> peer) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<> Reactions::updates() const {
|
||||||
|
return _updated.events();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Reaction> Reactions::Filtered(
|
std::vector<Reaction> Reactions::Filtered(
|
||||||
const std::vector<Reaction> &reactions,
|
const std::vector<Reaction> &reactions,
|
||||||
const std::vector<QString> &emoji) {
|
const std::vector<QString> &emoji) {
|
||||||
|
|
|
@ -24,6 +24,8 @@ class Reactions final {
|
||||||
public:
|
public:
|
||||||
explicit Reactions(not_null<Session*> owner);
|
explicit Reactions(not_null<Session*> owner);
|
||||||
|
|
||||||
|
void refresh();
|
||||||
|
|
||||||
[[nodiscard]] const std::vector<Reaction> &list() const;
|
[[nodiscard]] const std::vector<Reaction> &list() const;
|
||||||
[[nodiscard]] std::vector<Reaction> list(not_null<PeerData*> peer) const;
|
[[nodiscard]] std::vector<Reaction> list(not_null<PeerData*> peer) const;
|
||||||
|
|
||||||
|
|
|
@ -362,6 +362,7 @@ infoIconAdministrators: icon {{ "info/edit/group_manage_admins", infoIconFg, poi
|
||||||
infoIconBlacklist: icon {{ "info_blacklist", infoIconFg, point(-2px, -2px) }};
|
infoIconBlacklist: icon {{ "info_blacklist", infoIconFg, point(-2px, -2px) }};
|
||||||
infoIconPermissions: icon {{ "info/edit/group_manage_permissions", infoIconFg, point(0px, -2px) }};
|
infoIconPermissions: icon {{ "info/edit/group_manage_permissions", infoIconFg, point(0px, -2px) }};
|
||||||
infoIconInviteLinks: icon {{ "info/edit/group_manage_links", infoIconFg, point(-2px, 0px) }};
|
infoIconInviteLinks: icon {{ "info/edit/group_manage_links", infoIconFg, point(-2px, 0px) }};
|
||||||
|
infoIconReactions: icon {{ "menu/read_reactions", infoIconFg, point(2px, 4px) }};
|
||||||
infoInformationIconPosition: point(25px, 12px);
|
infoInformationIconPosition: point(25px, 12px);
|
||||||
infoNotificationsIconPosition: point(20px, 5px);
|
infoNotificationsIconPosition: point(20px, 5px);
|
||||||
infoSharedMediaIconPosition: point(20px, 24px);
|
infoSharedMediaIconPosition: point(20px, 24px);
|
||||||
|
@ -707,6 +708,11 @@ editPeerInvitesTopSkip: 10px;
|
||||||
editPeerInvitesSkip: 10px;
|
editPeerInvitesSkip: 10px;
|
||||||
editPeerInviteLinkBoxBottomSkip: 15px;
|
editPeerInviteLinkBoxBottomSkip: 15px;
|
||||||
|
|
||||||
|
editPeerReactionsButton: SettingsButton(infoProfileButton) {
|
||||||
|
padding: margins(59px, 13px, 8px, 11px);
|
||||||
|
}
|
||||||
|
editPeerReactionsPreview: 28px;
|
||||||
|
|
||||||
historyTopBarBack: IconButton(infoTopBarBack) {
|
historyTopBarBack: IconButton(infoTopBarBack) {
|
||||||
width: 52px;
|
width: 52px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "data/data_peer_values.h"
|
#include "data/data_peer_values.h"
|
||||||
#include "data/data_shared_media.h"
|
#include "data/data_shared_media.h"
|
||||||
|
#include "data/data_message_reactions.h"
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
@ -401,6 +402,35 @@ rpl::producer<bool> CanAddMemberValue(not_null<PeerData*> peer) {
|
||||||
return rpl::single(false);
|
return rpl::single(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<int> FullReactionsCountValue(
|
||||||
|
not_null<Main::Session*> session) {
|
||||||
|
const auto reactions = &session->data().reactions();
|
||||||
|
return rpl::single(
|
||||||
|
rpl::empty_value()
|
||||||
|
) | rpl::then(
|
||||||
|
reactions->updates()
|
||||||
|
) | rpl::map([=] {
|
||||||
|
return int(reactions->list().size());
|
||||||
|
}) | rpl::distinct_until_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<int> AllowedReactionsCountValue(not_null<PeerData*> peer) {
|
||||||
|
if (peer->isUser()) {
|
||||||
|
return FullReactionsCountValue(&peer->session());
|
||||||
|
}
|
||||||
|
return peer->session().changes().peerFlagsValue(
|
||||||
|
peer,
|
||||||
|
UpdateFlag::Reactions
|
||||||
|
) | rpl::map([=] {
|
||||||
|
if (const auto chat = peer->asChat()) {
|
||||||
|
return int(chat->allowedReactions().size());
|
||||||
|
} else if (const auto channel = peer->asChannel()) {
|
||||||
|
return int(channel->allowedReactions().size());
|
||||||
|
}
|
||||||
|
Unexpected("Peer type in AllowedReactionsCountValue.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Flag, typename Peer>
|
template <typename Flag, typename Peer>
|
||||||
rpl::producer<Badge> BadgeValueFromFlags(Peer peer) {
|
rpl::producer<Badge> BadgeValueFromFlags(Peer peer) {
|
||||||
return Data::PeerFlagsValue(
|
return Data::PeerFlagsValue(
|
||||||
|
|
|
@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
struct ChannelLocation;
|
struct ChannelLocation;
|
||||||
|
|
||||||
|
namespace Main {
|
||||||
|
class Session;
|
||||||
|
} // namespace Main
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class RpWidget;
|
class RpWidget;
|
||||||
template <typename Widget>
|
template <typename Widget>
|
||||||
|
@ -63,6 +67,8 @@ rpl::producer<int> SharedMediaCountValue(
|
||||||
Storage::SharedMediaType type);
|
Storage::SharedMediaType type);
|
||||||
rpl::producer<int> CommonGroupsCountValue(not_null<UserData*> user);
|
rpl::producer<int> CommonGroupsCountValue(not_null<UserData*> user);
|
||||||
rpl::producer<bool> CanAddMemberValue(not_null<PeerData*> peer);
|
rpl::producer<bool> CanAddMemberValue(not_null<PeerData*> peer);
|
||||||
|
rpl::producer<int> FullReactionsCountValue(not_null<Main::Session*> peer);
|
||||||
|
rpl::producer<int> AllowedReactionsCountValue(not_null<PeerData*> peer);
|
||||||
|
|
||||||
enum class Badge {
|
enum class Badge {
|
||||||
None,
|
None,
|
||||||
|
|
Loading…
Add table
Reference in a new issue