Allow sharing link from confcall.

This commit is contained in:
John Preston 2025-03-29 12:52:36 +05:00
parent 0d8e5b139b
commit 9f3f715527
13 changed files with 226 additions and 53 deletions

View file

@ -4755,6 +4755,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_also_end_channel" = "End live stream"; "lng_group_call_also_end_channel" = "End live stream";
"lng_group_call_settings_title" = "Settings"; "lng_group_call_settings_title" = "Settings";
"lng_group_call_invite" = "Invite Members"; "lng_group_call_invite" = "Invite Members";
"lng_group_call_invite_conf" = "Add People";
"lng_group_call_invited_status" = "invited"; "lng_group_call_invited_status" = "invited";
"lng_group_call_muted_by_me_status" = "muted for you"; "lng_group_call_muted_by_me_status" = "muted for you";
"lng_group_call_invite_title" = "Invite members"; "lng_group_call_invite_title" = "Invite members";

View file

@ -804,6 +804,7 @@ groupCallAddMember: SettingsButton(defaultSettingsButton) {
ripple: groupCallRipple; ripple: groupCallRipple;
} }
groupCallAddMemberIcon: icon {{ "info/info_add_member", groupCallMemberInactiveIcon, point(0px, 3px) }}; groupCallAddMemberIcon: icon {{ "info/info_add_member", groupCallMemberInactiveIcon, point(0px, 3px) }};
groupCallShareLinkIcon: icon {{ "menu/links_profile", groupCallMemberInactiveIcon, point(4px, 3px) }};
groupCallSubtitleLabel: FlatLabel(defaultFlatLabel) { groupCallSubtitleLabel: FlatLabel(defaultFlatLabel) {
maxHeight: 18px; maxHeight: 18px;
textFg: groupCallMemberNotJoinedStatus; textFg: groupCallMemberNotJoinedStatus;
@ -1489,12 +1490,15 @@ confcallLinkButton: RoundButton(defaultActiveButton) {
textTop: 12px; textTop: 12px;
style: semiboldTextStyle; style: semiboldTextStyle;
} }
confcallLinkBox: Box(defaultBox) { confcallLinkBoxInitial: Box(defaultBox) {
buttonPadding: margins(12px, 11px, 24px, 96px); buttonPadding: margins(12px, 11px, 24px, 96px);
buttonHeight: 42px; buttonHeight: 42px;
button: confcallLinkButton; button: confcallLinkButton;
shadowIgnoreTopSkip: true; shadowIgnoreTopSkip: true;
} }
confcallLinkBox: Box(confcallLinkBoxInitial) {
buttonPadding: margins(12px, 11px, 24px, 24px);
}
confcallLinkCopyButton: RoundButton(confcallLinkButton) { confcallLinkCopyButton: RoundButton(confcallLinkButton) {
icon: icon {{ "info/edit/links_copy", activeButtonFg }}; icon: icon {{ "info/edit/links_copy", activeButtonFg }};
iconOver: icon {{ "info/edit/links_copy", activeButtonFgOver }}; iconOver: icon {{ "info/edit/links_copy", activeButtonFgOver }};
@ -1516,3 +1520,21 @@ confcallLinkFooterOr: FlatLabel(confcallLinkCenteredText) {
confcallLinkFooterOrTop: 12px; confcallLinkFooterOrTop: 12px;
confcallLinkFooterOrSkip: 8px; confcallLinkFooterOrSkip: 8px;
confcallLinkFooterOrLineTop: 9px; confcallLinkFooterOrLineTop: 9px;
groupCallLinkBox: Box(confcallLinkBox) {
bg: groupCallMembersBg;
title: FlatLabel(boxTitle) {
textFg: groupCallMembersFg;
}
titleAdditionalFg: groupCallMemberNotJoinedStatus;
}
groupCallLinkCenteredText: FlatLabel(confcallLinkCenteredText) {
textFg: groupCallMembersFg;
}
groupCallLinkPreview: InputField(defaultInputField) {
textBg: groupCallMembersBgOver;
textFg: groupCallMembersFg;
textMargins: margins(12px, 8px, 30px, 5px);
style: defaultTextStyle;
heightMin: 35px;
}

View file

@ -1153,13 +1153,17 @@ void GroupCall::setRtmpInfo(const Calls::Group::RtmpInfo &value) {
} }
Data::GroupCall *GroupCall::lookupReal() const { Data::GroupCall *GroupCall::lookupReal() const {
if (_conferenceCall) { if (const auto conference = _conferenceCall.get()) {
return _conferenceCall.get(); return conference;
} }
const auto real = _peer->groupCall(); const auto real = _peer->groupCall();
return (real && real->id() == _id) ? real : nullptr; return (real && real->id() == _id) ? real : nullptr;
} }
std::shared_ptr<Data::GroupCall> GroupCall::conferenceCall() const {
return _conferenceCall;
}
rpl::producer<not_null<Data::GroupCall*>> GroupCall::real() const { rpl::producer<not_null<Data::GroupCall*>> GroupCall::real() const {
if (const auto real = lookupReal()) { if (const auto real = lookupReal()) {
return rpl::single(not_null{ real }); return rpl::single(not_null{ real });

View file

@ -256,6 +256,7 @@ public:
void setRtmpInfo(const Group::RtmpInfo &value); void setRtmpInfo(const Group::RtmpInfo &value);
[[nodiscard]] Data::GroupCall *lookupReal() const; [[nodiscard]] Data::GroupCall *lookupReal() const;
[[nodiscard]] std::shared_ptr<Data::GroupCall> conferenceCall() const;
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const; [[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
[[nodiscard]] rpl::producer<QByteArray> emojiHashValue() const; [[nodiscard]] rpl::producer<QByteArray> emojiHashValue() const;

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "calls/group/calls_group_common.h" #include "calls/group/calls_group_common.h"
#include "apiwrap.h"
#include "base/platform/base_platform_info.h" #include "base/platform/base_platform_info.h"
#include "boxes/share_box.h" #include "boxes/share_box.h"
#include "core/local_url_handlers.h" #include "core/local_url_handlers.h"
@ -19,8 +20,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/vertical_list.h" #include "ui/vertical_list.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_session.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "styles/style_layers.h" #include "styles/style_layers.h"
#include "styles/style_media_view.h"
#include "styles/style_calls.h" #include "styles/style_calls.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
@ -86,16 +89,34 @@ void ConferenceCallJoinConfirm(
}); });
} }
ConferenceCallLinkStyleOverrides DarkConferenceCallLinkStyle() {
return {
.box = &st::groupCallLinkBox,
.close = &st::storiesStealthBoxClose,
.centerLabel = &st::groupCallLinkCenteredText,
.linkPreview = &st::groupCallLinkPreview,
.shareBox = std::make_shared<ShareBoxStyleOverrides>(
DarkShareBoxStyle()),
};
}
void ShowConferenceCallLinkBox( void ShowConferenceCallLinkBox(
not_null<Window::SessionController*> controller, std::shared_ptr<Main::SessionShow> show,
std::shared_ptr<Data::GroupCall> call, std::shared_ptr<Data::GroupCall> call,
const QString &link, const QString &link,
bool initial) { ConferenceCallLinkArgs &&args) {
controller->show(Box([=](not_null<Ui::GenericBox*> box) { const auto st = args.st;
box->setStyle(st::confcallLinkBox); const auto initial = args.initial;
const auto weakWindow = args.weakWindow;
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
box->setStyle(st.box
? *st.box
: initial
? st::confcallLinkBoxInitial
: st::confcallLinkBox);
box->setWidth(st::boxWideWidth); box->setWidth(st::boxWideWidth);
box->setNoContentMargin(true); box->setNoContentMargin(true);
box->addTopButton(st::boxTitleClose, [=] { box->addTopButton(st.close ? *st.close : st::boxTitleClose, [=] {
box->closeBox(); box->closeBox();
}); });
@ -108,19 +129,24 @@ void ShowConferenceCallLinkBox(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
box, box,
tr::lng_confcall_link_title(), tr::lng_confcall_link_title(),
st::boxTitle)), st.box ? st.box->title : st::boxTitle)),
st::boxRowPadding + st::confcallLinkTitlePadding); st::boxRowPadding + st::confcallLinkTitlePadding);
box->addRow( box->addRow(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
box, box,
tr::lng_confcall_link_about(), tr::lng_confcall_link_about(),
st::confcallLinkCenteredText), (st.centerLabel
? *st.centerLabel
: st::confcallLinkCenteredText)),
st::boxRowPadding st::boxRowPadding
)->setTryMakeSimilarLines(true); )->setTryMakeSimilarLines(true);
Ui::AddSkip(box->verticalLayout(), st::defaultVerticalListSkip * 2); Ui::AddSkip(box->verticalLayout(), st::defaultVerticalListSkip * 2);
const auto preview = box->addRow( const auto preview = box->addRow(
Info::BotStarRef::MakeLinkLabel(box, link)); Info::BotStarRef::MakeLinkLabel(
box,
link,
st.linkPreview));
Ui::AddSkip(box->verticalLayout()); Ui::AddSkip(box->verticalLayout());
const auto copyCallback = [=] { const auto copyCallback = [=] {
@ -128,7 +154,10 @@ void ShowConferenceCallLinkBox(
box->uiShow()->showToast(tr::lng_username_copied(tr::now)); box->uiShow()->showToast(tr::lng_username_copied(tr::now));
}; };
const auto shareCallback = [=] { const auto shareCallback = [=] {
FastShareLink(controller, link); FastShareLink(
show,
link,
st.shareBox ? *st.shareBox : ShareBoxStyleOverrides());
}; };
preview->setClickedCallback(copyCallback); preview->setClickedCallback(copyCallback);
[[maybe_unused]] const auto share = box->addButton( [[maybe_unused]] const auto share = box->addButton(
@ -155,6 +184,10 @@ void ShowConferenceCallLinkBox(
share->moveToRight(padding.right(), share->y(), width); share->moveToRight(padding.right(), share->y(), width);
}, box->lifetime()); }, box->lifetime());
if (!initial) {
return;
}
const auto sep = Ui::CreateChild<Ui::FlatLabel>( const auto sep = Ui::CreateChild<Ui::FlatLabel>(
copy->parentWidget(), copy->parentWidget(),
tr::lng_confcall_link_or(), tr::lng_confcall_link_or(),
@ -180,14 +213,18 @@ void ShowConferenceCallLinkBox(
rpl::single(Ui::Text::IconEmoji(&st::textMoreIconEmoji)), rpl::single(Ui::Text::IconEmoji(&st::textMoreIconEmoji)),
[](QString v) { return Ui::Text::Link(v); }), [](QString v) { return Ui::Text::Link(v); }),
Ui::Text::WithEntities), Ui::Text::WithEntities),
st::confcallLinkCenteredText); (st.centerLabel
? *st.centerLabel
: st::confcallLinkCenteredText));
footer->setTryMakeSimilarLines(true); footer->setTryMakeSimilarLines(true);
footer->setClickHandlerFilter([=](const auto &...) { footer->setClickHandlerFilter([=](const auto &...) {
const auto local = Core::TryConvertUrlToLocal(link); const auto local = Core::TryConvertUrlToLocal(link);
controller->resolveConferenceCall( if (const auto controller = weakWindow.get()) {
local, controller->resolveConferenceCall(
crl::guard(box, [=](bool ok) { if (ok) box->closeBox(); }), local,
true); crl::guard(box, [=](bool ok) { if (ok) box->closeBox(); }),
true);
}
return false; return false;
}); });
copy->geometryValue() | rpl::start_with_next([=](QRect geometry) { copy->geometryValue() | rpl::start_with_next([=](QRect geometry) {
@ -209,4 +246,33 @@ void ShowConferenceCallLinkBox(
})); }));
} }
void ExportConferenceCallLink(
std::shared_ptr<Main::SessionShow> show,
std::shared_ptr<Data::GroupCall> call,
ConferenceCallLinkArgs &&args) {
const auto session = &show->session();
const auto finished = std::move(args.finished);
using Flag = MTPphone_ExportGroupCallInvite::Flag;
session->api().request(MTPphone_ExportGroupCallInvite(
MTP_flags(Flag::f_can_self_unmute),
call->input()
)).done([=](const MTPphone_ExportedGroupCallInvite &result) {
const auto link = qs(result.data().vlink());
Calls::Group::ShowConferenceCallLinkBox(
show,
call,
link,
base::duplicate(args));
if (const auto onstack = finished) {
finished(true);
}
}).fail([=](const MTP::Error &error) {
show->showToast(error.type());
if (const auto onstack = finished) {
finished(false);
}
}).send();
}
} // namespace Calls::Group } // namespace Calls::Group

View file

@ -8,13 +8,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "base/object_ptr.h" #include "base/object_ptr.h"
#include "base/weak_ptr.h"
class UserData; class UserData;
struct ShareBoxStyleOverrides;
namespace style {
struct Box;
struct FlatLabel;
struct IconButton;
struct InputField;
} // namespace style
namespace Data { namespace Data {
class GroupCall; class GroupCall;
} // namespace Data } // namespace Data
namespace Main {
class SessionShow;
} // namespace Main
namespace Ui { namespace Ui {
class Show; class Show;
class GenericBox; class GenericBox;
@ -118,10 +131,30 @@ void ConferenceCallJoinConfirm(
std::shared_ptr<Data::GroupCall> call, std::shared_ptr<Data::GroupCall> call,
Fn<void()> join); Fn<void()> join);
struct ConferenceCallLinkStyleOverrides {
const style::Box *box = nullptr;
const style::IconButton *close = nullptr;
const style::FlatLabel *centerLabel = nullptr;
const style::InputField *linkPreview = nullptr;
std::shared_ptr<ShareBoxStyleOverrides> shareBox;
};
[[nodiscard]] ConferenceCallLinkStyleOverrides DarkConferenceCallLinkStyle();
struct ConferenceCallLinkArgs {
bool initial = false;
Fn<void(bool)> finished;
base::weak_ptr<Window::SessionController> weakWindow = nullptr;
ConferenceCallLinkStyleOverrides st;
};
void ShowConferenceCallLinkBox( void ShowConferenceCallLinkBox(
not_null<Window::SessionController*> controller, std::shared_ptr<Main::SessionShow> show,
std::shared_ptr<Data::GroupCall> call, std::shared_ptr<Data::GroupCall> call,
const QString &link, const QString &link,
bool initial = false); ConferenceCallLinkArgs &&args);
void ExportConferenceCallLink(
std::shared_ptr<Main::SessionShow> show,
std::shared_ptr<Data::GroupCall> call,
ConferenceCallLinkArgs &&args);
} // namespace Calls::Group } // namespace Calls::Group

View file

@ -1615,6 +1615,7 @@ rpl::producer<int> Members::desiredHeightValue() const {
return rpl::combine( return rpl::combine(
heightValue(), heightValue(),
_addMemberButton.value(), _addMemberButton.value(),
_shareLinkButton.value(),
_listController->fullCountValue(), _listController->fullCountValue(),
_mode.value() _mode.value()
) | rpl::map([=] { ) | rpl::map([=] {
@ -1626,8 +1627,11 @@ void Members::setupAddMember(not_null<GroupCall*> call) {
using namespace rpl::mappers; using namespace rpl::mappers;
const auto peer = call->peer(); const auto peer = call->peer();
const auto conference = call->conference();
const auto canAddByPeer = [=](not_null<PeerData*> peer) { const auto canAddByPeer = [=](not_null<PeerData*> peer) {
if (peer->isBroadcast()) { if (conference) {
return rpl::single(true) | rpl::type_erased();
} else if (peer->isBroadcast()) {
return rpl::single(false) | rpl::type_erased(); return rpl::single(false) | rpl::type_erased();
} }
return rpl::combine( return rpl::combine(
@ -1638,6 +1642,9 @@ void Members::setupAddMember(not_null<GroupCall*> call) {
}) | rpl::type_erased(); }) | rpl::type_erased();
}; };
const auto canInviteByLinkByPeer = [=](not_null<PeerData*> peer) { const auto canInviteByLinkByPeer = [=](not_null<PeerData*> peer) {
if (conference) {
return rpl::single(true) | rpl::type_erased();
}
const auto channel = peer->asChannel(); const auto channel = peer->asChannel();
if (!channel) { if (!channel) {
return rpl::single(false) | rpl::type_erased(); return rpl::single(false) | rpl::type_erased();
@ -1672,11 +1679,18 @@ void Members::setupAddMember(not_null<GroupCall*> call) {
_addMemberButton = nullptr; _addMemberButton = nullptr;
updateControlsGeometry(); updateControlsGeometry();
} }
if (const auto old = _shareLinkButton.current()) {
delete old;
_shareLinkButton = nullptr;
updateControlsGeometry();
}
return; return;
} }
auto addMember = Settings::CreateButtonWithIcon( auto addMember = Settings::CreateButtonWithIcon(
_layout.get(), _layout.get(),
tr::lng_group_call_invite(), (conference
? tr::lng_group_call_invite_conf()
: tr::lng_group_call_invite()),
st::groupCallAddMember, st::groupCallAddMember,
{ .icon = &st::groupCallAddMemberIcon }); { .icon = &st::groupCallAddMemberIcon });
addMember->clicks( addMember->clicks(
@ -1688,6 +1702,21 @@ void Members::setupAddMember(not_null<GroupCall*> call) {
delete _addMemberButton.current(); delete _addMemberButton.current();
_addMemberButton = addMember.data(); _addMemberButton = addMember.data();
_layout->insert(3, std::move(addMember)); _layout->insert(3, std::move(addMember));
if (conference) {
auto shareLink = Settings::CreateButtonWithIcon(
_layout.get(),
tr::lng_group_invite_share(),
st::groupCallAddMember,
{ .icon = &st::groupCallShareLinkIcon });
shareLink->clicks() | rpl::to_empty | rpl::start_to_stream(
_shareLinkRequests,
shareLink->lifetime());
shareLink->show();
shareLink->resizeToWidth(_layout->width());
delete _shareLinkButton.current();
_shareLinkButton = shareLink.data();
_layout->insert(4, std::move(shareLink));
}
}, lifetime()); }, lifetime());
updateControlsGeometry(); updateControlsGeometry();

View file

@ -59,6 +59,9 @@ public:
[[nodiscard]] rpl::producer<> addMembersRequests() const { [[nodiscard]] rpl::producer<> addMembersRequests() const {
return _addMemberRequests.events(); return _addMemberRequests.events();
} }
[[nodiscard]] rpl::producer<> shareLinkRequests() const {
return _shareLinkRequests.events();
}
[[nodiscard]] MembersRow *lookupRow(not_null<PeerData*> peer) const; [[nodiscard]] MembersRow *lookupRow(not_null<PeerData*> peer) const;
[[nodiscard]] not_null<MembersRow*> rtmpFakeRow( [[nodiscard]] not_null<MembersRow*> rtmpFakeRow(
@ -106,10 +109,12 @@ private:
const not_null<Ui::RpWidget*> _videoWrap; const not_null<Ui::RpWidget*> _videoWrap;
std::unique_ptr<Viewport> _viewport; std::unique_ptr<Viewport> _viewport;
rpl::variable<Ui::RpWidget*> _addMemberButton = nullptr; rpl::variable<Ui::RpWidget*> _addMemberButton = nullptr;
rpl::variable<Ui::RpWidget*> _shareLinkButton = nullptr;
RpWidget *_topSkip = nullptr; RpWidget *_topSkip = nullptr;
RpWidget *_bottomSkip = nullptr; RpWidget *_bottomSkip = nullptr;
ListWidget *_list = nullptr; ListWidget *_list = nullptr;
rpl::event_stream<> _addMemberRequests; rpl::event_stream<> _addMemberRequests;
rpl::event_stream<> _shareLinkRequests;
mutable std::unique_ptr<MembersRow> _rtmpFakeRow; mutable std::unique_ptr<MembersRow> _rtmpFakeRow;

View file

@ -934,16 +934,12 @@ void Panel::setupMembers() {
_members->toggleMuteRequests( _members->toggleMuteRequests(
) | rpl::start_with_next([=](MuteRequest request) { ) | rpl::start_with_next([=](MuteRequest request) {
if (_call) { _call->toggleMute(request);
_call->toggleMute(request);
}
}, _callLifetime); }, _callLifetime);
_members->changeVolumeRequests( _members->changeVolumeRequests(
) | rpl::start_with_next([=](VolumeRequest request) { ) | rpl::start_with_next([=](VolumeRequest request) {
if (_call) { _call->changeVolume(request);
_call->changeVolume(request);
}
}, _callLifetime); }, _callLifetime);
_members->kickParticipantRequests( _members->kickParticipantRequests(
@ -964,6 +960,21 @@ void Panel::setupMembers() {
} }
}, _callLifetime); }, _callLifetime);
const auto exporting = std::make_shared<bool>();
_members->shareLinkRequests(
) | rpl::start_with_next([=] {
Expects(_call->conference());
if (*exporting) {
return;
}
*exporting = true;
ExportConferenceCallLink(uiShow(), _call->conferenceCall(), {
.st = DarkConferenceCallLinkStyle(),
.finished = [=](bool) { *exporting = false; },
});
}, _callLifetime);
_call->videoEndpointLargeValue( _call->videoEndpointLargeValue(
) | rpl::start_with_next([=](const VideoEndpoint &large) { ) | rpl::start_with_next([=](const VideoEndpoint &large) {
if (large && mode() != PanelMode::Wide) { if (large && mode() != PanelMode::Wide) {

View file

@ -390,14 +390,16 @@ void AddFullWidthButtonFooter(
object_ptr<Ui::AbstractButton> MakeLinkLabel( object_ptr<Ui::AbstractButton> MakeLinkLabel(
not_null<QWidget*> parent, not_null<QWidget*> parent,
const QString &link) { const QString &link,
const style::InputField *stOverride) {
const auto &st = stOverride ? *stOverride : st::dialogsFilter;
const auto text = link.startsWith(u"https://"_q) const auto text = link.startsWith(u"https://"_q)
? link.mid(8) ? link.mid(8)
: link.startsWith(u"http://"_q) : link.startsWith(u"http://"_q)
? link.mid(7) ? link.mid(7)
: link; : link;
const auto margins = st::dialogsFilter.textMargins; const auto margins = st.textMargins;
const auto height = st::dialogsFilter.heightMin; const auto height = st.heightMin;
const auto skip = margins.left(); const auto skip = margins.left();
auto result = object_ptr<Ui::AbstractButton>(parent); auto result = object_ptr<Ui::AbstractButton>(parent);
@ -408,12 +410,12 @@ object_ptr<Ui::AbstractButton> MakeLinkLabel(
auto p = QPainter(raw); auto p = QPainter(raw);
auto hq = PainterHighQualityEnabler(p); auto hq = PainterHighQualityEnabler(p);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(st::dialogsFilter.textBg); p.setBrush(st.textBg);
const auto radius = st::roundRadiusLarge; const auto radius = st::roundRadiusLarge;
p.drawRoundedRect(0, 0, raw->width(), height, radius, radius); p.drawRoundedRect(0, 0, raw->width(), height, radius, radius);
const auto font = st::dialogsFilter.style.font; const auto font = st.style.font;
p.setPen(st::dialogsFilter.textFg); p.setPen(st.textFg);
p.setFont(font); p.setFont(font);
const auto available = raw->width() - skip * 2; const auto available = raw->width() - skip * 2;
p.drawText( p.drawText(
@ -1065,4 +1067,4 @@ object_ptr<Ui::RpWidget> CreateLinkHeaderIcon(
return CreateLinkIcon(parent, session, usersCount); return CreateLinkIcon(parent, session, usersCount);
} }
} // namespace Info::BotStarRef } // namespace Info::BotStarRef

View file

@ -21,6 +21,7 @@ class Show;
namespace style { namespace style {
struct RoundButton; struct RoundButton;
struct InputField;
} // namespace style } // namespace style
namespace Main { namespace Main {
@ -107,7 +108,8 @@ void FinishProgram(
[[nodiscard]] object_ptr<Ui::AbstractButton> MakeLinkLabel( [[nodiscard]] object_ptr<Ui::AbstractButton> MakeLinkLabel(
not_null<QWidget*> parent, not_null<QWidget*> parent,
const QString &link); const QString &link,
const style::InputField *stOverride = nullptr);
[[nodiscard]] object_ptr<Ui::RpWidget> CreateLinkHeaderIcon( [[nodiscard]] object_ptr<Ui::RpWidget> CreateLinkHeaderIcon(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Main::Session*> session, not_null<Main::Session*> session,

View file

@ -259,3 +259,6 @@ darkGiftTableMessage: FlatLabel(giveawayGiftMessage) {
textFg: groupCallMembersFg; textFg: groupCallMembersFg;
palette: darkGiftPalette; palette: darkGiftPalette;
} }
darkGiftCodeLink: FlatLabel(giveawayGiftCodeLink) {
textFg: mediaviewMenuFg;
}

View file

@ -123,7 +123,7 @@ constexpr auto kPlayStatusLimit = 2;
(height - st::inviteViaLinkIcon.height()) / 2); (height - st::inviteViaLinkIcon.height()) / 2);
}, icon->lifetime()); }, icon->lifetime());
const auto creating = result->lifetime().make_state<int32>(); const auto creating = std::make_shared<int32>();
result->setClickedCallback([=] { result->setClickedCallback([=] {
if (*creating) { if (*creating) {
return; return;
@ -143,25 +143,19 @@ constexpr auto kPlayStatusLimit = 2;
false, // rtmp false, // rtmp
true); // conference true); // conference
call->processFullCall(result); call->processFullCall(result);
using Flag = MTPphone_ExportGroupCallInvite::Flag; const auto finished = [=](bool ok) {
session->api().request(MTPphone_ExportGroupCallInvite( if (!ok) {
MTP_flags(Flag::f_can_self_unmute), *creating = 0;
MTP_inputGroupCall(data.vid(), data.vaccess_hash()) } else if (const auto onstack = done) {
)).done(crl::guard(controller, [=](
const MTPphone_ExportedGroupCallInvite &result) {
const auto link = qs(result.data().vlink());
Calls::Group::ShowConferenceCallLinkBox(
controller,
call,
link,
true);
if (const auto onstack = done) {
onstack(); onstack();
} }
})).fail(crl::guard(controller, [=](const MTP::Error &error) { };
show->showToast(error.type()); const auto show = controller->uiShow();
*creating = 0; Calls::Group::ExportConferenceCallLink(show, call, {
})).send(); .initial = true,
.finished = finished,
.weakWindow = controller,
});
}); });
})).fail(crl::guard(controller, [=](const MTP::Error &error) { })).fail(crl::guard(controller, [=](const MTP::Error &error) {
show->showToast(error.type()); show->showToast(error.type());