mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Update API scheme to layer 115.
This commit is contained in:
parent
9370e87c54
commit
638d4d63c5
17 changed files with 414 additions and 224 deletions
|
@ -190,6 +190,8 @@ PRIVATE
|
|||
api/api_bot.h
|
||||
api/api_chat_filters.cpp
|
||||
api/api_chat_filters.h
|
||||
api/api_chat_invite.cpp
|
||||
api/api_chat_invite.h
|
||||
api/api_common.h
|
||||
api/api_editing.cpp
|
||||
api/api_editing.h
|
||||
|
|
|
@ -1132,6 +1132,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
"lng_group_invite_members#one" = "{count} member, among them:";
|
||||
"lng_group_invite_members#other" = "{count} members, among them:";
|
||||
"lng_channel_invite_private" = "This channel is private.\nPlease join it to continue viewing its content.";
|
||||
|
||||
"lng_group_invite_create" = "Create an invite link";
|
||||
"lng_group_invite_about" = "Telegram users will be able to join\nyour group by following this link.";
|
||||
|
|
|
@ -62,10 +62,9 @@ inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector<
|
|||
inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
|
||||
inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia;
|
||||
inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
|
||||
inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true force_file:flags.4?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
|
||||
inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
|
||||
inputMediaGifExternal#4843b0fd url:string q:string = InputMedia;
|
||||
inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
|
||||
|
@ -529,6 +528,7 @@ chatInviteExported#fc2e05bc link:string = ExportedChatInvite;
|
|||
|
||||
chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
|
||||
chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
|
||||
chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite;
|
||||
|
||||
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
|
||||
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
|
||||
|
@ -619,11 +619,6 @@ channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector
|
|||
|
||||
help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector<MessageEntity> min_age_confirm:flags.1?int = help.TermsOfService;
|
||||
|
||||
foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif;
|
||||
foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif;
|
||||
|
||||
messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.FoundGifs;
|
||||
|
||||
messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs;
|
||||
messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs;
|
||||
|
||||
|
@ -1312,7 +1307,6 @@ messages.migrateChat#15a3b8e3 chat_id:int = Updates;
|
|||
messages.searchGlobal#bf7225a4 flags:# folder_id:flags.0?int q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool;
|
||||
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
|
||||
messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs;
|
||||
messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
|
||||
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
|
||||
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
|
||||
|
@ -1502,4 +1496,4 @@ folders.deleteFolder#1c295881 folder_id:int = Updates;
|
|||
stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
|
||||
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
|
||||
|
||||
// LAYER 114
|
||||
// LAYER 115
|
||||
|
|
230
Telegram/SourceFiles/api/api_chat_invite.cpp
Normal file
230
Telegram/SourceFiles/api/api_chat_invite.cpp
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
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 "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"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
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 box = Ui::show(Box<ConfirmInviteBox>(
|
||||
session,
|
||||
data,
|
||||
invitePeekChannel,
|
||||
[=] { session->api().importChatInvite(hash); }));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}, [=](const RPCError &error) {
|
||||
if (error.code() != 400) {
|
||||
return;
|
||||
}
|
||||
Core::App().hideMediaView();
|
||||
Ui::show(Box<InformBox>(tr::lng_group_invite_bad_link(tr::now)));
|
||||
});
|
||||
}
|
||||
|
||||
} // 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)
|
||||
, _participants(GetParticipants(_session, data))
|
||||
, _isChannel(data.is_channel() && !data.is_megagroup()) {
|
||||
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)
|
||||
? 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);
|
||||
|
||||
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(
|
||||
(_isChannel
|
||||
? 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()) {
|
||||
int skip = (st::boxWideWidth - 4 * st::confirmInviteUserPhotoSize) / 5;
|
||||
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()
|
||||
? participant.user->name
|
||||
: participant.user->firstName);
|
||||
name->moveToLeft(left + (padding / 2), st::confirmInviteUserNameTop);
|
||||
left += _userWidth;
|
||||
}
|
||||
|
||||
newHeight += st::confirmInviteUserHeight;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
void ConfirmInviteBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
|
||||
if (_photo) {
|
||||
if (const auto image = _photo->image(Data::PhotoSize::Small)) {
|
||||
p.drawPixmap(
|
||||
(width() - st::confirmInvitePhotoSize) / 2,
|
||||
st::confirmInvitePhotoTop,
|
||||
image->pixCircled(
|
||||
st::confirmInvitePhotoSize,
|
||||
st::confirmInvitePhotoSize));
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
74
Telegram/SourceFiles/api/api_chat_invite.h
Normal file
74
Telegram/SourceFiles/api/api_chat_invite.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
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/box_content.h"
|
||||
|
||||
class UserData;
|
||||
class ChannelData;
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Data {
|
||||
class CloudImageView;
|
||||
class PhotoMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace Ui {
|
||||
class EmptyUserpic;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Api {
|
||||
|
||||
void CheckChatInvite(
|
||||
not_null<Window::SessionController*> controller,
|
||||
const QString &hash,
|
||||
ChannelData *invitePeekChannel = nullptr);
|
||||
|
||||
} // namespace Api
|
||||
|
||||
class ConfirmInviteBox final : public Ui::BoxContent {
|
||||
public:
|
||||
ConfirmInviteBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDchatInvite &data,
|
||||
ChannelData *invitePeekChannel,
|
||||
Fn<void()> submit);
|
||||
~ConfirmInviteBox();
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
struct Participant {
|
||||
not_null<UserData*> user;
|
||||
std::shared_ptr<Data::CloudImageView> userpic;
|
||||
};
|
||||
static std::vector<Participant> GetParticipants(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDchatInvite &data);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
Fn<void()> _submit;
|
||||
object_ptr<Ui::FlatLabel> _title;
|
||||
object_ptr<Ui::FlatLabel> _status;
|
||||
std::shared_ptr<Data::PhotoMedia> _photo;
|
||||
std::unique_ptr<Ui::EmptyUserpic> _photoEmpty;
|
||||
std::vector<Participant> _participants;
|
||||
bool _isChannel = false;
|
||||
|
||||
int _userWidth = 0;
|
||||
|
||||
};
|
|
@ -1645,7 +1645,7 @@ void ApiWrap::requestSelfParticipant(not_null<ChannelData*> channel) {
|
|||
}).fail([=](const RPCError &error) {
|
||||
_selfParticipantRequests.erase(channel);
|
||||
if (error.type() == qstr("CHANNEL_PRIVATE")) {
|
||||
channel->markForbidden();
|
||||
channel->privateErrorReceived();
|
||||
}
|
||||
finalize(-1, 0);
|
||||
}).afterDelay(kSmallDelayMs).send();
|
||||
|
@ -1962,6 +1962,9 @@ void ApiWrap::joinChannel(not_null<ChannelData*> channel) {
|
|||
applyUpdates(result);
|
||||
}).fail([=](const RPCError &error) {
|
||||
if (error.type() == qstr("CHANNEL_PRIVATE")
|
||||
&& channel->invitePeekExpires()) {
|
||||
channel->privateErrorReceived();
|
||||
} else if (error.type() == qstr("CHANNEL_PRIVATE")
|
||||
|| error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA")
|
||||
|| error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
|
||||
Ui::show(Box<InformBox>(channel->isMegagroup()
|
||||
|
|
|
@ -94,7 +94,6 @@ confirmInviteTitle: FlatLabel(defaultFlatLabel) {
|
|||
confirmInviteStatus: FlatLabel(boxLabel) {
|
||||
align: align(center);
|
||||
minWidth: 320px;
|
||||
maxHeight: 20px;
|
||||
textFg: windowSubTextFg;
|
||||
}
|
||||
confirmInviteTitleTop: 106px;
|
||||
|
|
|
@ -861,146 +861,6 @@ void DeleteMessagesBox::deleteAndClear() {
|
|||
session->data().sendHistoryChangeNotifications();
|
||||
}
|
||||
|
||||
ConfirmInviteBox::ConfirmInviteBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDchatInvite &data,
|
||||
Fn<void()> submit)
|
||||
: _session(session)
|
||||
, _submit(std::move(submit))
|
||||
, _title(this, st::confirmInviteTitle)
|
||||
, _status(this, st::confirmInviteStatus)
|
||||
, _participants(GetParticipants(_session, data))
|
||||
, _isChannel(data.is_channel() && !data.is_megagroup()) {
|
||||
const auto title = qs(data.vtitle());
|
||||
const auto count = data.vparticipants_count().v;
|
||||
const auto status = [&] {
|
||||
return (!_participants.empty() && _participants.size() < count)
|
||||
? tr::lng_group_invite_members(tr::now, lt_count, count)
|
||||
: (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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
(_isChannel
|
||||
? 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()) {
|
||||
int skip = (st::boxWideWidth - 4 * st::confirmInviteUserPhotoSize) / 5;
|
||||
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()
|
||||
? participant.user->name
|
||||
: participant.user->firstName);
|
||||
name->moveToLeft(left + (padding / 2), st::confirmInviteUserNameTop);
|
||||
left += _userWidth;
|
||||
}
|
||||
|
||||
newHeight += st::confirmInviteUserHeight;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
void ConfirmInviteBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
|
||||
if (_photo) {
|
||||
if (const auto image = _photo->image(Data::PhotoSize::Small)) {
|
||||
p.drawPixmap(
|
||||
(width() - st::confirmInvitePhotoSize) / 2,
|
||||
st::confirmInvitePhotoTop,
|
||||
image->pixCircled(
|
||||
st::confirmInvitePhotoSize,
|
||||
st::confirmInvitePhotoSize));
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
ConfirmInviteBox::~ConfirmInviteBox() = default;
|
||||
|
||||
ConfirmDontWarnBox::ConfirmDontWarnBox(
|
||||
QWidget*,
|
||||
rpl::producer<TextWithEntities> text,
|
||||
|
|
|
@ -206,46 +206,6 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class ConfirmInviteBox final
|
||||
: public Ui::BoxContent
|
||||
, private base::Subscriber {
|
||||
public:
|
||||
ConfirmInviteBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDchatInvite &data,
|
||||
Fn<void()> submit);
|
||||
~ConfirmInviteBox();
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
struct Participant {
|
||||
not_null<UserData*> user;
|
||||
std::shared_ptr<Data::CloudImageView> userpic;
|
||||
};
|
||||
static std::vector<Participant> GetParticipants(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDchatInvite &data);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
Fn<void()> _submit;
|
||||
object_ptr<Ui::FlatLabel> _title;
|
||||
object_ptr<Ui::FlatLabel> _status;
|
||||
std::shared_ptr<Data::PhotoMedia> _photo;
|
||||
std::unique_ptr<Ui::EmptyUserpic> _photoEmpty;
|
||||
std::vector<Participant> _participants;
|
||||
bool _isChannel = false;
|
||||
|
||||
int _userWidth = 0;
|
||||
|
||||
};
|
||||
|
||||
class ConfirmDontWarnBox : public Ui::BoxContent {
|
||||
public:
|
||||
ConfirmDontWarnBox(
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/local_url_handlers.h"
|
||||
|
||||
#include "api/api_text_entities.h"
|
||||
#include "api/api_chat_invite.h"
|
||||
#include "base/qthelp_regex.h"
|
||||
#include "base/qthelp_url.h"
|
||||
#include "lang/lang_cloud_manager.h"
|
||||
|
@ -50,31 +51,7 @@ bool JoinGroupByHash(
|
|||
if (!controller) {
|
||||
return false;
|
||||
}
|
||||
const auto hash = match->captured(1);
|
||||
const auto session = &controller->session();
|
||||
const auto weak = base::make_weak(controller);
|
||||
session->api().checkChatInvite(hash, [=](const MTPChatInvite &result) {
|
||||
Core::App().hideMediaView();
|
||||
result.match([=](const MTPDchatInvite &data) {
|
||||
Ui::show(Box<ConfirmInviteBox>(session, data, [=] {
|
||||
session->api().importChatInvite(hash);
|
||||
}));
|
||||
}, [=](const MTPDchatInviteAlready &data) {
|
||||
if (const auto chat = session->data().processChat(data.vchat())) {
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->showPeerHistory(
|
||||
chat,
|
||||
Window::SectionShow::Way::Forward);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, [=](const RPCError &error) {
|
||||
if (error.code() != 400) {
|
||||
return;
|
||||
}
|
||||
Core::App().hideMediaView();
|
||||
Ui::show(Box<InformBox>(tr::lng_group_invite_bad_link(tr::now)));
|
||||
});
|
||||
Api::CheckChatInvite(controller, match->captured(1));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/unixtime.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "api/api_chat_invite.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
namespace {
|
||||
|
@ -632,6 +633,40 @@ void ChannelData::growSlowmodeLastMessage(TimeId when) {
|
|||
session().changes().peerUpdated(this, UpdateFlag::Slowmode);
|
||||
}
|
||||
|
||||
void ChannelData::setInvitePeek(const QString &hash, TimeId expires) {
|
||||
if (!_invitePeek) {
|
||||
_invitePeek = std::make_unique<InvitePeek>();
|
||||
}
|
||||
_invitePeek->hash = hash;
|
||||
_invitePeek->expires = expires;
|
||||
}
|
||||
|
||||
void ChannelData::clearInvitePeek() {
|
||||
_invitePeek = nullptr;
|
||||
}
|
||||
|
||||
TimeId ChannelData::invitePeekExpires() const {
|
||||
return _invitePeek ? _invitePeek->expires : 0;
|
||||
}
|
||||
|
||||
QString ChannelData::invitePeekHash() const {
|
||||
return _invitePeek ? _invitePeek->hash : QString();
|
||||
}
|
||||
|
||||
void ChannelData::privateErrorReceived() {
|
||||
if (const auto expires = invitePeekExpires()) {
|
||||
const auto hash = invitePeekHash();
|
||||
for (const auto window : session().windows()) {
|
||||
clearInvitePeek();
|
||||
Api::CheckChatInvite(window, hash, this);
|
||||
return;
|
||||
}
|
||||
_invitePeek->expires = base::unixtime::now();
|
||||
} else {
|
||||
markForbidden();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Data {
|
||||
|
||||
void ApplyMigration(
|
||||
|
|
|
@ -386,6 +386,12 @@ public:
|
|||
[[nodiscard]] TimeId slowmodeLastMessage() const;
|
||||
void growSlowmodeLastMessage(TimeId when);
|
||||
|
||||
void setInvitePeek(const QString &hash, TimeId expires);
|
||||
void clearInvitePeek();
|
||||
[[nodiscard]] TimeId invitePeekExpires() const;
|
||||
[[nodiscard]] QString invitePeekHash() const;
|
||||
void privateErrorReceived();
|
||||
|
||||
// Still public data members.
|
||||
uint64 access = 0;
|
||||
|
||||
|
@ -401,6 +407,11 @@ public:
|
|||
TimeId inviteDate = 0;
|
||||
|
||||
private:
|
||||
struct InvitePeek {
|
||||
QString hash;
|
||||
TimeId expires = 0;
|
||||
};
|
||||
|
||||
auto unavailableReasons() const
|
||||
-> const std::vector<Data::UnavailableReason> & override;
|
||||
bool canEditLastAdmin(not_null<UserData*> user) const;
|
||||
|
@ -423,6 +434,7 @@ private:
|
|||
TimeId _restrictedUntil;
|
||||
|
||||
std::vector<Data::UnavailableReason> _unavailableReasons;
|
||||
std::unique_ptr<InvitePeek> _invitePeek;
|
||||
QString _inviteLink;
|
||||
ChannelData *_linkedChat = nullptr;
|
||||
|
||||
|
|
|
@ -475,6 +475,11 @@ void PeerData::setPinnedMessageId(MsgId messageId) {
|
|||
}
|
||||
|
||||
bool PeerData::canExportChatHistory() const {
|
||||
if (const auto channel = asChannel()) {
|
||||
if (!channel->amIn() && channel->invitePeekExpires()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto &block : _owner->history(id)->blocks) {
|
||||
for (const auto &message : block->messages) {
|
||||
if (!message->data()->serviceMsg()) {
|
||||
|
|
|
@ -1008,14 +1008,16 @@ void Session::setupChannelLeavingViewer() {
|
|||
PeerUpdate::Flag::ChannelAmIn
|
||||
) | rpl::map([](const PeerUpdate &update) {
|
||||
return update.peer->asChannel();
|
||||
}) | rpl::filter([](not_null<ChannelData*> channel) {
|
||||
return !(channel->amIn());
|
||||
}) | rpl::start_with_next([=](not_null<ChannelData*> channel) {
|
||||
// channel->clearFeed(); // #feed
|
||||
if (const auto history = historyLoaded(channel->id)) {
|
||||
history->removeJoinedMessage();
|
||||
history->updateChatListExistence();
|
||||
history->updateChatListSortPosition();
|
||||
if (channel->amIn()) {
|
||||
channel->clearInvitePeek();
|
||||
} else {
|
||||
// channel->clearFeed(); // #feed
|
||||
if (const auto history = historyLoaded(channel->id)) {
|
||||
history->removeJoinedMessage();
|
||||
history->updateChatListExistence();
|
||||
history->updateChatListSortPosition();
|
||||
}
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
|
|
|
@ -2391,6 +2391,10 @@ void HistoryWidget::unreadCountUpdated() {
|
|||
|
||||
void HistoryWidget::messagesFailed(const RPCError &error, int requestId) {
|
||||
if (error.type() == qstr("CHANNEL_PRIVATE")
|
||||
&& _peer->isChannel()
|
||||
&& _peer->asChannel()->invitePeekExpires()) {
|
||||
_peer->asChannel()->privateErrorReceived();
|
||||
} else if (error.type() == qstr("CHANNEL_PRIVATE")
|
||||
|| error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA")
|
||||
|| error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
|
||||
auto was = _peer;
|
||||
|
|
|
@ -41,6 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_chat_invite.h"
|
||||
#include "support/support_helper.h"
|
||||
#include "facades.h"
|
||||
#include "styles/style_window.h"
|
||||
|
@ -133,7 +134,8 @@ SessionController::SessionController(
|
|||
, _tabbedSelector(
|
||||
std::make_unique<ChatHelpers::TabbedSelector>(
|
||||
_window->widget(),
|
||||
this)) {
|
||||
this))
|
||||
, _invitePeekTimer([=] { checkInvitePeek(); }) {
|
||||
init();
|
||||
|
||||
if (Media::Player::instance()->pauseGifByRoundVideo()) {
|
||||
|
@ -309,6 +311,7 @@ void SessionController::setActiveChatEntry(Dialogs::RowDescriptor row) {
|
|||
const auto now = row.key.history();
|
||||
if (was && was != now) {
|
||||
was->setFakeUnreadWhileOpened(false);
|
||||
_invitePeekTimer.cancel();
|
||||
}
|
||||
_activeChatEntry = row;
|
||||
if (now) {
|
||||
|
@ -317,6 +320,30 @@ void SessionController::setActiveChatEntry(Dialogs::RowDescriptor row) {
|
|||
if (session().supportMode()) {
|
||||
pushToChatEntryHistory(row);
|
||||
}
|
||||
checkInvitePeek();
|
||||
}
|
||||
|
||||
void SessionController::checkInvitePeek() {
|
||||
const auto history = activeChatCurrent().history();
|
||||
if (!history) {
|
||||
return;
|
||||
}
|
||||
const auto channel = history->peer->asChannel();
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
const auto expires = channel->invitePeekExpires();
|
||||
if (!expires) {
|
||||
return;
|
||||
}
|
||||
const auto now = base::unixtime::now();
|
||||
if (expires > now) {
|
||||
_invitePeekTimer.callOnce((expires - now) * crl::time(1000));
|
||||
return;
|
||||
}
|
||||
const auto hash = channel->invitePeekHash();
|
||||
channel->clearInvitePeek();
|
||||
Api::CheckChatInvite(this, hash, channel);
|
||||
}
|
||||
|
||||
void SessionController::resetFakeUnreadWhileOpened() {
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/observer.h"
|
||||
#include "base/object_ptr.h"
|
||||
#include "base/weak_ptr.h"
|
||||
#include "base/timer.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "ui/effects/animation_value.h"
|
||||
|
||||
|
@ -324,6 +325,8 @@ private:
|
|||
bool chatEntryHistoryMove(int steps);
|
||||
void resetFakeUnreadWhileOpened();
|
||||
|
||||
void checkInvitePeek();
|
||||
|
||||
const not_null<Controller*> _window;
|
||||
|
||||
std::unique_ptr<Passport::FormController> _passportForm;
|
||||
|
@ -342,6 +345,8 @@ private:
|
|||
int _chatEntryHistoryPosition = -1;
|
||||
bool _selectingPeer = false;
|
||||
|
||||
base::Timer _invitePeekTimer;
|
||||
|
||||
rpl::variable<FilterId> _activeChatsFilter;
|
||||
|
||||
PeerData *_showEditPeer = nullptr;
|
||||
|
|
Loading…
Add table
Reference in a new issue