mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
feat: support tg://chat?id= links
This commit is contained in:
@@ -46,10 +46,48 @@ bool ResolveUser(
|
||||
return true;
|
||||
}
|
||||
|
||||
searchById(
|
||||
searchUserById(
|
||||
userId,
|
||||
&controller->session(),
|
||||
[=](const QString &title, UserData *data)
|
||||
[=](const QString &title, PeerData *data)
|
||||
{
|
||||
if (data) {
|
||||
controller->showPeerInfo(data);
|
||||
return;
|
||||
}
|
||||
|
||||
Core::App().hideMediaView();
|
||||
Ui::show(Ui::MakeInformBox(tr::ayu_UserNotFoundMessage()));
|
||||
}
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResolveChat(
|
||||
Window::SessionController *controller,
|
||||
const Match &match,
|
||||
const QVariant &context) {
|
||||
if (!controller) {
|
||||
return false;
|
||||
}
|
||||
const auto params = url_parse_params(
|
||||
match->captured(1),
|
||||
qthelp::UrlParamNameTransform::ToLower);
|
||||
const auto chatId = params.value(qsl("id")).toLongLong();
|
||||
if (!chatId) {
|
||||
return false;
|
||||
}
|
||||
const auto peer = controller->session().data().peerLoaded(static_cast<PeerId>(chatId));
|
||||
if (peer != nullptr) {
|
||||
controller->showPeerInfo(peer);
|
||||
return true;
|
||||
}
|
||||
|
||||
searchChatById(
|
||||
chatId,
|
||||
&controller->session(),
|
||||
[=](const QString &title, PeerData *data)
|
||||
{
|
||||
if (data) {
|
||||
controller->showPeerInfo(data);
|
||||
|
||||
@@ -18,6 +18,11 @@ bool ResolveUser(
|
||||
const Match &match,
|
||||
const QVariant &context);
|
||||
|
||||
bool ResolveChat(
|
||||
Window::SessionController *controller,
|
||||
const Match &match,
|
||||
const QVariant &context);
|
||||
|
||||
bool HandleAyu(
|
||||
Window::SessionController *controller,
|
||||
const Match &match,
|
||||
|
||||
@@ -221,10 +221,10 @@ void ActionStickerPackAuthor::searchAuthor(ID authorId) {
|
||||
const auto session = _session;
|
||||
const auto weak = base::make_weak(this);
|
||||
|
||||
searchById(
|
||||
searchUserById(
|
||||
authorId,
|
||||
session,
|
||||
[session, weak, authorId](const QString &username, UserData *user)
|
||||
[session, weak, authorId](const QString &username, PeerData *user)
|
||||
{
|
||||
if (!weak) {
|
||||
LOG(("ContextActionStickerAuthor: searchById callback after destruction"));
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "ayu/ayu_state.h"
|
||||
#include "ayu/data/messages_storage.h"
|
||||
#include "ayu/features/filters/filters_controller.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_poll.h"
|
||||
#include "data/data_saved_sublist.h"
|
||||
#include "lang/lang_text_entity.h"
|
||||
@@ -47,8 +48,8 @@
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
|
||||
|
||||
#include "unicode/regex.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto usernameResolverBotId = 7424190611L;
|
||||
@@ -102,7 +103,8 @@ bool isExteraPeer(ID peerId) {
|
||||
}
|
||||
|
||||
bool isSupporterPeer(ID peerId) {
|
||||
return RCManager::getInstance().supporters().contains(peerId) || RCManager::getInstance().supporterChannels().contains(peerId);
|
||||
return RCManager::getInstance().supporters().contains(peerId) || RCManager::getInstance().supporterChannels().
|
||||
contains(peerId);
|
||||
}
|
||||
|
||||
bool isCustomBadgePeer(ID peerId) {
|
||||
@@ -135,8 +137,9 @@ rpl::producer<Info::Profile::Badge::Content> ExteraBadgeTypeFromPeer(not_null<Pe
|
||||
return rpl::single(Info::Profile::Badge::Content{Info::Profile::BadgeType::None});
|
||||
}
|
||||
|
||||
Fn<void()> badgeClickHandler(not_null<PeerData *> peer) {
|
||||
return [=] {
|
||||
Fn<void()> badgeClickHandler(not_null<PeerData*> peer) {
|
||||
return [=]
|
||||
{
|
||||
const auto isCustomBadge = isCustomBadgePeer(getBareID(peer));
|
||||
const auto isExtera = isExteraPeer(getBareID(peer));
|
||||
const auto isSupporter = isSupporterPeer(getBareID(peer));
|
||||
@@ -596,7 +599,7 @@ int getScheduleTime(int64 sumSize) {
|
||||
return time;
|
||||
}
|
||||
|
||||
bool isMessageSavable(const not_null<HistoryItem *> item) {
|
||||
bool isMessageSavable(const not_null<HistoryItem*> item) {
|
||||
const auto &settings = AyuSettings::getInstance();
|
||||
|
||||
if (!settings.saveDeletedMessages) {
|
||||
@@ -618,7 +621,11 @@ void processMessageDelete(not_null<HistoryItem*> item) {
|
||||
}
|
||||
}
|
||||
|
||||
void resolveUser(ID userId, const QString &username, Main::Session *session, const UsernameResolverCallback &callback) {
|
||||
void resolvePeer(
|
||||
const QString &peerId,
|
||||
const QString &username,
|
||||
Main::Session *session,
|
||||
const UsernameResolverCallback &callback) {
|
||||
auto normalized = username.trimmed().toLower();
|
||||
if (normalized.isEmpty()) {
|
||||
callback(QString(), nullptr);
|
||||
@@ -642,11 +649,9 @@ void resolveUser(ID userId, const QString &username, Main::Session *session, con
|
||||
auto &data = result.c_contacts_resolvedPeer();
|
||||
session->data().processUsers(data.vusers());
|
||||
session->data().processChats(data.vchats());
|
||||
const auto peer = session->data().peerLoaded(
|
||||
peerFromMTP(data.vpeer()));
|
||||
if (const auto user = peer ? peer->asUser() : nullptr) {
|
||||
if ((user->id.value & PeerId::kChatTypeMask) == userId) {
|
||||
callback(normalized, user);
|
||||
if (const auto peer = session->data().peerLoaded(peerFromMTP(data.vpeer()))) {
|
||||
if (QString::number(peer->id.value & PeerId::kChatTypeMask) == peerId) {
|
||||
callback(normalized, peer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -658,26 +663,15 @@ void resolveUser(ID userId, const QString &username, Main::Session *session, con
|
||||
}).send();
|
||||
}
|
||||
|
||||
void searchUser(long long userId, Main::Session *session, bool searchUserFlag, const UsernameResolverCallback &callback) {
|
||||
void searchPeerInner(const QString &peerId, Main::Session *session, const UsernameResolverCallback &callback) {
|
||||
if (!session) {
|
||||
callback(QString(), nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto bot = session->data().userLoaded(usernameResolverBotId);
|
||||
|
||||
if (!bot) {
|
||||
if (searchUserFlag) {
|
||||
resolveUser(usernameResolverBotId,
|
||||
usernameResolverBotUsername,
|
||||
session,
|
||||
[=](const QString &title, UserData *data)
|
||||
{
|
||||
searchUser(userId, session, false, callback);
|
||||
});
|
||||
} else {
|
||||
callback(QString(), nullptr);
|
||||
}
|
||||
callback(QString(), nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -686,7 +680,7 @@ void searchUser(long long userId, Main::Session *session, bool searchUserFlag, c
|
||||
bot->inputUser,
|
||||
MTP_inputPeerEmpty(),
|
||||
MTPInputGeoPoint(),
|
||||
MTP_string(QString::number(userId)),
|
||||
MTP_string(peerId),
|
||||
MTP_string("")
|
||||
)).done([=](const MTPmessages_BotResults &result)
|
||||
{
|
||||
@@ -744,13 +738,13 @@ void searchUser(long long userId, Main::Session *session, bool searchUserFlag, c
|
||||
continue;
|
||||
}
|
||||
|
||||
ID id = 0; // 🆔
|
||||
QString id; // 🆔
|
||||
QString title; // 🏷
|
||||
QString username; // 📧
|
||||
|
||||
for (auto &line : text.split('\n')) {
|
||||
if (line.startsWith("🆔")) {
|
||||
id = line.mid(line.indexOf(": ") + 2).toLongLong();
|
||||
id = line.mid(line.indexOf(": ") + 2).trimmed();
|
||||
} else if (line.startsWith("🏷")) {
|
||||
title = line.mid(line.indexOf(": ") + 2);
|
||||
} else if (line.startsWith("📧")) {
|
||||
@@ -758,27 +752,33 @@ void searchUser(long long userId, Main::Session *session, bool searchUserFlag, c
|
||||
}
|
||||
}
|
||||
|
||||
if (id == 0 || id != userId) {
|
||||
if (id.isEmpty() || id != peerId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (id.startsWith("-100")) {
|
||||
id = id.mid(4);
|
||||
}
|
||||
|
||||
if (!username.isEmpty()) {
|
||||
resolveUser(id,
|
||||
username,
|
||||
session,
|
||||
[=](const QString &titleInner, UserData *data)
|
||||
{
|
||||
if (data) {
|
||||
callback(titleInner, data);
|
||||
} else {
|
||||
callback(title, nullptr);
|
||||
}
|
||||
});
|
||||
resolvePeer(
|
||||
id,
|
||||
username,
|
||||
session,
|
||||
[=](const QString &titleInner, PeerData *data)
|
||||
{
|
||||
if (data) {
|
||||
callback(titleInner, data);
|
||||
} else {
|
||||
callback(title, nullptr);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!title.isEmpty()) {
|
||||
callback(title, nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -789,28 +789,79 @@ void searchUser(long long userId, Main::Session *session, bool searchUserFlag, c
|
||||
}).handleAllErrors().send();
|
||||
}
|
||||
|
||||
void searchById(ID userId, Main::Session *session, const UsernameResolverCallback &callback) {
|
||||
void searchPeer(const QString &peerId, Main::Session *session, const UsernameResolverCallback &callback) {
|
||||
if (!session) {
|
||||
callback(QString(), nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (session->data().userLoaded(usernameResolverBotId)) {
|
||||
searchPeerInner(peerId, session, callback);
|
||||
} else {
|
||||
resolvePeer(
|
||||
QString::number(usernameResolverBotId),
|
||||
usernameResolverBotUsername,
|
||||
session,
|
||||
[=](const QString &title, PeerData *data)
|
||||
{
|
||||
searchPeerInner(peerId, session, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void searchUserById(ID userId, Main::Session *session, const UsernameResolverCallback &callback) {
|
||||
if (userId == 0 || !session) {
|
||||
callback(QString(), nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto dataLoaded = session->data().userLoaded(userId)) {
|
||||
callback(dataLoaded->username(), dataLoaded);
|
||||
if (const auto userLoaded = session->data().userLoaded(userId)) {
|
||||
callback(userLoaded->username(), userLoaded);
|
||||
return;
|
||||
}
|
||||
|
||||
searchUser(userId,
|
||||
session,
|
||||
true,
|
||||
[=](const QString &title, UserData *data)
|
||||
{
|
||||
if (data && data->accessHash()) {
|
||||
callback(title, data);
|
||||
} else {
|
||||
callback(QString(), nullptr);
|
||||
}
|
||||
});
|
||||
searchPeer(
|
||||
QString::number(userId),
|
||||
session,
|
||||
[=](const QString &title, PeerData *data)
|
||||
{
|
||||
if (data) {
|
||||
if (const auto user = data->asUser(); user->accessHash()) {
|
||||
callback(title, user);
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback(QString(), nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
void searchChatById(ID chatId, Main::Session *session, const UsernameResolverCallback &callback) {
|
||||
if (chatId == 0 || !session) {
|
||||
callback(QString(), nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto channelLoaded = session->data().channelLoaded(chatId)) {
|
||||
callback(channelLoaded->username(), channelLoaded);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto chatLoaded = session->data().chatLoaded(chatId)) {
|
||||
callback(chatLoaded->username(), chatLoaded);
|
||||
return;
|
||||
}
|
||||
|
||||
searchPeer(
|
||||
QString("-100") + QString::number(chatId),
|
||||
session,
|
||||
[=](const QString &title, PeerData *data)
|
||||
{
|
||||
if (data && (data->isChat() || data->isChannel())) {
|
||||
callback(title, data);
|
||||
} else {
|
||||
callback(QString(), nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ID getUserIdFromPackId(uint64 id) {
|
||||
@@ -867,20 +918,27 @@ void resolveAllChats(const std::map<long long, QString> &peers) {
|
||||
for (const auto &[id, username] : peers) {
|
||||
std::latch latch(1);
|
||||
|
||||
auto onSuccess = [=, &latch](const MTPChatInvite &invite) {
|
||||
|
||||
invite.match([=](const MTPDchatInvite &data) {},
|
||||
[=](const MTPDchatInviteAlready &data) {
|
||||
if (const auto chat = session->data().processChat(data.vchat())) {
|
||||
if (const auto channel = chat->asChannel()) {
|
||||
channel->clearInvitePeek();
|
||||
}
|
||||
}
|
||||
}, [=](const MTPDchatInvitePeek &data) {});
|
||||
auto onSuccess = [=, &latch](const MTPChatInvite &invite)
|
||||
{
|
||||
invite.match([=](const MTPDchatInvite &data)
|
||||
{
|
||||
},
|
||||
[=](const MTPDchatInviteAlready &data)
|
||||
{
|
||||
if (const auto chat = session->data().processChat(data.vchat())) {
|
||||
if (const auto channel = chat->asChannel()) {
|
||||
channel->clearInvitePeek();
|
||||
}
|
||||
}
|
||||
},
|
||||
[=](const MTPDchatInvitePeek &data)
|
||||
{
|
||||
});
|
||||
|
||||
latch.count_down();
|
||||
};
|
||||
auto onFail = [=, &latch](const MTP::Error &error) {
|
||||
auto onFail = [=, &latch](const MTP::Error &error)
|
||||
{
|
||||
if (MTP::IsFloodError(error.type())) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(20));
|
||||
}
|
||||
@@ -894,12 +952,12 @@ void resolveAllChats(const std::map<long long, QString> &peers) {
|
||||
});
|
||||
}
|
||||
|
||||
not_null<Main::Session *> currentSession() {
|
||||
not_null<Main::Session*> currentSession() {
|
||||
return &Core::App().domain().active().session();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
PeerData* getPeerFromDialogId(T id) {
|
||||
PeerData *getPeerFromDialogId(T id) {
|
||||
for (const auto &[index, account] : Core::App().domain().accounts()) {
|
||||
if (const auto session = account->maybeSession()) {
|
||||
PeerData *from = session->data().userLoaded(id);
|
||||
@@ -919,10 +977,10 @@ PeerData* getPeerFromDialogId(T id) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PeerData* getPeerFromDialogId(ID id) {
|
||||
PeerData *getPeerFromDialogId(ID id) {
|
||||
return getPeerFromDialogId<ID>(id);
|
||||
}
|
||||
|
||||
PeerData* getPeerFromDialogId(unsigned long long id) {
|
||||
PeerData *getPeerFromDialogId(unsigned long long id) {
|
||||
return getPeerFromDialogId<unsigned long long>(id);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "dialogs/dialogs_main_list.h"
|
||||
#include "info/profile/info_profile_badge.h"
|
||||
|
||||
using UsernameResolverCallback = Fn<void(const QString &, UserData *)>;
|
||||
using UsernameResolverCallback = Fn<void(const QString &, PeerData *)>;
|
||||
|
||||
Main::Session *getSession(ID userId);
|
||||
void dispatchToMainThread(const std::function<void()> &callback, int delay = 0);
|
||||
@@ -56,8 +56,8 @@ int getScheduleTime(int64 sumSize);
|
||||
bool isMessageSavable(not_null<HistoryItem *> item);
|
||||
void processMessageDelete(not_null<HistoryItem *> item);
|
||||
|
||||
void searchById(ID userId, Main::Session *session, bool retry, const UsernameResolverCallback &callback);
|
||||
void searchById(ID userId, Main::Session *session, const UsernameResolverCallback &callback);
|
||||
void searchUserById(ID userId, Main::Session *session, const UsernameResolverCallback &callback);
|
||||
void searchChatById(ID chatId, Main::Session *session, const UsernameResolverCallback &callback);
|
||||
|
||||
ID getUserIdFromPackId(uint64 id);
|
||||
|
||||
|
||||
@@ -781,10 +781,10 @@ void StickerSetBox::updateButtons() {
|
||||
return;
|
||||
}
|
||||
|
||||
searchById(
|
||||
searchUserById(
|
||||
innerId,
|
||||
session,
|
||||
[session, weak, innerId](const QString &username, UserData *user)
|
||||
[session, weak, innerId](const QString &username, PeerData *user)
|
||||
{
|
||||
if (!weak) {
|
||||
return;
|
||||
|
||||
@@ -1679,6 +1679,10 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
|
||||
u"^user\\?(.+)(#|$)"_q,
|
||||
AyuUrlHandlers::ResolveUser
|
||||
},
|
||||
{
|
||||
u"^chat\\?(.+)(#|$)"_q,
|
||||
AyuUrlHandlers::ResolveChat
|
||||
},
|
||||
{
|
||||
u"^ayu(/?.+)?(#|$)"_q,
|
||||
AyuUrlHandlers::HandleAyu
|
||||
|
||||
@@ -130,10 +130,10 @@ ResolvePhoneAction::ResolvePhoneAction(
|
||||
const auto weak = base::make_weak(this);
|
||||
const auto session = &controller->session();
|
||||
|
||||
searchById(
|
||||
searchUserById(
|
||||
possibleId,
|
||||
session,
|
||||
[weak](const QString &username, UserData *user)
|
||||
[weak](const QString &username, PeerData *user)
|
||||
{
|
||||
if (!weak) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user