mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Update API scheme on layer 145.
Restrict send from channels to premium in line with API restrictions.
This commit is contained in:
parent
e32031963b
commit
9bb2bb09b9
7 changed files with 176 additions and 44 deletions
|
@ -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?";
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -33,18 +40,16 @@ public:
|
|||
|
||||
[[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;
|
||||
|
||||
|
|
|
@ -13,21 +13,45 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#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;
|
||||
|
@ -37,35 +61,78 @@ public:
|
|||
[[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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
|
|
@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
class PeerData;
|
||||
|
||||
namespace Main {
|
||||
struct SendAsPeer;
|
||||
} // namespace Main
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
@ -22,9 +26,9 @@ class SendAsButton;
|
|||
|
||||
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);
|
||||
Fn<bool(not_null<PeerData*>)> done);
|
||||
|
||||
void SetupSendAsButton(
|
||||
not_null<SendAsButton*> button,
|
||||
|
|
Loading…
Add table
Reference in a new issue