init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

View File

@@ -0,0 +1,188 @@
/*
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 "main/session/send_as_peers.h"
#include "data/data_user.h"
#include "data/data_channel.h"
#include "data/data_session.h"
#include "data/data_changes.h"
#include "main/main_session.h"
#include "apiwrap.h"
namespace Main {
namespace {
constexpr auto kRequestEach = 30 * crl::time(1000);
} // namespace
SendAsPeers::SendAsPeers(not_null<Session*> session)
: _session(session)
, _onlyMe({ { .peer = session->user(), .premiumRequired = false } })
, _onlyMePaid({ session->user() }) {
_session->changes().peerUpdates(
Data::PeerUpdate::Flag::Rights
) | rpl::map([=](const Data::PeerUpdate &update) {
const auto peer = update.peer;
const auto channel = peer->asChannel();
const auto bits = 0
| (peer->amAnonymous() ? (1 << 0) : 0)
| ((channel && channel->isPublic()) ? (1 << 1) : 0)
| ((channel && channel->addsSignature()) ? (1 << 2) : 0)
| ((channel && channel->signatureProfiles()) ? (1 << 3) : 0);
return std::tuple(peer, bits);
}) | rpl::distinct_until_changed(
) | rpl::filter([=](not_null<PeerData*> peer, int) {
return _lists.contains(peer) || _lastRequestTime.contains(peer);
}) | rpl::on_next([=](not_null<PeerData*> peer, int) {
refresh(peer, true);
}, _lifetime);
}
bool SendAsPeers::shouldChoose(SendAsKey key) {
refresh(key);
if (list(key).size() < 2) {
return false;
}
if (key.type == SendAsType::VideoStream) {
return true;
}
const auto channel = key.peer->asBroadcast();
return Data::CanSendAnything(key.peer, false)
&& (!channel
|| channel->addsSignature()
|| channel->signatureProfiles());
}
void SendAsPeers::refresh(SendAsKey key, bool force) {
if (key.type != SendAsType::VideoStream && !key.peer->isChannel()) {
return;
}
const auto now = crl::now();
const auto i = _lastRequestTime.find(key);
const auto when = (i == end(_lastRequestTime)) ? -1 : i->second;
if (!force && (when >= 0 && now < when + kRequestEach)) {
return;
}
_lastRequestTime[key] = now;
request(key);
if (key.type == SendAsType::Message) {
request({ key.peer, SendAsType::PaidReaction });
}
}
const std::vector<SendAsPeer> &SendAsPeers::list(SendAsKey key) const {
if (key.type != SendAsType::VideoStream && !key.peer->isChannel()) {
return _onlyMe;
}
const auto i = _lists.find(key);
return (i != end(_lists)) ? i->second : _onlyMe;
}
rpl::producer<SendAsKey> SendAsPeers::updated() const {
return _updates.events();
}
void SendAsPeers::saveChosen(
not_null<PeerData*> peer,
not_null<PeerData*> chosen) {
peer->session().api().request(MTPmessages_SaveDefaultSendAs(
peer->input(),
chosen->input()
)).send();
setChosen(peer, chosen->id);
}
void SendAsPeers::setChosen(not_null<PeerData*> peer, PeerId chosenId) {
if (chosen(peer) == chosenId) {
return;
}
const auto fallback = peer->amAnonymous()
? peer
: peer->session().user();
if (fallback->id == chosenId) {
_chosen.remove(peer);
} else {
_chosen[peer] = chosenId;
}
_updates.fire({ peer });
}
PeerId SendAsPeers::chosen(not_null<PeerData*> peer) const {
const auto i = _chosen.find(peer);
return (i != end(_chosen)) ? i->second : PeerId();
}
not_null<PeerData*> SendAsPeers::resolveChosen(
not_null<PeerData*> peer) const {
return ResolveChosen(peer, list({ peer }), chosen(peer));
}
not_null<PeerData*> SendAsPeers::ResolveChosen(
not_null<PeerData*> peer,
const std::vector<SendAsPeer> &list,
PeerId chosen) {
const auto fallback = peer->amAnonymous()
? peer
: peer->session().user();
if (!chosen) {
chosen = fallback->id;
}
const auto i = ranges::find(list, chosen, [](const SendAsPeer &as) {
return as.peer->id;
});
return (i != end(list))
? i->peer
: !list.empty()
? list.front().peer
: fallback;
}
void SendAsPeers::request(SendAsKey key) {
using Flag = MTPchannels_GetSendAs::Flag;
key.peer->session().api().request(MTPchannels_GetSendAs(
MTP_flags((key.type == SendAsType::PaidReaction)
? Flag::f_for_paid_reactions
: (key.type == SendAsType::VideoStream)
? Flag::f_for_live_stories
: Flag()),
key.peer->input()
)).done([=](const MTPchannels_SendAsPeers &result) {
auto parsed = std::vector<SendAsPeer>();
auto &owner = key.peer->owner();
result.match([&](const MTPDchannels_sendAsPeers &data) {
owner.processUsers(data.vusers());
owner.processChats(data.vchats());
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 (parsed.size() > 1) {
auto &now = _lists[key];
if (now != parsed) {
now = std::move(parsed);
_updates.fire_copy(key);
}
} else if (const auto i = _lists.find(key); i != end(_lists)) {
_lists.erase(i);
_updates.fire_copy(key);
}
}).send();
}
} // namespace Main

View File

@@ -0,0 +1,86 @@
/*
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
class PeerData;
namespace Main {
class Session;
struct SendAsPeer {
not_null<PeerData*> peer;
bool premiumRequired = false;
friend inline auto operator<=>(SendAsPeer, SendAsPeer) = default;
};
enum class SendAsType : uchar {
Message,
PaidReaction,
VideoStream,
};
struct SendAsKey {
SendAsKey(
not_null<PeerData*> peer,
SendAsType type = SendAsType::Message)
: peer(peer)
, type(type) {
}
friend inline auto operator<=>(SendAsKey, SendAsKey) = default;
friend inline bool operator==(SendAsKey, SendAsKey) = default;
not_null<PeerData*> peer;
SendAsType type = SendAsType::Message;
};
class SendAsPeers final {
public:
explicit SendAsPeers(not_null<Session*> session);
bool shouldChoose(SendAsKey key);
void refresh(SendAsKey key, bool force = false);
[[nodiscard]] const std::vector<SendAsPeer> &list(SendAsKey key) const;
[[nodiscard]] rpl::producer<SendAsKey> updated() const;
void saveChosen(not_null<PeerData*> peer, not_null<PeerData*> chosen);
void setChosen(not_null<PeerData*> peer, PeerId chosenId);
[[nodiscard]] PeerId chosen(not_null<PeerData*> peer) const;
[[nodiscard]] const std::vector<not_null<PeerData*>> &paidReactionList(
not_null<PeerData*> peer) const;
// If !list(peer).empty() then the result will be from that list.
[[nodiscard]] not_null<PeerData*> resolveChosen(
not_null<PeerData*> peer) const;
[[nodiscard]] static not_null<PeerData*> ResolveChosen(
not_null<PeerData*> peer,
const std::vector<SendAsPeer> &list,
PeerId chosen);
private:
void request(SendAsKey key);
const not_null<Session*> _session;
const std::vector<SendAsPeer> _onlyMe;
const std::vector<not_null<PeerData*>> _onlyMePaid;
base::flat_map<SendAsKey, std::vector<SendAsPeer>> _lists;
base::flat_map<SendAsKey, crl::time> _lastRequestTime;
base::flat_map<not_null<PeerData*>, PeerId> _chosen;
rpl::event_stream<SendAsKey> _updates;
rpl::lifetime _lifetime;
};
} // namespace Main

View File

@@ -0,0 +1,92 @@
/*
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 "main/session/session_show.h"
#include "chat_helpers/message_field.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/layers/generic_box.h"
namespace Main {
namespace {
class SimpleSessionShow final : public SessionShow {
public:
SimpleSessionShow(
std::shared_ptr<Ui::Show> show,
not_null<Session*> session);
void showOrHideBoxOrLayer(
std::variant<
v::null_t,
object_ptr<Ui::BoxContent>,
std::unique_ptr<Ui::LayerWidget>> &&layer,
Ui::LayerOptions options,
anim::type animated) const override;
not_null<QWidget*> toastParent() const override;
bool valid() const override;
operator bool() const override;
Session &session() const override;
private:
const std::shared_ptr<Ui::Show> _show;
const not_null<Session*> _session;
};
SimpleSessionShow::SimpleSessionShow(
std::shared_ptr<Ui::Show> show,
not_null<Session*> session)
: _show(std::move(show))
, _session(session) {
}
void SimpleSessionShow::showOrHideBoxOrLayer(
std::variant<
v::null_t,
object_ptr<Ui::BoxContent>,
std::unique_ptr<Ui::LayerWidget>> &&layer,
Ui::LayerOptions options,
anim::type animated) const {
_show->showOrHideBoxOrLayer(std::move(layer), options, animated);
}
not_null<QWidget*> SimpleSessionShow::toastParent() const {
return _show->toastParent();
}
bool SimpleSessionShow::valid() const {
return _show->valid();
}
SimpleSessionShow::operator bool() const {
return _show->operator bool();
}
Session &SimpleSessionShow::session() const {
return *_session;
}
} // namespace
bool SessionShow::showFrozenError() {
if (!session().frozen()) {
return false;
}
showBox(Box(FrozenInfoBox, &session(), FreezeInfoStyleOverride()));
return true;
}
std::shared_ptr<SessionShow> MakeSessionShow(
std::shared_ptr<Ui::Show> show,
not_null<Session*> session) {
return std::make_shared<SimpleSessionShow>(std::move(show), session);
}
} // namespace Main

View File

@@ -0,0 +1,28 @@
/*
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/show.h"
namespace Main {
class Session;
class SessionShow : public Ui::Show {
public:
[[nodiscard]] virtual Main::Session &session() const = 0;
bool showFrozenError();
};
[[nodiscard]] std::shared_ptr<SessionShow> MakeSessionShow(
std::shared_ptr<Ui::Show> show,
not_null<Session*> session);
} // namespace Main