tdesktop/Telegram/SourceFiles/api/api_chat_invite.cpp

360 lines
11 KiB
C++
Raw Normal View History

2020-07-01 14:19:25 +00:00
/*
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 "api/api_chat_invite.h"
#include "apiwrap.h"
#include "window/window_session_controller.h"
#include "lang/lang_keys.h"
2020-07-01 14:19:25 +00:00
#include "main/main_session.h"
#include "ui/empty_userpic.h"
#include "core/application.h"
#include "data/data_session.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_channel.h"
#include "data/data_user.h"
#include "data/data_file_origin.h"
2021-10-18 21:36:55 +00:00
#include "ui/boxes/confirm_box.h"
#include "ui/toasts/common_toasts.h"
2022-05-06 12:46:43 +00:00
#include "boxes/premium_limits_box.h"
2020-07-01 14:19:25 +00:00
#include "styles/style_boxes.h"
#include "styles/style_layers.h"
namespace Api {
namespace {
void SubmitChatInvite(
base::weak_ptr<Window::SessionController> weak,
not_null<Main::Session*> session,
const QString &hash,
bool isGroup) {
session->api().request(MTPmessages_ImportChatInvite(
MTP_string(hash)
)).done([=](const MTPUpdates &result) {
session->api().applyUpdates(result);
const auto strongController = weak.get();
if (!strongController) {
return;
}
strongController->hideLayer();
const auto handleChats = [&](const MTPVector<MTPChat> &chats) {
if (chats.v.isEmpty()) {
return;
}
const auto peerId = chats.v[0].match([](const MTPDchat &data) {
return peerFromChat(data.vid().v);
}, [](const MTPDchannel &data) {
return peerFromChannel(data.vid().v);
}, [](auto&&) {
return PeerId(0);
});
if (const auto peer = session->data().peerLoaded(peerId)) {
// Shows in the primary window anyway.
strongController->showPeerHistory(
peer,
Window::SectionShow::Way::Forward);
}
};
result.match([&](const MTPDupdates &data) {
handleChats(data.vchats());
}, [&](const MTPDupdatesCombined &data) {
handleChats(data.vchats());
}, [&](auto &&) {
LOG(("API Error: unexpected update cons %1 "
"(ApiWrap::importChatInvite)").arg(result.type()));
});
}).fail([=](const MTP::Error &error) {
2022-05-06 12:46:43 +00:00
const auto &type = error.type();
const auto strongController = weak.get();
if (!strongController) {
return;
2022-05-06 12:46:43 +00:00
} else if (type == u"CHANNELS_TOO_MUCH"_q) {
strongController->show(
Box(ChannelsLimitBox, &strongController->session()));
}
strongController->hideLayer();
Ui::ShowMultilineToast({
.parentOverride = Window::Show(strongController).toastParent(),
.text = { [&] {
if (type == u"INVITE_REQUEST_SENT"_q) {
return isGroup
? tr::lng_group_request_sent(tr::now)
: tr::lng_group_request_sent_channel(tr::now);
} else if (type == u"USERS_TOO_MUCH"_q) {
return tr::lng_group_invite_no_room(tr::now);
} else {
return tr::lng_group_invite_bad_link(tr::now);
}
}() },
.duration = ApiWrap::kJoinErrorDuration });
}).send();
}
} // namespace
2020-07-01 14:19:25 +00:00
void CheckChatInvite(
not_null<Window::SessionController*> controller,
const QString &hash,
ChannelData *invitePeekChannel) {
const auto session = &controller->session();
const auto weak = base::make_weak(controller.get());
session->api().checkChatInvite(hash, [=](const MTPChatInvite &result) {
Core::App().hideMediaView();
result.match([=](const MTPDchatInvite &data) {
const auto strongController = weak.get();
if (!strongController) {
return;
}
2021-10-12 12:50:18 +00:00
const auto isGroup = !data.is_broadcast();
const auto box = strongController->show(Box<ConfirmInviteBox>(
2020-07-01 14:19:25 +00:00
session,
data,
invitePeekChannel,
[=] { SubmitChatInvite(weak, session, hash, isGroup); }));
2020-07-01 14:19:25 +00:00
if (invitePeekChannel) {
box->boxClosing(
) | rpl::filter([=] {
return !invitePeekChannel->amIn();
}) | rpl::start_with_next([=] {
if (const auto strong = weak.get()) {
strong->clearSectionStack(Window::SectionShow(
Window::SectionShow::Way::ClearStack,
anim::type::normal,
anim::activation::background));
}
}, box->lifetime());
}
}, [=](const MTPDchatInviteAlready &data) {
if (const auto chat = session->data().processChat(data.vchat())) {
if (const auto channel = chat->asChannel()) {
channel->clearInvitePeek();
}
if (const auto strong = weak.get()) {
strong->showPeerHistory(
chat,
Window::SectionShow::Way::Forward);
}
}
}, [=](const MTPDchatInvitePeek &data) {
if (const auto chat = session->data().processChat(data.vchat())) {
if (const auto channel = chat->asChannel()) {
channel->setInvitePeek(hash, data.vexpires().v);
if (const auto strong = weak.get()) {
strong->showPeerHistory(
chat,
Window::SectionShow::Way::Forward);
}
}
}
});
2021-03-12 12:48:00 +00:00
}, [=](const MTP::Error &error) {
2020-07-01 14:19:25 +00:00
if (error.code() != 400) {
return;
}
Core::App().hideMediaView();
if (const auto strong = weak.get()) {
strong->show(Ui::MakeInformBox(tr::lng_group_invite_bad_link()));
}
2020-07-01 14:19:25 +00:00
});
}
} // namespace Api
ConfirmInviteBox::ConfirmInviteBox(
QWidget*,
not_null<Main::Session*> session,
const MTPDchatInvite &data,
ChannelData *invitePeekChannel,
Fn<void()> submit)
: _session(session)
, _submit(std::move(submit))
, _title(this, st::confirmInviteTitle)
, _status(this, st::confirmInviteStatus)
2021-10-14 13:45:13 +00:00
, _about(this, st::confirmInviteAbout)
, _aboutRequests(this, st::confirmInviteStatus)
2020-07-01 14:19:25 +00:00
, _participants(GetParticipants(_session, data))
2021-10-12 12:50:18 +00:00
, _isChannel(data.is_channel() && !data.is_megagroup())
, _requestApprove(data.is_request_needed()) {
2020-07-01 14:19:25 +00:00
const auto title = qs(data.vtitle());
const auto count = data.vparticipants_count().v;
const auto status = [&] {
return invitePeekChannel
? tr::lng_channel_invite_private(tr::now)
: (!_participants.empty() && _participants.size() < count)
? tr::lng_group_invite_members(tr::now, lt_count, count)
: (count > 0 && _isChannel)
? tr::lng_chat_status_subscribers(
tr::now,
lt_count_decimal,
count)
2020-07-01 14:19:25 +00:00
: (count > 0)
? tr::lng_chat_status_members(tr::now, lt_count_decimal, count)
: _isChannel
? tr::lng_channel_status(tr::now)
: tr::lng_group_status(tr::now);
}();
_title->setText(title);
_status->setText(status);
2021-10-14 13:45:13 +00:00
if (const auto v = qs(data.vabout().value_or_empty()); !v.isEmpty()) {
_about->setText(v);
} else {
_about.destroy();
}
if (_requestApprove) {
_aboutRequests->setText(_isChannel
? tr::lng_group_request_about_channel(tr::now)
: tr::lng_group_request_about(tr::now));
} else {
_aboutRequests.destroy();
}
2020-07-01 14:19:25 +00:00
const auto photo = _session->data().processPhoto(data.vphoto());
if (!photo->isNull()) {
_photo = photo->createMediaView();
_photo->wanted(Data::PhotoSize::Small, Data::FileOrigin());
if (!_photo->image(Data::PhotoSize::Small)) {
_session->downloaderTaskFinished(
) | rpl::start_with_next([=] {
update();
}, lifetime());
}
} else {
_photoEmpty = std::make_unique<Ui::EmptyUserpic>(
Data::PeerUserpicColor(0),
title);
}
}
ConfirmInviteBox::~ConfirmInviteBox() = default;
auto ConfirmInviteBox::GetParticipants(
not_null<Main::Session*> session,
const MTPDchatInvite &data)
-> std::vector<Participant> {
const auto participants = data.vparticipants();
if (!participants) {
return {};
}
const auto &v = participants->v;
auto result = std::vector<Participant>();
result.reserve(v.size());
for (const auto &participant : v) {
if (const auto user = session->data().processUser(participant)) {
result.push_back(Participant{ user });
}
}
return result;
}
void ConfirmInviteBox::prepare() {
addButton(
2021-10-12 12:50:18 +00:00
(_requestApprove
? tr::lng_group_request_to_join()
: _isChannel
2020-07-01 14:19:25 +00:00
? tr::lng_profile_join_channel()
: tr::lng_profile_join_group()),
_submit);
addButton(tr::lng_cancel(), [=] { closeBox(); });
while (_participants.size() > 4) {
_participants.pop_back();
}
auto newHeight = st::confirmInviteStatusTop + _status->height() + st::boxPadding.bottom();
if (!_participants.empty()) {
2021-10-14 13:45:13 +00:00
int skip = (st::confirmInviteUsersWidth - 4 * st::confirmInviteUserPhotoSize) / 5;
2020-07-01 14:19:25 +00:00
int padding = skip / 2;
_userWidth = (st::confirmInviteUserPhotoSize + 2 * padding);
int sumWidth = _participants.size() * _userWidth;
int left = (st::boxWideWidth - sumWidth) / 2;
for (const auto &participant : _participants) {
auto name = new Ui::FlatLabel(this, st::confirmInviteUserName);
name->resizeToWidth(st::confirmInviteUserPhotoSize + padding);
name->setText(participant.user->firstName.isEmpty()
2022-08-09 11:12:19 +00:00
? participant.user->name()
2020-07-01 14:19:25 +00:00
: participant.user->firstName);
name->moveToLeft(left + (padding / 2), st::confirmInviteUserNameTop);
left += _userWidth;
}
newHeight += st::confirmInviteUserHeight;
}
2021-10-14 13:45:13 +00:00
if (_about) {
const auto padding = st::confirmInviteAboutPadding;
_about->resizeToWidth(st::boxWideWidth - padding.left() - padding.right());
newHeight += padding.top() + _about->height() + padding.bottom();
}
if (_aboutRequests) {
const auto padding = st::confirmInviteAboutRequestsPadding;
_aboutRequests->resizeToWidth(st::boxWideWidth - padding.left() - padding.right());
newHeight += padding.top() + _aboutRequests->height() + padding.bottom();
}
2020-07-01 14:19:25 +00:00
setDimensions(st::boxWideWidth, newHeight);
}
void ConfirmInviteBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_title->move((width() - _title->width()) / 2, st::confirmInviteTitleTop);
_status->move((width() - _status->width()) / 2, st::confirmInviteStatusTop);
2021-10-14 13:45:13 +00:00
auto bottom = _status->y()
+ _status->height()
+ st::boxPadding.bottom()
+ (_participants.empty() ? 0 : st::confirmInviteUserHeight);
if (_about) {
const auto padding = st::confirmInviteAboutPadding;
_about->move((width() - _about->width()) / 2, bottom + padding.top());
bottom += padding.top() + _about->height() + padding.bottom();
}
if (_aboutRequests) {
const auto padding = st::confirmInviteAboutRequestsPadding;
_aboutRequests->move((width() - _aboutRequests->width()) / 2, bottom + padding.top());
}
2020-07-01 14:19:25 +00:00
}
void ConfirmInviteBox::paintEvent(QPaintEvent *e) {
BoxContent::paintEvent(e);
Painter p(this);
if (_photo) {
if (const auto image = _photo->image(Data::PhotoSize::Small)) {
const auto size = st::confirmInvitePhotoSize;
2020-07-01 14:19:25 +00:00
p.drawPixmap(
(width() - size) / 2,
2020-07-01 14:19:25 +00:00
st::confirmInvitePhotoTop,
image->pix(
{ size, size },
{ .options = Images::Option::RoundCircle }));
2020-07-01 14:19:25 +00:00
}
} else if (_photoEmpty) {
_photoEmpty->paint(
p,
(width() - st::confirmInvitePhotoSize) / 2,
st::confirmInvitePhotoTop,
width(),
st::confirmInvitePhotoSize);
}
int sumWidth = _participants.size() * _userWidth;
int left = (width() - sumWidth) / 2;
for (auto &participant : _participants) {
participant.user->paintUserpicLeft(
p,
participant.userpic,
left + (_userWidth - st::confirmInviteUserPhotoSize) / 2,
st::confirmInviteUserPhotoTop,
width(),
st::confirmInviteUserPhotoSize);
left += _userWidth;
}
}