Skip to content

Commit

Permalink
Update API scheme on layer 145.
Browse files Browse the repository at this point in the history
Restrict send from channels to premium in line with API restrictions.
  • Loading branch information
john-preston committed Sep 2, 2022
1 parent e320319 commit 9bb2bb0
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 44 deletions.
2 changes: 2 additions & 0 deletions Telegram/Resources/langs/lang.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1935,6 +1935,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_send_anonymous_ph" = "Send anonymously...";
"lng_send_as_title" = "Send message as...";
"lng_send_as_anonymous_admin" = "Anonymous admin";
"lng_send_as_premium_required" = "Subscribe to {link} to be able to comment on behalf of your channels in group chats.";
"lng_send_as_premium_required_link" = "Telegram Premium";
"lng_record_cancel" = "Release outside this field to cancel";
"lng_record_lock_cancel_sure" = "Are you sure you want to stop recording and discard your voice message?";
"lng_record_listen_cancel_sure" = "Are you sure you want to discard your recorded voice message?";
Expand Down
4 changes: 3 additions & 1 deletion Telegram/Resources/tl/api.tl
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,7 @@ searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosi

messages.searchResultsPositions#53b22baf count:int positions:Vector<SearchResultsPosition> = messages.SearchResultsPositions;

channels.sendAsPeers#8356cda9 peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = channels.SendAsPeers;
channels.sendAsPeers#f496b0c6 peers:Vector<SendAsPeer> chats:Vector<Chat> users:Vector<User> = channels.SendAsPeers;

users.userFull#3b6d152e full_user:UserFull chats:Vector<Chat> users:Vector<User> = users.UserFull;

Expand Down Expand Up @@ -1442,6 +1442,8 @@ account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = accou

premiumSubscriptionOption#b6f11ebe flags:# current:flags.1?true can_purchase_upgrade:flags.2?true months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption;

sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer;

---functions---

invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
Expand Down
5 changes: 1 addition & 4 deletions Telegram/SourceFiles/boxes/peer_list_box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,10 +663,7 @@ int PeerListRow::paintNameIconGetWidth(
int availableWidth,
int outerWidth,
bool selected) {
if (special()
|| _isSavedMessagesChat
|| _isRepliesMessagesChat
|| !_peer->isUser()) {
if (special() || _isSavedMessagesChat || _isRepliesMessagesChat) {
return 0;
}
return _bagde.drawGetWidth(
Expand Down
35 changes: 22 additions & 13 deletions Telegram/SourceFiles/main/session/send_as_peers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ constexpr auto kRequestEach = 30 * crl::time(1000);

SendAsPeers::SendAsPeers(not_null<Session*> session)
: _session(session)
, _onlyMe({ session->user() }) {
, _onlyMe({ { .peer = session->user(), .premiumRequired = false } }) {
_session->changes().peerUpdates(
Data::PeerUpdate::Flag::Rights
) | rpl::map([=](const Data::PeerUpdate &update) {
Expand Down Expand Up @@ -60,7 +60,7 @@ void SendAsPeers::refresh(not_null<PeerData*> peer, bool force) {
request(peer);
}

const std::vector<not_null<PeerData*>> &SendAsPeers::list(
const std::vector<SendAsPeer> &SendAsPeers::list(
not_null<PeerData*> peer) const {
const auto i = _lists.find(peer);
return (i != end(_lists)) ? i->second : _onlyMe;
Expand Down Expand Up @@ -108,13 +108,15 @@ not_null<PeerData*> SendAsPeers::resolveChosen(

not_null<PeerData*> SendAsPeers::ResolveChosen(
not_null<PeerData*> peer,
const std::vector<not_null<PeerData*>> &list,
const std::vector<SendAsPeer> &list,
PeerId chosen) {
const auto i = ranges::find(list, chosen, &PeerData::id);
const auto i = ranges::find(list, chosen, [](const SendAsPeer &as) {
return as.peer->id;
});
return (i != end(list))
? (*i)
? i->peer
: !list.empty()
? list.front()
? list.front().peer
: (peer->isMegagroup() && peer->amAnonymous())
? peer
: peer->session().user();
Expand All @@ -124,21 +126,28 @@ void SendAsPeers::request(not_null<PeerData*> peer) {
peer->session().api().request(MTPchannels_GetSendAs(
peer->input
)).done([=](const MTPchannels_SendAsPeers &result) {
auto list = std::vector<not_null<PeerData*>>();
auto parsed = std::vector<SendAsPeer>();
auto &owner = peer->owner();
result.match([&](const MTPDchannels_sendAsPeers &data) {
owner.processUsers(data.vusers());
owner.processChats(data.vchats());
for (const auto &id : data.vpeers().v) {
if (const auto peer = owner.peerLoaded(peerFromMTP(id))) {
list.push_back(peer);
const auto &list = data.vpeers().v;
parsed.reserve(list.size());
for (const auto &as : list) {
const auto &data = as.data();
const auto peerId = peerFromMTP(data.vpeer());
if (const auto peer = owner.peerLoaded(peerId)) {
parsed.push_back({
.peer = peer,
.premiumRequired = data.is_premium_required(),
});
}
}
});
if (list.size() > 1) {
if (parsed.size() > 1) {
auto &now = _lists[peer];
if (now != list) {
now = std::move(list);
if (now != parsed) {
now = std::move(parsed);
_updates.fire_copy(peer);
}
} else if (const auto i = _lists.find(peer); i != end(_lists)) {
Expand Down
17 changes: 11 additions & 6 deletions Telegram/SourceFiles/main/session/send_as_peers.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,20 @@ namespace Main {

class Session;

struct SendAsPeer {
not_null<PeerData*> peer;
bool premiumRequired = false;

friend inline auto operator<=>(SendAsPeer, SendAsPeer) = default;
};

class SendAsPeers final {
public:
explicit SendAsPeers(not_null<Session*> session);

bool shouldChoose(not_null<PeerData*> peer);
void refresh(not_null<PeerData*> peer, bool force = false);
[[nodiscard]] const std::vector<not_null<PeerData*>> &list(
[[nodiscard]] const std::vector<SendAsPeer> &list(
not_null<PeerData*> peer) const;
[[nodiscard]] rpl::producer<not_null<PeerData*>> updated() const;

Expand All @@ -33,18 +40,16 @@ class SendAsPeers final {

[[nodiscard]] static not_null<PeerData*> ResolveChosen(
not_null<PeerData*> peer,
const std::vector<not_null<PeerData*>> &list,
const std::vector<SendAsPeer> &list,
PeerId chosen);

private:
void request(not_null<PeerData*> peer);

const not_null<Session*> _session;
const std::vector<not_null<PeerData*>> _onlyMe;
const std::vector<SendAsPeer> _onlyMe;

base::flat_map<
not_null<PeerData*>,
std::vector<not_null<PeerData*>>> _lists;
base::flat_map<not_null<PeerData*>, std::vector<SendAsPeer>> _lists;
base::flat_map<not_null<PeerData*>, crl::time> _lastRequestTime;
base::flat_map<not_null<PeerData*>, PeerId> _chosen;

Expand Down
149 changes: 131 additions & 18 deletions Telegram/SourceFiles/ui/chat/choose_send_as.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,45 @@ For license and copyright information please follow this link:
#include "data/data_peer_values.h"
#include "history/history.h"
#include "ui/controls/send_as_button.h"
#include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
#include "window/window_session_controller.h"
#include "main/main_session.h"
#include "main/session/send_as_peers.h"
#include "lang/lang_keys.h"
#include "settings/settings_premium.h"
#include "styles/style_calls.h"
#include "styles/style_boxes.h"
#include "styles/style_chat.h"
#include "styles/style_chat_helpers.h"

namespace Ui {
namespace {

class Row final : public PeerListRow {
public:
explicit Row(const Main::SendAsPeer &sendAsPeer);

int paintNameIconGetWidth(
Painter &p,
Fn<void()> repaint,
crl::time now,
int nameLeft,
int nameTop,
int nameWidth,
int availableWidth,
int outerWidth,
bool selected) override;

private:
bool _premiumRequired = false;

};

class ListController final : public PeerListController {
public:
ListController(
std::vector<not_null<PeerData*>> list,
std::vector<Main::SendAsPeer> list,
not_null<PeerData*> selected);

Main::Session &session() const override;
Expand All @@ -37,35 +61,78 @@ class ListController final : public PeerListController {
[[nodiscard]] rpl::producer<not_null<PeerData*>> clicked() const;

private:
std::unique_ptr<PeerListRow> createRow(not_null<PeerData*> peer);
std::unique_ptr<Row> createRow(const Main::SendAsPeer &sendAsPeer);

std::vector<not_null<PeerData*>> _list;
std::vector<Main::SendAsPeer> _list;
not_null<PeerData*> _selected;
rpl::event_stream<not_null<PeerData*>> _clicked;

};

Row::Row(const Main::SendAsPeer &sendAsPeer)
: PeerListRow(sendAsPeer.peer)
, _premiumRequired(sendAsPeer.premiumRequired) {
}

int Row::paintNameIconGetWidth(
Painter &p,
Fn<void()> repaint,
crl::time now,
int nameLeft,
int nameTop,
int nameWidth,
int availableWidth,
int outerWidth,
bool selected) {
if (_premiumRequired && !peer()->session().premium()) {
const auto &icon = st::emojiPremiumRequired;
availableWidth -= icon.width();
const auto x = nameLeft + std::min(nameWidth, availableWidth);
icon.paint(p, x, nameTop, outerWidth);
return icon.width();
}
return PeerListRow::paintNameIconGetWidth(
p,
std::move(repaint),
now,
nameLeft,
nameTop,
nameWidth,
availableWidth,
outerWidth,
selected);
}

ListController::ListController(
std::vector<not_null<PeerData*>> list,
std::vector<Main::SendAsPeer> list,
not_null<PeerData*> selected)
: PeerListController()
, _list(std::move(list))
, _selected(selected) {
Data::AmPremiumValue(
&selected->session()
) | rpl::skip(1) | rpl::start_with_next([=] {
const auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count; ++i) {
delegate()->peerListUpdateRow(
delegate()->peerListRowAt(i));
}
}, lifetime());
}

Main::Session &ListController::session() const {
return _selected->session();
}

std::unique_ptr<PeerListRow> ListController::createRow(
not_null<PeerData*> peer) {
auto result = std::make_unique<PeerListRow>(peer);
if (peer->isSelf()) {
std::unique_ptr<Row> ListController::createRow(
const Main::SendAsPeer &sendAsPeer) {
auto result = std::make_unique<Row>(sendAsPeer);
if (sendAsPeer.peer->isSelf()) {
result->setCustomStatus(
tr::lng_group_call_join_as_personal(tr::now));
} else if (peer->isMegagroup()) {
} else if (sendAsPeer.peer->isMegagroup()) {
result->setCustomStatus(tr::lng_send_as_anonymous_admin(tr::now));
} else if (const auto channel = peer->asChannel()) {
} else if (const auto channel = sendAsPeer.peer->asChannel()) {
result->setCustomStatus(tr::lng_chat_status_subscribers(
tr::now,
lt_count,
Expand All @@ -76,11 +143,11 @@ std::unique_ptr<PeerListRow> ListController::createRow(

void ListController::prepare() {
delegate()->peerListSetSearchMode(PeerListSearchMode::Disabled);
for (const auto &peer : _list) {
auto row = createRow(peer);
for (const auto &sendAsPeer : _list) {
auto row = createRow(sendAsPeer);
const auto raw = row.get();
delegate()->peerListAppendRow(std::move(row));
if (peer == _selected) {
if (sendAsPeer.peer == _selected) {
delegate()->peerListSetRowChecked(raw, true);
raw->finishCheckedAnimation();
}
Expand All @@ -100,14 +167,50 @@ rpl::producer<not_null<PeerData*>> ListController::clicked() const {
return _clicked.events();
}

void ShowPremiumPromoToast(not_null<Window::SessionController*> controller) {
using WeakToast = base::weak_ptr<Ui::Toast::Instance>;
const auto toast = std::make_shared<WeakToast>();

auto link = Ui::Text::Link(
tr::lng_send_as_premium_required_link(tr::now));
link.entities.push_back(
EntityInText(EntityType::Semibold, 0, link.text.size()));
const auto config = Ui::Toast::Config{
.text = tr::lng_send_as_premium_required(
tr::now,
lt_link,
link,
Ui::Text::WithEntities),
.st = &st::defaultMultilineToast,
.durationMs = Ui::Toast::kDefaultDuration * 2,
.multiline = true,
.filter = crl::guard(&controller->session(), [=](
const ClickHandlerPtr &,
Qt::MouseButton button) {
if (button == Qt::LeftButton) {
if (const auto strong = toast->get()) {
strong->hideAnimated();
(*toast) = nullptr;
Settings::ShowPremium(controller, "send_as");
return true;
}
}
return false;
}),
};
(*toast) = Ui::Toast::Show(
Window::Show(controller).toastParent(),
config);
}

} // namespace

void ChooseSendAsBox(
not_null<GenericBox*> box,
std::vector<not_null<PeerData*>> list,
std::vector<Main::SendAsPeer> list,
not_null<PeerData*> chosen,
Fn<void(not_null<PeerData*>)> done) {
Expects(ranges::contains(list, chosen));
Fn<bool(not_null<PeerData*>)> done) {
Expects(ranges::contains(list, chosen, &Main::SendAsPeer::peer));
Expects(done != nullptr);

box->setWidth(st::groupCallJoinAsWidth);
Expand All @@ -132,8 +235,7 @@ void ChooseSendAsBox(
controller->clicked(
) | rpl::start_with_next([=](not_null<PeerData*> peer) {
const auto weak = MakeWeak(box);
done(peer);
if (weak) {
if (done(peer) && weak) {
box->closeBox();
}
}, box->lifetime());
Expand Down Expand Up @@ -165,7 +267,18 @@ void SetupSendAsButton(
return;
}
const auto done = [=](not_null<PeerData*> sendAs) {
const auto i = ranges::find(
list,
sendAs,
&Main::SendAsPeer::peer);
if (i != end(list)
&& i->premiumRequired
&& !sendAs->session().premium()) {
ShowPremiumPromoToast(window);
return false;
}
session->sendAsPeers().saveChosen(peer, sendAs);
return true;
};
window->show(Box(
Ui::ChooseSendAsBox,
Expand Down
Loading

16 comments on commit 9bb2bb0

@Fangliding
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你所热爱的,就是你的生活

@lingclay
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

666

@voidlynx
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

So what's up with that?

@clover-yan
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nita mug bee!

@LinkBoi00
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That aged well

@hanbao233xD
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你所热爱的 就是你的生活
也许会 但绝对不会

@Ayx03
Copy link

@Ayx03 Ayx03 commented on 9bb2bb0 Sep 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Telegram 未来有可能会倒闭,但绝不会变质

@CCRcmcpe
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bruh.

@mubashir-rehman
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes! Another lie.

@Kyliekyler
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We all thought that free features remain free, so why is this happening?

@andrigamerita
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Durov for this amazing piece of software that gets more and more amazing every day 🙏🙏🙏🙏🏻

@ShionKanagawa
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Durov sucks

@ShionKanagawa
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fuck the durov great again lol

@PoneyClairDeLune
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh hey, Mr. Pavel Durov, care to explain what is "existing features remain free"?

@Aokromes
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh hey, Mr. Pavel Durov, care to explain what is "existing features remain free"?

you think durov reads here? stop spamming.

@dogtopus
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you think durov reads here? stop spamming.

Durov is ignoring anything criticizing telegram premium lol

Please sign in to comment.