mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 15:43:55 +02:00
Implement "Create New Call" interface.
This commit is contained in:
parent
042f51e58f
commit
c6b2967da0
12 changed files with 375 additions and 227 deletions
|
@ -4932,6 +4932,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_confcall_already_joined_many#one" = "{user}, {other} and **{count}** other person already joined this call.";
|
"lng_confcall_already_joined_many#one" = "{user}, {other} and **{count}** other person already joined this call.";
|
||||||
"lng_confcall_already_joined_many#other" = "{user}, {other} and **{count}** other people already joined this call.";
|
"lng_confcall_already_joined_many#other" = "{user}, {other} and **{count}** other people already joined this call.";
|
||||||
"lng_confcall_join_button" = "Join Group Call";
|
"lng_confcall_join_button" = "Join Group Call";
|
||||||
|
"lng_confcall_create_call" = "Create New Call";
|
||||||
|
"lng_confcall_create_call_description#one" = "You can add up to {count} participant to a call.";
|
||||||
|
"lng_confcall_create_call_description#other" = "You can add up to {count} participants to a call.";
|
||||||
|
"lng_confcall_create_title" = "New Call";
|
||||||
"lng_confcall_create_link" = "Create Call Link";
|
"lng_confcall_create_link" = "Create Call Link";
|
||||||
"lng_confcall_create_link_description" = "You can create a link that will allow your friends on Telegram to join the call.";
|
"lng_confcall_create_link_description" = "You can create a link that will allow your friends on Telegram to join the call.";
|
||||||
"lng_confcall_link_revoke" = "Revoke link";
|
"lng_confcall_link_revoke" = "Revoke link";
|
||||||
|
|
|
@ -1505,6 +1505,42 @@ groupCallCalendarColors: CalendarColors {
|
||||||
titleTextColor: groupCallMembersFg;
|
titleTextColor: groupCallMembersFg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createCallInviteLink: SettingsButton(defaultSettingsButton) {
|
||||||
|
textFg: windowActiveTextFg;
|
||||||
|
textFgOver: windowActiveTextFg;
|
||||||
|
textBg: windowBg;
|
||||||
|
textBgOver: windowBgOver;
|
||||||
|
|
||||||
|
style: TextStyle(defaultTextStyle) {
|
||||||
|
font: font(14px semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
height: 20px;
|
||||||
|
padding: margins(74px, 8px, 8px, 9px);
|
||||||
|
}
|
||||||
|
createCallInviteLinkIcon: icon {{ "info/edit/group_manage_links", windowActiveTextFg }};
|
||||||
|
createCallInviteLinkIconPosition: point(23px, 2px);
|
||||||
|
createCallVideo: IconButton {
|
||||||
|
width: 36px;
|
||||||
|
height: 52px;
|
||||||
|
|
||||||
|
icon: icon {{ "info/info_media_video", menuIconFg }};
|
||||||
|
iconOver: icon {{ "info/info_media_video", menuIconFgOver }};
|
||||||
|
iconPosition: point(-1px, -1px);
|
||||||
|
|
||||||
|
ripple: defaultRippleAnimation;
|
||||||
|
rippleAreaPosition: point(0px, 8px);
|
||||||
|
rippleAreaSize: 36px;
|
||||||
|
}
|
||||||
|
createCallVideoActive: icon {{ "info/info_media_video", windowActiveTextFg }};
|
||||||
|
createCallVideoMargins: margins(0px, 0px, 10px, 0px);
|
||||||
|
createCallAudio: IconButton(createCallVideo) {
|
||||||
|
icon: icon {{ "menu/phone", menuIconFg }};
|
||||||
|
iconOver: icon {{ "menu/phone", menuIconFgOver }};
|
||||||
|
}
|
||||||
|
createCallAudioActive: icon {{ "menu/phone", windowActiveTextFg }};
|
||||||
|
createCallAudioMargins: margins(0px, 0px, 4px, 0px);
|
||||||
|
|
||||||
confcallLinkButton: RoundButton(defaultActiveButton) {
|
confcallLinkButton: RoundButton(defaultActiveButton) {
|
||||||
height: 42px;
|
height: 42px;
|
||||||
textTop: 12px;
|
textTop: 12px;
|
||||||
|
@ -1572,26 +1608,17 @@ confcallInviteParticipants: FlatLabel(defaultFlatLabel) {
|
||||||
textFg: callNameFg;
|
textFg: callNameFg;
|
||||||
}
|
}
|
||||||
confcallInviteParticipantsPadding: margins(8px, 3px, 12px, 2px);
|
confcallInviteParticipantsPadding: margins(8px, 3px, 12px, 2px);
|
||||||
confcallInviteVideo: IconButton {
|
confcallInviteVideo: IconButton(createCallVideo) {
|
||||||
width: 36px;
|
|
||||||
height: 52px;
|
|
||||||
|
|
||||||
icon: icon {{ "info/info_media_video", groupCallMemberInactiveIcon }};
|
icon: icon {{ "info/info_media_video", groupCallMemberInactiveIcon }};
|
||||||
iconOver: icon {{ "info/info_media_video", groupCallMemberInactiveIcon }};
|
iconOver: icon {{ "info/info_media_video", groupCallMemberInactiveIcon }};
|
||||||
iconPosition: point(-1px, -1px);
|
|
||||||
|
|
||||||
ripple: groupCallRipple;
|
ripple: groupCallRipple;
|
||||||
rippleAreaPosition: point(0px, 8px);
|
|
||||||
rippleAreaSize: 36px;
|
|
||||||
}
|
}
|
||||||
confcallInviteVideoActive: icon {{ "info/info_media_video", groupCallActiveFg }};
|
confcallInviteVideoActive: icon {{ "info/info_media_video", groupCallActiveFg }};
|
||||||
confcallInviteVideoMargins: margins(0px, 0px, 10px, 0px);
|
|
||||||
confcallInviteAudio: IconButton(confcallInviteVideo) {
|
confcallInviteAudio: IconButton(confcallInviteVideo) {
|
||||||
icon: icon {{ "menu/phone", groupCallMemberInactiveIcon }};
|
icon: icon {{ "menu/phone", groupCallMemberInactiveIcon }};
|
||||||
iconOver: icon {{ "menu/phone", groupCallMemberInactiveIcon }};
|
iconOver: icon {{ "menu/phone", groupCallMemberInactiveIcon }};
|
||||||
}
|
}
|
||||||
confcallInviteAudioActive: icon {{ "menu/phone", groupCallActiveFg }};
|
confcallInviteAudioActive: icon {{ "menu/phone", groupCallActiveFg }};
|
||||||
confcallInviteAudioMargins: margins(0px, 0px, 4px, 0px);
|
|
||||||
|
|
||||||
groupCallLinkBox: Box(confcallLinkBox) {
|
groupCallLinkBox: Box(confcallLinkBox) {
|
||||||
bg: groupCallMembersBg;
|
bg: groupCallMembersBg;
|
||||||
|
@ -1610,23 +1637,17 @@ groupCallLinkPreview: InputField(defaultInputField) {
|
||||||
style: defaultTextStyle;
|
style: defaultTextStyle;
|
||||||
heightMin: 35px;
|
heightMin: 35px;
|
||||||
}
|
}
|
||||||
groupCallInviteLink: SettingsButton(defaultSettingsButton) {
|
groupCallInviteLink: SettingsButton(createCallInviteLink) {
|
||||||
textFg: mediaviewTextLinkFg;
|
textFg: mediaviewTextLinkFg;
|
||||||
textFgOver: mediaviewTextLinkFg;
|
textFgOver: mediaviewTextLinkFg;
|
||||||
textBg: groupCallMembersBg;
|
textBg: groupCallMembersBg;
|
||||||
textBgOver: groupCallMembersBgOver;
|
textBgOver: groupCallMembersBgOver;
|
||||||
|
|
||||||
style: TextStyle(defaultTextStyle) {
|
|
||||||
font: font(14px semibold);
|
|
||||||
}
|
|
||||||
|
|
||||||
height: 20px;
|
|
||||||
padding: margins(63px, 8px, 8px, 9px);
|
padding: margins(63px, 8px, 8px, 9px);
|
||||||
|
|
||||||
ripple: groupCallRipple;
|
ripple: groupCallRipple;
|
||||||
}
|
}
|
||||||
groupCallInviteLinkIcon: icon {{ "info/edit/group_manage_links", mediaviewTextLinkFg }};
|
groupCallInviteLinkIcon: icon {{ "info/edit/group_manage_links", mediaviewTextLinkFg }};
|
||||||
groupCallInviteLinkIconPosition: point(23px, 2px);
|
|
||||||
|
|
||||||
confcallLinkMenu: IconButton(boxTitleClose) {
|
confcallLinkMenu: IconButton(boxTitleClose) {
|
||||||
icon: icon {{ "title_menu_dots", boxTitleCloseFg }};
|
icon: icon {{ "title_menu_dots", boxTitleCloseFg }};
|
||||||
|
|
|
@ -9,17 +9,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "ui/effects/ripple_animation.h"
|
#include "ui/effects/ripple_animation.h"
|
||||||
|
#include "ui/layers/generic_box.h"
|
||||||
|
#include "ui/text/text_utilities.h"
|
||||||
|
#include "ui/widgets/menu/menu_add_action_callback.h"
|
||||||
|
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
#include "ui/vertical_list.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
|
#include "calls/group/calls_group_common.h"
|
||||||
|
#include "calls/group/calls_group_invite_controller.h"
|
||||||
#include "calls/calls_instance.h"
|
#include "calls/calls_instance.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "history/history_item_helpers.h"
|
#include "history/history_item_helpers.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
|
#include "main/main_app_config.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
@ -32,6 +41,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "api/api_updates.h"
|
#include "api/api_updates.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
#include "info/profile/info_profile_icon.h"
|
||||||
|
#include "settings/settings_calls.h"
|
||||||
|
#include "styles/style_info.h" // infoTopBarMenu
|
||||||
#include "styles/style_layers.h" // st::boxLabel.
|
#include "styles/style_layers.h" // st::boxLabel.
|
||||||
#include "styles/style_calls.h"
|
#include "styles/style_calls.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
@ -150,7 +162,7 @@ void GroupCallRow::rightActionStopLastRipple() {
|
||||||
|
|
||||||
namespace GroupCalls {
|
namespace GroupCalls {
|
||||||
|
|
||||||
ListController::ListController(not_null<Window::SessionController*> window)
|
ListController::ListController(not_null<::Window::SessionController*> window)
|
||||||
: _window(window) {
|
: _window(window) {
|
||||||
setStyleOverrides(&st::peerListSingleRow);
|
setStyleOverrides(&st::peerListSingleRow);
|
||||||
}
|
}
|
||||||
|
@ -227,7 +239,7 @@ void ListController::rowClicked(not_null<PeerListRow*> row) {
|
||||||
crl::on_main(window, [=, peer = row->peer()] {
|
crl::on_main(window, [=, peer = row->peer()] {
|
||||||
window->showPeerHistory(
|
window->showPeerHistory(
|
||||||
peer,
|
peer,
|
||||||
Window::SectionShow::Way::ClearStack);
|
::Window::SectionShow::Way::ClearStack);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,7 +482,7 @@ void BoxController::Row::rightActionStopLastRipple() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxController::BoxController(not_null<Window::SessionController*> window)
|
BoxController::BoxController(not_null<::Window::SessionController*> window)
|
||||||
: _window(window)
|
: _window(window)
|
||||||
, _api(&_window->session().mtp()) {
|
, _api(&_window->session().mtp()) {
|
||||||
}
|
}
|
||||||
|
@ -591,7 +603,7 @@ void BoxController::rowClicked(not_null<PeerListRow*> row) {
|
||||||
crl::on_main(window, [=, peer = row->peer()] {
|
crl::on_main(window, [=, peer = row->peer()] {
|
||||||
window->showPeerHistory(
|
window->showPeerHistory(
|
||||||
peer,
|
peer,
|
||||||
Window::SectionShow::Way::ClearStack,
|
::Window::SectionShow::Way::ClearStack,
|
||||||
itemId);
|
itemId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -698,7 +710,7 @@ std::unique_ptr<PeerListRow> BoxController::createRow(
|
||||||
|
|
||||||
void ClearCallsBox(
|
void ClearCallsBox(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
not_null<Window::SessionController*> window) {
|
not_null<::Window::SessionController*> window) {
|
||||||
const auto weak = Ui::MakeWeak(box);
|
const auto weak = Ui::MakeWeak(box);
|
||||||
box->addRow(
|
box->addRow(
|
||||||
object_ptr<Ui::FlatLabel>(
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
@ -756,4 +768,133 @@ void ClearCallsBox(
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] not_null<Ui::SettingsButton*> AddCreateCallButton(
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
not_null<::Window::SessionController*> controller,
|
||||||
|
Fn<void()> done) {
|
||||||
|
const auto result = container->add(object_ptr<Ui::SettingsButton>(
|
||||||
|
container,
|
||||||
|
tr::lng_confcall_create_call(),
|
||||||
|
st::inviteViaLinkButton), QMargins());
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
Ui::AddDividerText(
|
||||||
|
container,
|
||||||
|
tr::lng_confcall_create_call_description(
|
||||||
|
lt_count,
|
||||||
|
rpl::single(controller->session().appConfig().confcallSizeLimit()
|
||||||
|
* 1.),
|
||||||
|
Ui::Text::WithEntities));
|
||||||
|
|
||||||
|
const auto icon = Ui::CreateChild<Info::Profile::FloatingIcon>(
|
||||||
|
result,
|
||||||
|
st::inviteViaLinkIcon,
|
||||||
|
QPoint());
|
||||||
|
result->heightValue(
|
||||||
|
) | rpl::start_with_next([=](int height) {
|
||||||
|
icon->moveToLeft(
|
||||||
|
st::inviteViaLinkIconPosition.x(),
|
||||||
|
(height - st::inviteViaLinkIcon.height()) / 2);
|
||||||
|
}, icon->lifetime());
|
||||||
|
|
||||||
|
result->setClickedCallback([=] {
|
||||||
|
controller->show(Group::PrepareCreateCallBox(controller, done));
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowCallsBox(not_null<::Window::SessionController*> window) {
|
||||||
|
struct State {
|
||||||
|
State(not_null<::Window::SessionController*> window)
|
||||||
|
: callsController(window)
|
||||||
|
, groupCallsController(window) {
|
||||||
|
}
|
||||||
|
Calls::BoxController callsController;
|
||||||
|
PeerListContentDelegateSimple callsDelegate;
|
||||||
|
|
||||||
|
Calls::GroupCalls::ListController groupCallsController;
|
||||||
|
PeerListContentDelegateSimple groupCallsDelegate;
|
||||||
|
|
||||||
|
base::unique_qptr<Ui::PopupMenu> menu;
|
||||||
|
};
|
||||||
|
|
||||||
|
window->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||||
|
const auto state = box->lifetime().make_state<State>(window);
|
||||||
|
|
||||||
|
const auto groupCalls = box->addRow(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
box,
|
||||||
|
object_ptr<Ui::VerticalLayout>(box)),
|
||||||
|
{});
|
||||||
|
groupCalls->hide(anim::type::instant);
|
||||||
|
groupCalls->toggleOn(state->groupCallsController.shownValue());
|
||||||
|
|
||||||
|
Ui::AddSubsectionTitle(
|
||||||
|
groupCalls->entity(),
|
||||||
|
tr::lng_call_box_groupcalls_subtitle());
|
||||||
|
state->groupCallsDelegate.setContent(groupCalls->entity()->add(
|
||||||
|
object_ptr<PeerListContent>(box, &state->groupCallsController),
|
||||||
|
{}));
|
||||||
|
state->groupCallsController.setDelegate(&state->groupCallsDelegate);
|
||||||
|
Ui::AddSkip(groupCalls->entity());
|
||||||
|
Ui::AddDivider(groupCalls->entity());
|
||||||
|
Ui::AddSkip(groupCalls->entity());
|
||||||
|
|
||||||
|
const auto button = AddCreateCallButton(
|
||||||
|
box->verticalLayout(),
|
||||||
|
window,
|
||||||
|
crl::guard(box, [=] { box->closeBox(); }));
|
||||||
|
button->events(
|
||||||
|
) | rpl::filter([=](not_null<QEvent*> e) {
|
||||||
|
return (e->type() == QEvent::Enter);
|
||||||
|
}) | rpl::start_with_next([=] {
|
||||||
|
state->callsDelegate.peerListMouseLeftGeometry();
|
||||||
|
}, button->lifetime());
|
||||||
|
|
||||||
|
const auto content = box->addRow(
|
||||||
|
object_ptr<PeerListContent>(box, &state->callsController),
|
||||||
|
{});
|
||||||
|
state->callsDelegate.setContent(content);
|
||||||
|
state->callsController.setDelegate(&state->callsDelegate);
|
||||||
|
|
||||||
|
box->setWidth(state->callsController.contentWidth());
|
||||||
|
state->callsController.boxHeightValue(
|
||||||
|
) | rpl::start_with_next([=](int height) {
|
||||||
|
box->setMinHeight(height);
|
||||||
|
}, box->lifetime());
|
||||||
|
box->setTitle(tr::lng_call_box_title());
|
||||||
|
box->addButton(tr::lng_close(), [=] {
|
||||||
|
box->closeBox();
|
||||||
|
});
|
||||||
|
const auto menuButton = box->addTopButton(st::infoTopBarMenu);
|
||||||
|
menuButton->setClickedCallback([=] {
|
||||||
|
state->menu = base::make_unique_q<Ui::PopupMenu>(
|
||||||
|
menuButton,
|
||||||
|
st::popupMenuWithIcons);
|
||||||
|
const auto showSettings = [=] {
|
||||||
|
window->showSettings(
|
||||||
|
Settings::Calls::Id(),
|
||||||
|
::Window::SectionShow(anim::type::instant));
|
||||||
|
};
|
||||||
|
const auto clearAll = crl::guard(box, [=] {
|
||||||
|
box->uiShow()->showBox(Box(Calls::ClearCallsBox, window));
|
||||||
|
});
|
||||||
|
state->menu->addAction(
|
||||||
|
tr::lng_settings_section_call_settings(tr::now),
|
||||||
|
showSettings,
|
||||||
|
&st::menuIconSettings);
|
||||||
|
if (state->callsDelegate.peerListFullRowsCount() > 0) {
|
||||||
|
Ui::Menu::CreateAddActionCallback(state->menu)({
|
||||||
|
.text = tr::lng_call_box_clear_all(tr::now),
|
||||||
|
.handler = clearAll,
|
||||||
|
.icon = &st::menuIconDeleteAttention,
|
||||||
|
.isAttention = true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
state->menu->popup(QCursor::pos());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Calls
|
} // namespace Calls
|
||||||
|
|
|
@ -81,4 +81,6 @@ void ClearCallsBox(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
not_null<::Window::SessionController*> window);
|
not_null<::Window::SessionController*> window);
|
||||||
|
|
||||||
|
void ShowCallsBox(not_null<::Window::SessionController*> window);
|
||||||
|
|
||||||
} // namespace Calls
|
} // namespace Calls
|
||||||
|
|
|
@ -238,14 +238,14 @@ void Instance::startOrJoinGroupCall(
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::startOrJoinConferenceCall(StartConferenceInfo args) {
|
void Instance::startOrJoinConferenceCall(StartConferenceInfo args) {
|
||||||
Expects(args.call || (args.migrating && args.show));
|
Expects(args.call || args.show);
|
||||||
|
|
||||||
const auto migrationInfo = (args.migrating
|
const auto migrationInfo = (args.migrating
|
||||||
&& args.call
|
&& args.call
|
||||||
&& _currentCallPanel)
|
&& _currentCallPanel)
|
||||||
? _currentCallPanel->migrationInfo()
|
? _currentCallPanel->migrationInfo()
|
||||||
: ConferencePanelMigration();
|
: ConferencePanelMigration();
|
||||||
if (args.call && !args.migrating) {
|
if (!args.migrating) {
|
||||||
destroyCurrentCall();
|
destroyCurrentCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,17 +270,17 @@ void Instance::startOrJoinConferenceCall(StartConferenceInfo args) {
|
||||||
destroyCurrentCall(args.call.get(), args.linkSlug);
|
destroyCurrentCall(args.call.get(), args.linkSlug);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (const auto was = base::take(_migratingGroupCall)) {
|
if (const auto was = base::take(_startingGroupCall)) {
|
||||||
destroyGroupCall(was.get());
|
destroyGroupCall(was.get());
|
||||||
}
|
}
|
||||||
_migratingGroupCall = std::move(call);
|
_startingGroupCall = std::move(call);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::migratedConferenceReady(
|
void Instance::startedConferenceReady(
|
||||||
not_null<GroupCall*> call,
|
not_null<GroupCall*> call,
|
||||||
StartConferenceInfo args) {
|
StartConferenceInfo args) {
|
||||||
if (_migratingGroupCall.get() != call) {
|
if (_startingGroupCall.get() != call) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto migrationInfo = _currentCallPanel
|
const auto migrationInfo = _currentCallPanel
|
||||||
|
@ -289,7 +289,7 @@ void Instance::migratedConferenceReady(
|
||||||
_currentGroupCallPanel = std::make_unique<Group::Panel>(
|
_currentGroupCallPanel = std::make_unique<Group::Panel>(
|
||||||
call,
|
call,
|
||||||
migrationInfo);
|
migrationInfo);
|
||||||
_currentGroupCall = std::move(_migratingGroupCall);
|
_currentGroupCall = std::move(_startingGroupCall);
|
||||||
_currentGroupCallChanges.fire_copy(call);
|
_currentGroupCallChanges.fire_copy(call);
|
||||||
const auto real = call->conferenceCall().get();
|
const auto real = call->conferenceCall().get();
|
||||||
const auto link = real->conferenceInviteLink();
|
const auto link = real->conferenceInviteLink();
|
||||||
|
@ -461,8 +461,8 @@ void Instance::destroyGroupCall(not_null<GroupCall*> call) {
|
||||||
LOG(("Calls::Instance doesn't prevent quit any more."));
|
LOG(("Calls::Instance doesn't prevent quit any more."));
|
||||||
}
|
}
|
||||||
Core::App().quitPreventFinished();
|
Core::App().quitPreventFinished();
|
||||||
} else if (_migratingGroupCall.get() == call) {
|
} else if (_startingGroupCall.get() == call) {
|
||||||
base::take(_migratingGroupCall);
|
base::take(_startingGroupCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,7 +695,7 @@ void Instance::handleGroupCallUpdate(
|
||||||
const MTPUpdate &update) {
|
const MTPUpdate &update) {
|
||||||
const auto groupCall = _currentGroupCall
|
const auto groupCall = _currentGroupCall
|
||||||
? _currentGroupCall.get()
|
? _currentGroupCall.get()
|
||||||
: _migratingGroupCall.get();
|
: _startingGroupCall.get();
|
||||||
if (groupCall && (&groupCall->peer()->session() == session)) {
|
if (groupCall && (&groupCall->peer()->session() == session)) {
|
||||||
update.match([&](const MTPDupdateGroupCall &data) {
|
update.match([&](const MTPDupdateGroupCall &data) {
|
||||||
groupCall->handlePossibleCreateOrJoinResponse(data);
|
groupCall->handlePossibleCreateOrJoinResponse(data);
|
||||||
|
@ -744,7 +744,7 @@ void Instance::applyGroupCallUpdateChecked(
|
||||||
const MTPUpdate &update) {
|
const MTPUpdate &update) {
|
||||||
const auto groupCall = _currentGroupCall
|
const auto groupCall = _currentGroupCall
|
||||||
? _currentGroupCall.get()
|
? _currentGroupCall.get()
|
||||||
: _migratingGroupCall.get();
|
: _startingGroupCall.get();
|
||||||
if (groupCall && (&groupCall->peer()->session() == session)) {
|
if (groupCall && (&groupCall->peer()->session() == session)) {
|
||||||
groupCall->handleUpdate(update);
|
groupCall->handleUpdate(update);
|
||||||
}
|
}
|
||||||
|
@ -798,7 +798,7 @@ void Instance::destroyCurrentCall(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
base::take(_migratingGroupCall);
|
base::take(_startingGroupCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Instance::hasVisiblePanel(Main::Session *session) const {
|
bool Instance::hasVisiblePanel(Main::Session *session) const {
|
||||||
|
|
|
@ -86,7 +86,7 @@ public:
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
StartGroupCallArgs args);
|
StartGroupCallArgs args);
|
||||||
void startOrJoinConferenceCall(StartConferenceInfo args);
|
void startOrJoinConferenceCall(StartConferenceInfo args);
|
||||||
void migratedConferenceReady(
|
void startedConferenceReady(
|
||||||
not_null<GroupCall*> call,
|
not_null<GroupCall*> call,
|
||||||
StartConferenceInfo args);
|
StartConferenceInfo args);
|
||||||
void showStartWithRtmp(
|
void showStartWithRtmp(
|
||||||
|
@ -203,7 +203,7 @@ private:
|
||||||
std::unique_ptr<Panel> _currentCallPanel;
|
std::unique_ptr<Panel> _currentCallPanel;
|
||||||
|
|
||||||
std::unique_ptr<GroupCall> _currentGroupCall;
|
std::unique_ptr<GroupCall> _currentGroupCall;
|
||||||
std::unique_ptr<GroupCall> _migratingGroupCall;
|
std::unique_ptr<GroupCall> _startingGroupCall;
|
||||||
rpl::event_stream<GroupCall*> _currentGroupCallChanges;
|
rpl::event_stream<GroupCall*> _currentGroupCallChanges;
|
||||||
std::unique_ptr<Group::Panel> _currentGroupCallPanel;
|
std::unique_ptr<Group::Panel> _currentGroupCallPanel;
|
||||||
|
|
||||||
|
|
|
@ -662,7 +662,7 @@ GroupCall::GroupCall(
|
||||||
if (!canManage() && real->joinMuted()) {
|
if (!canManage() && real->joinMuted()) {
|
||||||
_muted = MuteState::ForceMuted;
|
_muted = MuteState::ForceMuted;
|
||||||
}
|
}
|
||||||
} else if (!conference.migrating) {
|
} else if (!conference.migrating && !conference.show) {
|
||||||
_peer->session().changes().peerFlagsValue(
|
_peer->session().changes().peerFlagsValue(
|
||||||
_peer,
|
_peer,
|
||||||
Data::PeerUpdate::Flag::GroupCall
|
Data::PeerUpdate::Flag::GroupCall
|
||||||
|
@ -682,18 +682,18 @@ GroupCall::GroupCall(
|
||||||
|
|
||||||
setupMediaDevices();
|
setupMediaDevices();
|
||||||
setupOutgoingVideo();
|
setupOutgoingVideo();
|
||||||
if (_conferenceCall || conference.migrating) {
|
if (_conferenceCall || conference.migrating || conference.show) {
|
||||||
setupConference();
|
setupConference();
|
||||||
}
|
}
|
||||||
if (conference.migrating) {
|
if (conference.migrating || (conference.show && !_conferenceCall)) {
|
||||||
if (!conference.muted) {
|
if (!conference.muted) {
|
||||||
setMuted(MuteState::Active);
|
setMuted(MuteState::Active);
|
||||||
}
|
}
|
||||||
_migratedConferenceInfo = std::make_shared<StartConferenceInfo>(
|
_startConferenceInfo = std::make_shared<StartConferenceInfo>(
|
||||||
std::move(conference));
|
std::move(conference));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_id || (!_conferenceCall && _migratedConferenceInfo)) {
|
if (_id || (!_conferenceCall && _startConferenceInfo)) {
|
||||||
initialJoin();
|
initialJoin();
|
||||||
} else {
|
} else {
|
||||||
start(join.scheduleDate, join.rtmp);
|
start(join.scheduleDate, join.rtmp);
|
||||||
|
@ -703,7 +703,7 @@ GroupCall::GroupCall(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::processMigration(StartConferenceInfo conference) {
|
void GroupCall::processConferenceStart(StartConferenceInfo conference) {
|
||||||
if (!conference.videoCapture) {
|
if (!conference.videoCapture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1185,7 +1185,7 @@ bool GroupCall::rtmp() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GroupCall::conference() const {
|
bool GroupCall::conference() const {
|
||||||
return _conferenceCall || _migratedConferenceInfo;
|
return _conferenceCall || _startConferenceInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GroupCall::listenersHidden() const {
|
bool GroupCall::listenersHidden() const {
|
||||||
|
@ -1552,7 +1552,7 @@ void GroupCall::rejoin(not_null<PeerData*> as) {
|
||||||
};
|
};
|
||||||
LOG(("Call Info: Join payload received, joining with ssrc: %1."
|
LOG(("Call Info: Join payload received, joining with ssrc: %1."
|
||||||
).arg(_joinState.payload.ssrc));
|
).arg(_joinState.payload.ssrc));
|
||||||
if (!_conferenceCall && _migratedConferenceInfo) {
|
if (!_conferenceCall && _startConferenceInfo) {
|
||||||
startConference();
|
startConference();
|
||||||
} else if (_conferenceCall
|
} else if (_conferenceCall
|
||||||
&& !_conferenceCall->blockchainMayBeEmpty()
|
&& !_conferenceCall->blockchainMayBeEmpty()
|
||||||
|
@ -1655,7 +1655,7 @@ void GroupCall::refreshLastBlockAndJoin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::startConference() {
|
void GroupCall::startConference() {
|
||||||
Expects(_e2e != nullptr && _migratedConferenceInfo != nullptr);
|
Expects(_e2e != nullptr && _startConferenceInfo != nullptr);
|
||||||
|
|
||||||
const auto joinBlock = _e2e->makeJoinBlock().data;
|
const auto joinBlock = _e2e->makeJoinBlock().data;
|
||||||
Assert(!joinBlock.isEmpty());
|
Assert(!joinBlock.isEmpty());
|
||||||
|
@ -1706,7 +1706,7 @@ void GroupCall::joinDone(
|
||||||
MuteState wasMuteState,
|
MuteState wasMuteState,
|
||||||
bool wasVideoStopped,
|
bool wasVideoStopped,
|
||||||
bool justCreated) {
|
bool justCreated) {
|
||||||
Expects(!justCreated || _migratedConferenceInfo != nullptr);
|
Expects(!justCreated || _startConferenceInfo != nullptr);
|
||||||
|
|
||||||
_serverTimeMs = serverTimeMs;
|
_serverTimeMs = serverTimeMs;
|
||||||
_serverTimeMsGotAt = crl::now();
|
_serverTimeMsGotAt = crl::now();
|
||||||
|
@ -1728,9 +1728,9 @@ void GroupCall::joinDone(
|
||||||
setupConferenceCall();
|
setupConferenceCall();
|
||||||
_conferenceLinkSlug = Group::ExtractConferenceSlug(
|
_conferenceLinkSlug = Group::ExtractConferenceSlug(
|
||||||
_conferenceCall->conferenceInviteLink());
|
_conferenceCall->conferenceInviteLink());
|
||||||
Core::App().calls().migratedConferenceReady(
|
Core::App().calls().startedConferenceReady(
|
||||||
this,
|
this,
|
||||||
*_migratedConferenceInfo);
|
*_startConferenceInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyQueuedSelfUpdates();
|
applyQueuedSelfUpdates();
|
||||||
|
@ -1757,8 +1757,8 @@ void GroupCall::joinDone(
|
||||||
sendOutboundBlock(base::take(_pendingOutboundBlock));
|
sendOutboundBlock(base::take(_pendingOutboundBlock));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (const auto once = base::take(_migratedConferenceInfo)) {
|
if (const auto once = base::take(_startConferenceInfo)) {
|
||||||
processMigration(*once);
|
processConferenceStart(*once);
|
||||||
}
|
}
|
||||||
for (const auto &callback : base::take(_rejoinedCallbacks)) {
|
for (const auto &callback : base::take(_rejoinedCallbacks)) {
|
||||||
callback();
|
callback();
|
||||||
|
|
|
@ -635,7 +635,7 @@ private:
|
||||||
void markTrackPaused(const VideoEndpoint &endpoint, bool paused);
|
void markTrackPaused(const VideoEndpoint &endpoint, bool paused);
|
||||||
void markTrackShown(const VideoEndpoint &endpoint, bool shown);
|
void markTrackShown(const VideoEndpoint &endpoint, bool shown);
|
||||||
|
|
||||||
void processMigration(StartConferenceInfo conference);
|
void processConferenceStart(StartConferenceInfo conference);
|
||||||
void inviteToConference(
|
void inviteToConference(
|
||||||
InviteRequest request,
|
InviteRequest request,
|
||||||
Fn<not_null<InviteResult*>()> resultAddress,
|
Fn<not_null<InviteResult*>()> resultAddress,
|
||||||
|
@ -650,7 +650,7 @@ private:
|
||||||
std::shared_ptr<Data::GroupCall> _conferenceCall;
|
std::shared_ptr<Data::GroupCall> _conferenceCall;
|
||||||
std::shared_ptr<TdE2E::Call> _e2e;
|
std::shared_ptr<TdE2E::Call> _e2e;
|
||||||
QByteArray _pendingOutboundBlock;
|
QByteArray _pendingOutboundBlock;
|
||||||
std::shared_ptr<StartConferenceInfo> _migratedConferenceInfo;
|
std::shared_ptr<StartConferenceInfo> _startConferenceInfo;
|
||||||
|
|
||||||
not_null<PeerData*> _peer; // Can change in legacy group migration.
|
not_null<PeerData*> _peer; // Can change in legacy group migration.
|
||||||
rpl::event_stream<PeerData*> _peerStream;
|
rpl::event_stream<PeerData*> _peerStream;
|
||||||
|
|
|
@ -436,8 +436,6 @@ void ShowConferenceCallLinkBox(
|
||||||
void MakeConferenceCall(ConferenceFactoryArgs &&args) {
|
void MakeConferenceCall(ConferenceFactoryArgs &&args) {
|
||||||
const auto show = std::move(args.show);
|
const auto show = std::move(args.show);
|
||||||
const auto finished = std::move(args.finished);
|
const auto finished = std::move(args.finished);
|
||||||
const auto joining = args.joining;
|
|
||||||
const auto info = std::move(args.info);
|
|
||||||
const auto session = &show->session();
|
const auto session = &show->session();
|
||||||
const auto fail = [=](QString error) {
|
const auto fail = [=](QString error) {
|
||||||
show->showToast(error);
|
show->showToast(error);
|
||||||
|
@ -464,20 +462,10 @@ void MakeConferenceCall(ConferenceFactoryArgs &&args) {
|
||||||
fail(u"Call link not found!"_q);
|
fail(u"Call link not found!"_q);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (joining) {
|
Calls::Group::ShowConferenceCallLinkBox(
|
||||||
if (auto slug = ExtractConferenceSlug(link); !slug.isEmpty()) {
|
show,
|
||||||
auto copy = info;
|
call,
|
||||||
copy.call = call;
|
{ .initial = true });
|
||||||
copy.linkSlug = std::move(slug);
|
|
||||||
Core::App().calls().startOrJoinConferenceCall(
|
|
||||||
std::move(copy));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Calls::Group::ShowConferenceCallLinkBox(
|
|
||||||
show,
|
|
||||||
call,
|
|
||||||
{ .initial = true });
|
|
||||||
}
|
|
||||||
if (const auto onstack = finished) {
|
if (const auto onstack = finished) {
|
||||||
finished(true);
|
finished(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "calls/group/calls_group_common.h"
|
#include "calls/group/calls_group_common.h"
|
||||||
#include "calls/group/calls_group_menu.h"
|
#include "calls/group/calls_group_menu.h"
|
||||||
#include "calls/calls_call.h"
|
#include "calls/calls_call.h"
|
||||||
|
#include "calls/calls_instance.h"
|
||||||
|
#include "core/application.h"
|
||||||
#include "boxes/peer_lists_box.h"
|
#include "boxes/peer_lists_box.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
@ -29,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_boxes.h" // membersMarginTop
|
#include "styles/style_boxes.h" // membersMarginTop
|
||||||
#include "styles/style_calls.h"
|
#include "styles/style_calls.h"
|
||||||
#include "styles/style_dialogs.h" // searchedBarHeight
|
#include "styles/style_dialogs.h" // searchedBarHeight
|
||||||
|
@ -65,9 +68,18 @@ namespace {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ConfInviteStyles {
|
||||||
|
const style::IconButton *video = nullptr;
|
||||||
|
const style::icon *videoActive = nullptr;
|
||||||
|
const style::IconButton *audio = nullptr;
|
||||||
|
const style::icon *audioActive = nullptr;
|
||||||
|
const style::SettingsButton *inviteViaLink = nullptr;
|
||||||
|
const style::icon *inviteViaLinkIcon = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class ConfInviteRow final : public PeerListRow {
|
class ConfInviteRow final : public PeerListRow {
|
||||||
public:
|
public:
|
||||||
using PeerListRow::PeerListRow;
|
ConfInviteRow(not_null<UserData*> user, const ConfInviteStyles &st);
|
||||||
|
|
||||||
void setAlreadyIn(bool alreadyIn);
|
void setAlreadyIn(bool alreadyIn);
|
||||||
void setVideo(bool video);
|
void setVideo(bool video);
|
||||||
|
@ -88,6 +100,9 @@ public:
|
||||||
int selectedElement) override;
|
int selectedElement) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
[[nodiscard]] const style::IconButton &buttonSt(int element) const;
|
||||||
|
|
||||||
|
const ConfInviteStyles &_st;
|
||||||
std::unique_ptr<Ui::RippleAnimation> _videoRipple;
|
std::unique_ptr<Ui::RippleAnimation> _videoRipple;
|
||||||
std::unique_ptr<Ui::RippleAnimation> _audioRipple;
|
std::unique_ptr<Ui::RippleAnimation> _audioRipple;
|
||||||
bool _alreadyIn = false;
|
bool _alreadyIn = false;
|
||||||
|
@ -99,6 +114,7 @@ class ConfInviteController final : public ContactsBoxController {
|
||||||
public:
|
public:
|
||||||
ConfInviteController(
|
ConfInviteController(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
|
ConfInviteStyles st,
|
||||||
base::flat_set<not_null<UserData*>> alreadyIn,
|
base::flat_set<not_null<UserData*>> alreadyIn,
|
||||||
Fn<void()> shareLink);
|
Fn<void()> shareLink);
|
||||||
|
|
||||||
|
@ -119,6 +135,7 @@ private:
|
||||||
[[nodiscard]] int fullCount() const;
|
[[nodiscard]] int fullCount() const;
|
||||||
void toggleRowSelected(not_null<PeerListRow*> row, bool video);
|
void toggleRowSelected(not_null<PeerListRow*> row, bool video);
|
||||||
|
|
||||||
|
const ConfInviteStyles _st;
|
||||||
const base::flat_set<not_null<UserData*>> _alreadyIn;
|
const base::flat_set<not_null<UserData*>> _alreadyIn;
|
||||||
const Fn<void()> _shareLink;
|
const Fn<void()> _shareLink;
|
||||||
rpl::variable<bool> _hasSelected;
|
rpl::variable<bool> _hasSelected;
|
||||||
|
@ -127,6 +144,33 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] ConfInviteStyles ConfInviteDarkStyles() {
|
||||||
|
return {
|
||||||
|
.video = &st::confcallInviteVideo,
|
||||||
|
.videoActive = &st::confcallInviteVideoActive,
|
||||||
|
.audio = &st::confcallInviteAudio,
|
||||||
|
.audioActive = &st::confcallInviteAudioActive,
|
||||||
|
.inviteViaLink = &st::groupCallInviteLink,
|
||||||
|
.inviteViaLinkIcon = &st::groupCallInviteLinkIcon,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] ConfInviteStyles ConfInviteDefaultStyles() {
|
||||||
|
return {
|
||||||
|
.video = &st::createCallVideo,
|
||||||
|
.videoActive = &st::createCallVideoActive,
|
||||||
|
.audio = &st::createCallAudio,
|
||||||
|
.audioActive = &st::createCallAudioActive,
|
||||||
|
.inviteViaLink = &st::createCallInviteLink,
|
||||||
|
.inviteViaLinkIcon = &st::createCallInviteLinkIcon,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfInviteRow::ConfInviteRow(not_null<UserData*> user, const ConfInviteStyles &st)
|
||||||
|
: PeerListRow(user)
|
||||||
|
, _st(st) {
|
||||||
|
}
|
||||||
|
|
||||||
void ConfInviteRow::setAlreadyIn(bool alreadyIn) {
|
void ConfInviteRow::setAlreadyIn(bool alreadyIn) {
|
||||||
_alreadyIn = alreadyIn;
|
_alreadyIn = alreadyIn;
|
||||||
setDisabledState(alreadyIn ? State::DisabledChecked : State::Active);
|
setDisabledState(alreadyIn ? State::DisabledChecked : State::Active);
|
||||||
|
@ -136,6 +180,12 @@ void ConfInviteRow::setVideo(bool video) {
|
||||||
_video = video;
|
_video = video;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const style::IconButton &ConfInviteRow::buttonSt(int element) const {
|
||||||
|
return (element == 1)
|
||||||
|
? (_st.video ? *_st.video : st::createCallVideo)
|
||||||
|
: (_st.audio ? *_st.audio : st::createCallAudio);
|
||||||
|
}
|
||||||
|
|
||||||
int ConfInviteRow::elementsCount() const {
|
int ConfInviteRow::elementsCount() const {
|
||||||
return _alreadyIn ? 0 : 2;
|
return _alreadyIn ? 0 : 2;
|
||||||
}
|
}
|
||||||
|
@ -144,13 +194,11 @@ QRect ConfInviteRow::elementGeometry(int element, int outerWidth) const {
|
||||||
if (_alreadyIn || (element != 1 && element != 2)) {
|
if (_alreadyIn || (element != 1 && element != 2)) {
|
||||||
return QRect();
|
return QRect();
|
||||||
}
|
}
|
||||||
const auto &st = (element == 1)
|
const auto &st = buttonSt(element);
|
||||||
? st::confcallInviteVideo
|
|
||||||
: st::confcallInviteAudio;
|
|
||||||
const auto size = QSize(st.width, st.height);
|
const auto size = QSize(st.width, st.height);
|
||||||
const auto margins = (element == 1)
|
const auto margins = (element == 1)
|
||||||
? st::confcallInviteVideoMargins
|
? st::createCallVideoMargins
|
||||||
: st::confcallInviteAudioMargins;
|
: st::createCallAudioMargins;
|
||||||
const auto right = margins.right();
|
const auto right = margins.right();
|
||||||
const auto top = margins.top();
|
const auto top = margins.top();
|
||||||
const auto side = (element == 1)
|
const auto side = (element == 1)
|
||||||
|
@ -178,9 +226,7 @@ void ConfInviteRow::elementAddRipple(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto &ripple = (element == 1) ? _videoRipple : _audioRipple;
|
auto &ripple = (element == 1) ? _videoRipple : _audioRipple;
|
||||||
const auto &st = (element == 1)
|
const auto &st = buttonSt(element);
|
||||||
? st::confcallInviteVideo
|
|
||||||
: st::confcallInviteAudio;
|
|
||||||
if (!ripple) {
|
if (!ripple) {
|
||||||
auto mask = Ui::RippleAnimation::EllipseMask(QSize(
|
auto mask = Ui::RippleAnimation::EllipseMask(QSize(
|
||||||
st.rippleAreaSize,
|
st.rippleAreaSize,
|
||||||
|
@ -211,9 +257,7 @@ void ConfInviteRow::elementsPaint(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto paintElement = [&](int element) {
|
const auto paintElement = [&](int element) {
|
||||||
const auto &st = (element == 1)
|
const auto &st = buttonSt(element);
|
||||||
? st::confcallInviteVideo
|
|
||||||
: st::confcallInviteAudio;
|
|
||||||
auto &ripple = (element == 1) ? _videoRipple : _audioRipple;
|
auto &ripple = (element == 1) ? _videoRipple : _audioRipple;
|
||||||
const auto active = checked() && ((element == 1) ? _video : !_video);
|
const auto active = checked() && ((element == 1) ? _video : !_video);
|
||||||
const auto geometry = elementGeometry(element, outerWidth);
|
const auto geometry = elementGeometry(element, outerWidth);
|
||||||
|
@ -230,8 +274,12 @@ void ConfInviteRow::elementsPaint(
|
||||||
const auto selected = (element == selectedElement);
|
const auto selected = (element == selectedElement);
|
||||||
const auto &icon = active
|
const auto &icon = active
|
||||||
? (element == 1
|
? (element == 1
|
||||||
? st::confcallInviteVideoActive
|
? (_st.videoActive
|
||||||
: st::confcallInviteAudioActive)
|
? *_st.videoActive
|
||||||
|
: st::createCallVideoActive)
|
||||||
|
: (_st.audioActive
|
||||||
|
? *_st.audioActive
|
||||||
|
: st::createCallAudioActive))
|
||||||
: (selected ? st.iconOver : st.icon);
|
: (selected ? st.iconOver : st.icon);
|
||||||
icon.paintInCenter(p, geometry);
|
icon.paintInCenter(p, geometry);
|
||||||
};
|
};
|
||||||
|
@ -241,9 +289,11 @@ void ConfInviteRow::elementsPaint(
|
||||||
|
|
||||||
ConfInviteController::ConfInviteController(
|
ConfInviteController::ConfInviteController(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
|
ConfInviteStyles st,
|
||||||
base::flat_set<not_null<UserData*>> alreadyIn,
|
base::flat_set<not_null<UserData*>> alreadyIn,
|
||||||
Fn<void()> shareLink)
|
Fn<void()> shareLink)
|
||||||
: ContactsBoxController(session)
|
: ContactsBoxController(session)
|
||||||
|
, _st(st)
|
||||||
, _alreadyIn(std::move(alreadyIn))
|
, _alreadyIn(std::move(alreadyIn))
|
||||||
, _shareLink(std::move(shareLink)) {
|
, _shareLink(std::move(shareLink)) {
|
||||||
}
|
}
|
||||||
|
@ -272,7 +322,7 @@ std::unique_ptr<PeerListRow> ConfInviteController::createRow(
|
||||||
|| user->isInaccessible()) {
|
|| user->isInaccessible()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto result = std::make_unique<ConfInviteRow>(user);
|
auto result = std::make_unique<ConfInviteRow>(user, _st);
|
||||||
if (_alreadyIn.contains(user)) {
|
if (_alreadyIn.contains(user)) {
|
||||||
result->setAlreadyIn(true);
|
result->setAlreadyIn(true);
|
||||||
}
|
}
|
||||||
|
@ -283,7 +333,9 @@ std::unique_ptr<PeerListRow> ConfInviteController::createRow(
|
||||||
}
|
}
|
||||||
|
|
||||||
int ConfInviteController::fullCount() const {
|
int ConfInviteController::fullCount() const {
|
||||||
return _alreadyIn.size() + delegate()->peerListSelectedRowsCount();
|
return _alreadyIn.size()
|
||||||
|
+ delegate()->peerListSelectedRowsCount()
|
||||||
|
+ (_alreadyIn.contains(session().user()) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfInviteController::rowClicked(not_null<PeerListRow*> row) {
|
void ConfInviteController::rowClicked(not_null<PeerListRow*> row) {
|
||||||
|
@ -336,17 +388,21 @@ void ConfInviteController::prepareViewHook() {
|
||||||
object_ptr<Ui::SettingsButton>(
|
object_ptr<Ui::SettingsButton>(
|
||||||
nullptr,
|
nullptr,
|
||||||
tr::lng_profile_add_via_link(),
|
tr::lng_profile_add_via_link(),
|
||||||
st::groupCallInviteLink),
|
(_st.inviteViaLink
|
||||||
|
? *_st.inviteViaLink
|
||||||
|
: st::createCallInviteLink)),
|
||||||
style::margins(0, st::membersMarginTop, 0, 0));
|
style::margins(0, st::membersMarginTop, 0, 0));
|
||||||
|
|
||||||
const auto icon = Ui::CreateChild<Info::Profile::FloatingIcon>(
|
const auto icon = Ui::CreateChild<Info::Profile::FloatingIcon>(
|
||||||
button->entity(),
|
button->entity(),
|
||||||
st::groupCallInviteLinkIcon,
|
(_st.inviteViaLinkIcon
|
||||||
|
? *_st.inviteViaLinkIcon
|
||||||
|
: st::createCallInviteLinkIcon),
|
||||||
QPoint());
|
QPoint());
|
||||||
button->entity()->heightValue(
|
button->entity()->heightValue(
|
||||||
) | rpl::start_with_next([=](int height) {
|
) | rpl::start_with_next([=](int height) {
|
||||||
icon->moveToLeft(
|
icon->moveToLeft(
|
||||||
st::groupCallInviteLinkIconPosition.x(),
|
st::createCallInviteLinkIconPosition.x(),
|
||||||
(height - st::groupCallInviteLinkIcon.height()) / 2);
|
(height - st::groupCallInviteLinkIcon.height()) / 2);
|
||||||
}, icon->lifetime());
|
}, icon->lifetime());
|
||||||
|
|
||||||
|
@ -504,6 +560,7 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||||
};
|
};
|
||||||
auto controller = std::make_unique<ConfInviteController>(
|
auto controller = std::make_unique<ConfInviteController>(
|
||||||
&real->session(),
|
&real->session(),
|
||||||
|
ConfInviteDarkStyles(),
|
||||||
alreadyIn,
|
alreadyIn,
|
||||||
shareLink);
|
shareLink);
|
||||||
const auto raw = controller.get();
|
const auto raw = controller.get();
|
||||||
|
@ -674,6 +731,7 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||||
auto alreadyIn = base::flat_set<not_null<UserData*>>{ user };
|
auto alreadyIn = base::flat_set<not_null<UserData*>>{ user };
|
||||||
auto controller = std::make_unique<ConfInviteController>(
|
auto controller = std::make_unique<ConfInviteController>(
|
||||||
&user->session(),
|
&user->session(),
|
||||||
|
ConfInviteDarkStyles(),
|
||||||
alreadyIn,
|
alreadyIn,
|
||||||
shareLink);
|
shareLink);
|
||||||
const auto raw = controller.get();
|
const auto raw = controller.get();
|
||||||
|
@ -699,4 +757,73 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||||
return Box<PeerListBox>(std::move(controller), initBox);
|
return Box<PeerListBox>(std::move(controller), initBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_ptr<Ui::BoxContent> PrepareCreateCallBox(
|
||||||
|
not_null<::Window::SessionController*> window,
|
||||||
|
Fn<void()> created) {
|
||||||
|
struct State {
|
||||||
|
bool creatingLink = false;
|
||||||
|
QPointer<PeerListBox> box;
|
||||||
|
};
|
||||||
|
const auto state = std::make_shared<State>();
|
||||||
|
const auto finished = [=](bool ok) {
|
||||||
|
if (!ok) {
|
||||||
|
state->creatingLink = false;
|
||||||
|
} else {
|
||||||
|
if (const auto strong = state->box.data()) {
|
||||||
|
strong->closeBox();
|
||||||
|
}
|
||||||
|
if (const auto onstack = created) {
|
||||||
|
onstack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auto shareLink = [=] {
|
||||||
|
if (state->creatingLink) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state->creatingLink = true;
|
||||||
|
MakeConferenceCall({
|
||||||
|
.show = window->uiShow(),
|
||||||
|
.finished = finished,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
auto controller = std::make_unique<ConfInviteController>(
|
||||||
|
&window->session(),
|
||||||
|
ConfInviteDefaultStyles(),
|
||||||
|
base::flat_set<not_null<UserData*>>(),
|
||||||
|
shareLink);
|
||||||
|
const auto raw = controller.get();
|
||||||
|
const auto initBox = [=](not_null<PeerListBox*> box) {
|
||||||
|
box->setTitle(tr::lng_confcall_create_title());
|
||||||
|
|
||||||
|
const auto create = [=] {
|
||||||
|
auto selected = raw->requests(box->collectSelectedRows());
|
||||||
|
if (selected.size() != 1) {
|
||||||
|
Core::App().calls().startOrJoinConferenceCall({
|
||||||
|
.show = window->uiShow(),
|
||||||
|
.invite = std::move(selected),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const auto &invite = selected.front();
|
||||||
|
Core::App().calls().startOutgoingCall(
|
||||||
|
invite.user,
|
||||||
|
invite.video);
|
||||||
|
}
|
||||||
|
finished(true);
|
||||||
|
};
|
||||||
|
box->addButton(
|
||||||
|
rpl::conditional(
|
||||||
|
raw->hasSelectedValue(),
|
||||||
|
tr::lng_group_call_confcall_add(),
|
||||||
|
tr::lng_create_group_create()),
|
||||||
|
create);
|
||||||
|
box->addButton(tr::lng_close(), [=] {
|
||||||
|
box->closeBox();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
auto result = Box<PeerListBox>(std::move(controller), initBox);
|
||||||
|
state->box = result.data();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Calls::Group
|
} // namespace Calls::Group
|
||||||
|
|
|
@ -87,4 +87,8 @@ private:
|
||||||
Fn<void(std::vector<InviteRequest>)> inviteUsers,
|
Fn<void(std::vector<InviteRequest>)> inviteUsers,
|
||||||
Fn<void()> shareLink);
|
Fn<void()> shareLink);
|
||||||
|
|
||||||
|
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareCreateCallBox(
|
||||||
|
not_null<::Window::SessionController*> window,
|
||||||
|
Fn<void()> created = nullptr);
|
||||||
|
|
||||||
} // namespace Calls::Group
|
} // namespace Calls::Group
|
||||||
|
|
|
@ -98,145 +98,6 @@ constexpr auto kPlayStatusLimit = 2;
|
||||||
|| (now.month() == 1 && now.day() == 1);
|
|| (now.month() == 1 && now.day() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] not_null<Ui::SettingsButton*> AddCreateCallLinkButton(
|
|
||||||
not_null<Ui::VerticalLayout*> container,
|
|
||||||
not_null<Window::SessionController*> controller,
|
|
||||||
Fn<void()> done) {
|
|
||||||
const auto result = container->add(object_ptr<Ui::SettingsButton>(
|
|
||||||
container,
|
|
||||||
tr::lng_confcall_create_link(),
|
|
||||||
st::inviteViaLinkButton), QMargins());
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
Ui::AddDividerText(
|
|
||||||
container,
|
|
||||||
tr::lng_confcall_create_link_description(Ui::Text::WithEntities));
|
|
||||||
|
|
||||||
const auto icon = Ui::CreateChild<Info::Profile::FloatingIcon>(
|
|
||||||
result,
|
|
||||||
st::inviteViaLinkIcon,
|
|
||||||
QPoint());
|
|
||||||
result->heightValue(
|
|
||||||
) | rpl::start_with_next([=](int height) {
|
|
||||||
icon->moveToLeft(
|
|
||||||
st::inviteViaLinkIconPosition.x(),
|
|
||||||
(height - st::inviteViaLinkIcon.height()) / 2);
|
|
||||||
}, icon->lifetime());
|
|
||||||
|
|
||||||
const auto creating = std::make_shared<bool>();
|
|
||||||
result->setClickedCallback([=] {
|
|
||||||
if (*creating) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*creating = true;
|
|
||||||
const auto finished = [=](bool ok) {
|
|
||||||
if (!ok) {
|
|
||||||
*creating = false;
|
|
||||||
} else if (const auto onstack = done) {
|
|
||||||
onstack();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Calls::Group::MakeConferenceCall({
|
|
||||||
.show = controller->uiShow(),
|
|
||||||
.finished = finished,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShowCallsBox(not_null<Window::SessionController*> window) {
|
|
||||||
struct State {
|
|
||||||
State(not_null<Window::SessionController*> window)
|
|
||||||
: callsController(window)
|
|
||||||
, groupCallsController(window) {
|
|
||||||
}
|
|
||||||
Calls::BoxController callsController;
|
|
||||||
PeerListContentDelegateSimple callsDelegate;
|
|
||||||
|
|
||||||
Calls::GroupCalls::ListController groupCallsController;
|
|
||||||
PeerListContentDelegateSimple groupCallsDelegate;
|
|
||||||
|
|
||||||
base::unique_qptr<Ui::PopupMenu> menu;
|
|
||||||
};
|
|
||||||
|
|
||||||
window->show(Box([=](not_null<Ui::GenericBox*> box) {
|
|
||||||
const auto state = box->lifetime().make_state<State>(window);
|
|
||||||
|
|
||||||
const auto groupCalls = box->addRow(
|
|
||||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
|
||||||
box,
|
|
||||||
object_ptr<Ui::VerticalLayout>(box)),
|
|
||||||
{});
|
|
||||||
groupCalls->hide(anim::type::instant);
|
|
||||||
groupCalls->toggleOn(state->groupCallsController.shownValue());
|
|
||||||
|
|
||||||
Ui::AddSubsectionTitle(
|
|
||||||
groupCalls->entity(),
|
|
||||||
tr::lng_call_box_groupcalls_subtitle());
|
|
||||||
state->groupCallsDelegate.setContent(groupCalls->entity()->add(
|
|
||||||
object_ptr<PeerListContent>(box, &state->groupCallsController),
|
|
||||||
{}));
|
|
||||||
state->groupCallsController.setDelegate(&state->groupCallsDelegate);
|
|
||||||
Ui::AddSkip(groupCalls->entity());
|
|
||||||
Ui::AddDivider(groupCalls->entity());
|
|
||||||
Ui::AddSkip(groupCalls->entity());
|
|
||||||
|
|
||||||
const auto button = AddCreateCallLinkButton(
|
|
||||||
box->verticalLayout(),
|
|
||||||
window,
|
|
||||||
crl::guard(box, [=] { box->closeBox(); }));
|
|
||||||
button->events(
|
|
||||||
) | rpl::filter([=](not_null<QEvent*> e) {
|
|
||||||
return (e->type() == QEvent::Enter);
|
|
||||||
}) | rpl::start_with_next([=] {
|
|
||||||
state->callsDelegate.peerListMouseLeftGeometry();
|
|
||||||
}, button->lifetime());
|
|
||||||
|
|
||||||
const auto content = box->addRow(
|
|
||||||
object_ptr<PeerListContent>(box, &state->callsController),
|
|
||||||
{});
|
|
||||||
state->callsDelegate.setContent(content);
|
|
||||||
state->callsController.setDelegate(&state->callsDelegate);
|
|
||||||
|
|
||||||
box->setWidth(state->callsController.contentWidth());
|
|
||||||
state->callsController.boxHeightValue(
|
|
||||||
) | rpl::start_with_next([=](int height) {
|
|
||||||
box->setMinHeight(height);
|
|
||||||
}, box->lifetime());
|
|
||||||
box->setTitle(tr::lng_call_box_title());
|
|
||||||
box->addButton(tr::lng_close(), [=] {
|
|
||||||
box->closeBox();
|
|
||||||
});
|
|
||||||
const auto menuButton = box->addTopButton(st::infoTopBarMenu);
|
|
||||||
menuButton->setClickedCallback([=] {
|
|
||||||
state->menu = base::make_unique_q<Ui::PopupMenu>(
|
|
||||||
menuButton,
|
|
||||||
st::popupMenuWithIcons);
|
|
||||||
const auto showSettings = [=] {
|
|
||||||
window->showSettings(
|
|
||||||
Settings::Calls::Id(),
|
|
||||||
Window::SectionShow(anim::type::instant));
|
|
||||||
};
|
|
||||||
const auto clearAll = crl::guard(box, [=] {
|
|
||||||
box->uiShow()->showBox(Box(Calls::ClearCallsBox, window));
|
|
||||||
});
|
|
||||||
state->menu->addAction(
|
|
||||||
tr::lng_settings_section_call_settings(tr::now),
|
|
||||||
showSettings,
|
|
||||||
&st::menuIconSettings);
|
|
||||||
if (state->callsDelegate.peerListFullRowsCount() > 0) {
|
|
||||||
Ui::Menu::CreateAddActionCallback(state->menu)({
|
|
||||||
.text = tr::lng_call_box_clear_all(tr::now),
|
|
||||||
.handler = clearAll,
|
|
||||||
.icon = &st::menuIconDeleteAttention,
|
|
||||||
.isAttention = true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
state->menu->popup(QCursor::pos());
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<TextWithEntities> SetStatusLabel(
|
[[nodiscard]] rpl::producer<TextWithEntities> SetStatusLabel(
|
||||||
not_null<Main::Session*> session) {
|
not_null<Main::Session*> session) {
|
||||||
const auto self = session->user();
|
const auto self = session->user();
|
||||||
|
@ -835,7 +696,7 @@ void MainMenu::setupMenu() {
|
||||||
tr::lng_menu_calls(),
|
tr::lng_menu_calls(),
|
||||||
{ &st::menuIconPhone }
|
{ &st::menuIconPhone }
|
||||||
)->setClickedCallback([=] {
|
)->setClickedCallback([=] {
|
||||||
ShowCallsBox(controller);
|
::Calls::ShowCallsBox(controller);
|
||||||
});
|
});
|
||||||
addAction(
|
addAction(
|
||||||
tr::lng_saved_messages(),
|
tr::lng_saved_messages(),
|
||||||
|
|
Loading…
Add table
Reference in a new issue