Move actions from Settings to Three-Dot-Menu.
This commit is contained in:
parent
b24e5ce809
commit
f8783c3bfc
|
@ -428,6 +428,17 @@ groupCallPopupMenu: PopupMenu(defaultPopupMenu) {
|
||||||
animation: groupCallPanelAnimation;
|
animation: groupCallPanelAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupCallInnerDropdown: InnerDropdown(defaultInnerDropdown) {
|
||||||
|
shadow: groupCallMenuShadow;
|
||||||
|
animation: groupCallPanelAnimation;
|
||||||
|
bg: groupCallMenuBg;
|
||||||
|
scroll: defaultSolidScroll;
|
||||||
|
scrollPadding: margins(0px, 8px, 0px, 8px);
|
||||||
|
}
|
||||||
|
groupCallDropdownMenu: DropdownMenu(defaultDropdownMenu) {
|
||||||
|
wrap: groupCallInnerDropdown;
|
||||||
|
menu: groupCallMenu;
|
||||||
|
}
|
||||||
groupCallMembersListItem: PeerListItem(defaultPeerListItem) {
|
groupCallMembersListItem: PeerListItem(defaultPeerListItem) {
|
||||||
button: OutlineButton(defaultPeerListButton) {
|
button: OutlineButton(defaultPeerListButton) {
|
||||||
textBg: groupCallMembersBg;
|
textBg: groupCallMembersBg;
|
||||||
|
@ -526,9 +537,9 @@ groupCallField: InputField(defaultInputField) {
|
||||||
menu: groupCallPopupMenu;
|
menu: groupCallPopupMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
groupCallMembersTop: 62px;
|
groupCallMembersTop: 51px;
|
||||||
groupCallTitleTop: 14px;
|
groupCallTitleTop: 8px;
|
||||||
groupCallSubtitleTop: 33px;
|
groupCallSubtitleTop: 26px;
|
||||||
|
|
||||||
groupCallMembersMargin: margins(16px, 16px, 16px, 28px);
|
groupCallMembersMargin: margins(16px, 16px, 16px, 28px);
|
||||||
groupCallAddMember: SettingsButton(defaultSettingsButton) {
|
groupCallAddMember: SettingsButton(defaultSettingsButton) {
|
||||||
|
@ -562,7 +573,29 @@ groupCallAddButtonPosition: point(10px, 7px);
|
||||||
groupCallMembersWidthMax: 360px;
|
groupCallMembersWidthMax: 360px;
|
||||||
groupCallRecordingMark: 6px;
|
groupCallRecordingMark: 6px;
|
||||||
groupCallRecordingMarkSkip: 4px;
|
groupCallRecordingMarkSkip: 4px;
|
||||||
groupCallRecordingMarkTop: 6px;
|
groupCallRecordingMarkTop: 8px;
|
||||||
|
|
||||||
|
groupCallMenuTogglePosition: point(13px, 8px);
|
||||||
|
groupCallMenuToggle: IconButton {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
|
||||||
|
icon: icon {{ "info/edit/dotsmini", groupCallMemberInactiveIcon }};
|
||||||
|
iconOver: icon {{ "info/edit/dotsmini", groupCallMemberInactiveIcon }};
|
||||||
|
iconPosition: point(6px, 6px);
|
||||||
|
|
||||||
|
rippleAreaPosition: point(3px, 3px);
|
||||||
|
rippleAreaSize: 30px;
|
||||||
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
color: groupCallMembersBg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
groupCallJoinAsToggle: UserpicButton(defaultUserpicButton) {
|
||||||
|
size: size(36px, 36px);
|
||||||
|
photoSize: 30px;
|
||||||
|
photoPosition: point(3px, 3px);
|
||||||
|
}
|
||||||
|
groupCallMenuPosition: point(-1px, 29px);
|
||||||
|
|
||||||
groupCallActiveButton: IconButton {
|
groupCallActiveButton: IconButton {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
|
|
|
@ -16,10 +16,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/widgets/call_button.h"
|
#include "ui/widgets/call_button.h"
|
||||||
#include "ui/widgets/call_mute_button.h"
|
#include "ui/widgets/call_mute_button.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
|
#include "ui/widgets/dropdown_menu.h"
|
||||||
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/layers/layer_manager.h"
|
#include "ui/layers/layer_manager.h"
|
||||||
#include "ui/layers/generic_box.h"
|
#include "ui/layers/generic_box.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
|
#include "ui/special_buttons.h"
|
||||||
#include "info/profile/info_profile_values.h" // Info::Profile::Value.
|
#include "info/profile/info_profile_values.h" // Info::Profile::Value.
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
@ -31,6 +34,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "base/event_filter.h"
|
#include "base/event_filter.h"
|
||||||
|
#include "base/unixtime.h"
|
||||||
|
#include "base/timer_rpl.h"
|
||||||
#include "boxes/peers/edit_participants_box.h"
|
#include "boxes/peers/edit_participants_box.h"
|
||||||
#include "boxes/peers/add_participants_box.h"
|
#include "boxes/peers/add_participants_box.h"
|
||||||
#include "boxes/peer_lists_box.h"
|
#include "boxes/peer_lists_box.h"
|
||||||
|
@ -137,6 +142,81 @@ private:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditGroupCallTitleBox(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
const QString &placeholder,
|
||||||
|
const QString &title,
|
||||||
|
Fn<void(QString)> done) {
|
||||||
|
box->setTitle(tr::lng_group_call_edit_title());
|
||||||
|
const auto input = box->addRow(object_ptr<Ui::InputField>(
|
||||||
|
box,
|
||||||
|
st::groupCallField,
|
||||||
|
rpl::single(placeholder),
|
||||||
|
title));
|
||||||
|
box->setFocusCallback([=] {
|
||||||
|
input->setFocusFast();
|
||||||
|
});
|
||||||
|
box->addButton(tr::lng_settings_save(), [=] {
|
||||||
|
const auto result = input->getLastText().trimmed();
|
||||||
|
box->closeBox();
|
||||||
|
done(result);
|
||||||
|
});
|
||||||
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartGroupCallRecordingBox(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
const QString &title,
|
||||||
|
Fn<void(QString)> done) {
|
||||||
|
box->setTitle(tr::lng_group_call_recording_start());
|
||||||
|
|
||||||
|
box->addRow(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
box.get(),
|
||||||
|
tr::lng_group_call_recording_start_sure(),
|
||||||
|
st::groupCallBoxLabel));
|
||||||
|
|
||||||
|
const auto input = box->addRow(object_ptr<Ui::InputField>(
|
||||||
|
box,
|
||||||
|
st::groupCallField,
|
||||||
|
tr::lng_group_call_recording_start_field(),
|
||||||
|
title));
|
||||||
|
box->setFocusCallback([=] {
|
||||||
|
input->setFocusFast();
|
||||||
|
});
|
||||||
|
box->addButton(tr::lng_group_call_recording_start_button(), [=] {
|
||||||
|
const auto result = input->getLastText().trimmed();
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
input->showError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
box->closeBox();
|
||||||
|
done(result);
|
||||||
|
});
|
||||||
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopGroupCallRecordingBox(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
Fn<void(QString)> done) {
|
||||||
|
box->addRow(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
box.get(),
|
||||||
|
tr::lng_group_call_recording_stop_sure(),
|
||||||
|
st::groupCallBoxLabel),
|
||||||
|
style::margins(
|
||||||
|
st::boxRowPadding.left(),
|
||||||
|
st::boxPadding.top(),
|
||||||
|
st::boxRowPadding.right(),
|
||||||
|
st::boxPadding.bottom()));
|
||||||
|
|
||||||
|
box->addButton(tr::lng_box_ok(), [=] {
|
||||||
|
box->closeBox();
|
||||||
|
done(QString());
|
||||||
|
});
|
||||||
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
|
}
|
||||||
|
|
||||||
InviteController::InviteController(
|
InviteController::InviteController(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
base::flat_set<not_null<UserData*>> alreadyIn)
|
base::flat_set<not_null<UserData*>> alreadyIn)
|
||||||
|
@ -599,6 +679,7 @@ void GroupPanel::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||||
_recordingMark.destroy();
|
_recordingMark.destroy();
|
||||||
} else if (recording && !_recordingMark) {
|
} else if (recording && !_recordingMark) {
|
||||||
_recordingMark.create(widget());
|
_recordingMark.create(widget());
|
||||||
|
_recordingMark->show();
|
||||||
const auto size = st::groupCallRecordingMark;
|
const auto size = st::groupCallRecordingMark;
|
||||||
const auto skip = st::groupCallRecordingMarkSkip;
|
const auto skip = st::groupCallRecordingMarkSkip;
|
||||||
_recordingMark->resize(size + 2 * skip, size + 2 * skip);
|
_recordingMark->resize(size + 2 * skip, size + 2 * skip);
|
||||||
|
@ -631,8 +712,206 @@ void GroupPanel::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||||
(recorded
|
(recorded
|
||||||
? tr::lng_group_call_recording_started(tr::now)
|
? tr::lng_group_call_recording_started(tr::now)
|
||||||
: tr::lng_group_call_recording_stopped(tr::now)));
|
: tr::lng_group_call_recording_stopped(tr::now)));
|
||||||
}, _callLifetime);
|
}, widget()->lifetime());
|
||||||
validateRecordingMark(real->recordStartDate() != 0);
|
validateRecordingMark(real->recordStartDate() != 0);
|
||||||
|
|
||||||
|
const auto showMenu = _peer->canManageGroupCall();
|
||||||
|
const auto showUserpic = !showMenu
|
||||||
|
&& (_call->possibleJoinAs().size() > 1); // #TODO calls when to show
|
||||||
|
if (showMenu) {
|
||||||
|
_joinAsToggle.destroy();
|
||||||
|
if (!_menuToggle) {
|
||||||
|
_menuToggle.create(widget(), st::groupCallMenuToggle);
|
||||||
|
_menuToggle->show();
|
||||||
|
_menuToggle->setClickedCallback([=] { showMainMenu(); });
|
||||||
|
}
|
||||||
|
} else if (showUserpic) {
|
||||||
|
_menuToggle.destroy();
|
||||||
|
rpl::single(
|
||||||
|
_call->joinAs()
|
||||||
|
) | rpl::then(_call->rejoinEvents(
|
||||||
|
) | rpl::map([](const Group::RejoinEvent &event) {
|
||||||
|
return event.nowJoinAs;
|
||||||
|
})) | rpl::start_with_next([=](not_null<PeerData*> joinAs) {
|
||||||
|
auto joinAsToggle = object_ptr<Ui::UserpicButton>(
|
||||||
|
widget(),
|
||||||
|
joinAs,
|
||||||
|
Ui::UserpicButton::Role::Custom,
|
||||||
|
st::groupCallJoinAsToggle);
|
||||||
|
_joinAsToggle.destroy();
|
||||||
|
_joinAsToggle = std::move(joinAsToggle);
|
||||||
|
_joinAsToggle->show();
|
||||||
|
_joinAsToggle->setClickedCallback([=] {
|
||||||
|
chooseJoinAs();
|
||||||
|
});
|
||||||
|
}, widget()->lifetime());
|
||||||
|
} else {
|
||||||
|
_menuToggle.destroy();
|
||||||
|
_joinAsToggle.destroy();
|
||||||
|
}
|
||||||
|
updateControlsGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupPanel::chooseJoinAs() {
|
||||||
|
const auto context = Group::ChooseJoinAsProcess::Context::Switch;
|
||||||
|
const auto callback = [=](Group::JoinInfo info) {
|
||||||
|
if (_call) {
|
||||||
|
_call->rejoinAs(info);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auto showBox = [=](object_ptr<Ui::BoxContent> next) {
|
||||||
|
_layerBg->showBox(std::move(next));
|
||||||
|
};
|
||||||
|
const auto showToast = [=](QString text) {
|
||||||
|
Ui::Toast::Show(widget(), text);
|
||||||
|
};
|
||||||
|
_joinAsProcess.start(
|
||||||
|
_peer,
|
||||||
|
context,
|
||||||
|
showBox,
|
||||||
|
showToast,
|
||||||
|
callback,
|
||||||
|
_call->joinAs());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupPanel::showMainMenu() {
|
||||||
|
const auto real = _peer->groupCall();
|
||||||
|
if (_menu || !_call || !real || real->id() != _call->id()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_menu.create(widget(), st::groupCallDropdownMenu);
|
||||||
|
const auto raw = _menu.data();
|
||||||
|
raw->setHiddenCallback([=] {
|
||||||
|
raw->deleteLater();
|
||||||
|
if (_menu == raw) {
|
||||||
|
_menu = nullptr;
|
||||||
|
_menuToggle->setForceRippled(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
raw->setShowStartCallback([=] {
|
||||||
|
if (_menu == raw) {
|
||||||
|
_menuToggle->setForceRippled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
raw->setHideStartCallback([=] {
|
||||||
|
if (_menu == raw) {
|
||||||
|
_menuToggle->setForceRippled(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_menuToggle->installEventFilter(_menu);
|
||||||
|
|
||||||
|
const auto addEditJoinAs = (_call->possibleJoinAs().size() > 1); // #TODO calls when to show
|
||||||
|
const auto addEditTitle = _peer->canManageGroupCall();
|
||||||
|
const auto addEditRecording = _peer->canManageGroupCall();
|
||||||
|
if (addEditJoinAs) {
|
||||||
|
_menu->addAction(tr::lng_group_call_display_as_header(tr::now), [=] {
|
||||||
|
chooseJoinAs();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (addEditTitle) {
|
||||||
|
_menu->addAction(tr::lng_group_call_edit_title(tr::now), [=] {
|
||||||
|
const auto done = [=](const QString &title) {
|
||||||
|
if (_call) {
|
||||||
|
_call->changeTitle(title);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_layerBg->showBox(Box(
|
||||||
|
EditGroupCallTitleBox,
|
||||||
|
_peer->name,
|
||||||
|
real->title(),
|
||||||
|
done));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (addEditRecording) {
|
||||||
|
const auto action = _menu->addAction((real->recordStartDate() != 0)
|
||||||
|
? tr::lng_group_call_recording_stop(tr::now)
|
||||||
|
: tr::lng_group_call_recording_start(tr::now), [=] {
|
||||||
|
const auto real = _peer->groupCall();
|
||||||
|
const auto id = _call ? _call->id() : 0;
|
||||||
|
if (!real || real->id() != id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto recordStartDate = real->recordStartDate();
|
||||||
|
const auto done = [=](QString title) {
|
||||||
|
if (_call) {
|
||||||
|
_call->toggleRecording(!recordStartDate, title);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (recordStartDate) {
|
||||||
|
_layerBg->showBox(Box(
|
||||||
|
StopGroupCallRecordingBox,
|
||||||
|
done));
|
||||||
|
} else {
|
||||||
|
_layerBg->showBox(Box(
|
||||||
|
StartGroupCallRecordingBox,
|
||||||
|
real->title(),
|
||||||
|
done));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
static const auto ToDurationFrom = [](TimeId startDate) {
|
||||||
|
return [=] {
|
||||||
|
const auto now = base::unixtime::now();
|
||||||
|
const auto elapsed = std::max(now - startDate, 0);
|
||||||
|
const auto hours = elapsed / 3600;
|
||||||
|
const auto minutes = (elapsed % 3600) / 60;
|
||||||
|
const auto seconds = (elapsed % 60);
|
||||||
|
return hours
|
||||||
|
? QString("%1:%2:%3"
|
||||||
|
).arg(hours
|
||||||
|
).arg(minutes, 2, 10, QChar('0')
|
||||||
|
).arg(seconds, 2, 10, QChar('0'))
|
||||||
|
: QString("%1:%2"
|
||||||
|
).arg(minutes
|
||||||
|
).arg(seconds, 2, 10, QChar('0'));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static const auto ToRecordDuration = [](TimeId startDate) {
|
||||||
|
return !startDate
|
||||||
|
? (rpl::single(QString()) | rpl::type_erased())
|
||||||
|
: rpl::single(
|
||||||
|
rpl::empty_value()
|
||||||
|
) | rpl::then(base::timer_each(
|
||||||
|
crl::time(1000)
|
||||||
|
)) | rpl::map(ToDurationFrom(startDate));
|
||||||
|
};
|
||||||
|
rpl::combine(
|
||||||
|
real->recordStartDateValue(),
|
||||||
|
tr::lng_group_call_recording_stop(),
|
||||||
|
tr::lng_group_call_recording_start()
|
||||||
|
) | rpl::map([=](TimeId startDate, QString stop, QString start) {
|
||||||
|
using namespace rpl::mappers;
|
||||||
|
return startDate
|
||||||
|
? ToRecordDuration(
|
||||||
|
startDate
|
||||||
|
) | rpl::map(stop + '\t' + _1) : rpl::single(start);
|
||||||
|
}) | rpl::flatten_latest() | rpl::start_with_next([=](QString text) {
|
||||||
|
action->setText(text);
|
||||||
|
}, _menu->lifetime());
|
||||||
|
}
|
||||||
|
_menu->addAction(tr::lng_group_call_settings(tr::now), [=] {
|
||||||
|
if (_call) {
|
||||||
|
_layerBg->showBox(Box(GroupCallSettingsBox, _call));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_menu->addAction(tr::lng_group_call_end(tr::now), [=] {
|
||||||
|
if (_call) {
|
||||||
|
_layerBg->showBox(Box(
|
||||||
|
LeaveGroupCallBox,
|
||||||
|
_call,
|
||||||
|
true,
|
||||||
|
BoxContext::GroupCallPanel));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto x = st::groupCallMenuPosition.x();
|
||||||
|
const auto y = st::groupCallMenuPosition.y();
|
||||||
|
if (_menuToggle->x() > widget()->width() / 2) {
|
||||||
|
_menu->moveToRight(x, y);
|
||||||
|
_menu->showAnimated(Ui::PanelAnimation::Origin::TopRight);
|
||||||
|
} else {
|
||||||
|
_menu->moveToLeft(x, y);
|
||||||
|
_menu->showAnimated(Ui::PanelAnimation::Origin::TopLeft);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupPanel::addMembers() {
|
void GroupPanel::addMembers() {
|
||||||
|
@ -847,6 +1126,11 @@ void GroupPanel::initGeometry() {
|
||||||
|
|
||||||
QRect GroupPanel::computeTitleRect() const {
|
QRect GroupPanel::computeTitleRect() const {
|
||||||
const auto skip = st::groupCallTitleTop;
|
const auto skip = st::groupCallTitleTop;
|
||||||
|
const auto remove = skip + (_menuToggle
|
||||||
|
? (_menuToggle->width() + st::groupCallMenuTogglePosition.x())
|
||||||
|
: 0) + (_joinAsToggle
|
||||||
|
? (_joinAsToggle->width() + st::groupCallMenuTogglePosition.x())
|
||||||
|
: 0);
|
||||||
const auto width = widget()->width();
|
const auto width = widget()->width();
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
return QRect(70, 0, width - skip - 70, 28);
|
return QRect(70, 0, width - skip - 70, 28);
|
||||||
|
@ -854,8 +1138,8 @@ QRect GroupPanel::computeTitleRect() const {
|
||||||
const auto controls = _controls->geometry();
|
const auto controls = _controls->geometry();
|
||||||
const auto right = controls.x() + controls.width() + skip;
|
const auto right = controls.x() + controls.width() + skip;
|
||||||
return (controls.center().x() < width / 2)
|
return (controls.center().x() < width / 2)
|
||||||
? QRect(right, 0, width - right - skip, controls.height())
|
? QRect(right, 0, width - right - remove, controls.height())
|
||||||
: QRect(skip, 0, controls.x() - 2 * skip, controls.height());
|
: QRect(remove, 0, controls.x() - skip - remove, controls.height());
|
||||||
#endif // !Q_OS_MAC
|
#endif // !Q_OS_MAC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -893,6 +1177,28 @@ void GroupPanel::updateControlsGeometry() {
|
||||||
_settings->moveToLeft((widget()->width() - fullWidth) / 2, buttonsTop);
|
_settings->moveToLeft((widget()->width() - fullWidth) / 2, buttonsTop);
|
||||||
_hangup->moveToRight((widget()->width() - fullWidth) / 2, buttonsTop);
|
_hangup->moveToRight((widget()->width() - fullWidth) / 2, buttonsTop);
|
||||||
refreshTitle();
|
refreshTitle();
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
const auto controlsOnTheLeft = true;
|
||||||
|
#else // Q_OS_MAC
|
||||||
|
const auto controlsOnTheLeft = _controls->geometry().center().x()
|
||||||
|
< widget()->width() / 2;
|
||||||
|
#endif // Q_OS_MAC
|
||||||
|
const auto menux = st::groupCallMenuTogglePosition.x();
|
||||||
|
const auto menuy = st::groupCallMenuTogglePosition.y();
|
||||||
|
if (controlsOnTheLeft) {
|
||||||
|
if (_menuToggle) {
|
||||||
|
_menuToggle->moveToRight(menux, menuy);
|
||||||
|
} else if (_joinAsToggle) {
|
||||||
|
_joinAsToggle->moveToRight(menux, menuy);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_menuToggle) {
|
||||||
|
_menuToggle->moveToLeft(menux, menuy);
|
||||||
|
} else if (_joinAsToggle) {
|
||||||
|
_joinAsToggle->moveToLeft(menux, menuy);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupPanel::refreshTitle() {
|
void GroupPanel::refreshTitle() {
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
#include "base/object_ptr.h"
|
#include "base/object_ptr.h"
|
||||||
#include "calls/calls_group_call.h"
|
#include "calls/calls_group_call.h"
|
||||||
|
#include "calls/calls_choose_join_as.h"
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ class GroupCall;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class AbstractButton;
|
class AbstractButton;
|
||||||
|
class DropdownMenu;
|
||||||
class CallButton;
|
class CallButton;
|
||||||
class CallMuteButton;
|
class CallMuteButton;
|
||||||
class IconButton;
|
class IconButton;
|
||||||
|
@ -96,6 +98,8 @@ private:
|
||||||
|
|
||||||
void endCall();
|
void endCall();
|
||||||
|
|
||||||
|
void showMainMenu();
|
||||||
|
void chooseJoinAs();
|
||||||
void addMembers();
|
void addMembers();
|
||||||
void kickMember(not_null<UserData*> user);
|
void kickMember(not_null<UserData*> user);
|
||||||
void kickMemberSure(not_null<UserData*> user);
|
void kickMemberSure(not_null<UserData*> user);
|
||||||
|
@ -123,8 +127,12 @@ private:
|
||||||
object_ptr<Ui::FlatLabel> _title = { nullptr };
|
object_ptr<Ui::FlatLabel> _title = { nullptr };
|
||||||
object_ptr<Ui::FlatLabel> _subtitle = { nullptr };
|
object_ptr<Ui::FlatLabel> _subtitle = { nullptr };
|
||||||
object_ptr<Ui::AbstractButton> _recordingMark = { nullptr };
|
object_ptr<Ui::AbstractButton> _recordingMark = { nullptr };
|
||||||
|
object_ptr<Ui::IconButton> _menuToggle = { nullptr };
|
||||||
|
object_ptr<Ui::DropdownMenu> _menu = { nullptr };
|
||||||
|
object_ptr<Ui::AbstractButton> _joinAsToggle = { nullptr };
|
||||||
object_ptr<GroupMembers> _members;
|
object_ptr<GroupMembers> _members;
|
||||||
rpl::variable<QString> _titleText;
|
rpl::variable<QString> _titleText;
|
||||||
|
Group::ChooseJoinAsProcess _joinAsProcess;
|
||||||
|
|
||||||
object_ptr<Ui::CallButton> _settings;
|
object_ptr<Ui::CallButton> _settings;
|
||||||
std::unique_ptr<Ui::CallMuteButton> _mute;
|
std::unique_ptr<Ui::CallMuteButton> _mute;
|
||||||
|
|
|
@ -86,81 +86,6 @@ void SaveCallJoinMuted(
|
||||||
QString::number(delay / 1000., 'f', 2));
|
QString::number(delay / 1000., 'f', 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditGroupCallTitleBox(
|
|
||||||
not_null<Ui::GenericBox*> box,
|
|
||||||
const QString &placeholder,
|
|
||||||
const QString &title,
|
|
||||||
Fn<void(QString)> done) {
|
|
||||||
box->setTitle(tr::lng_group_call_edit_title());
|
|
||||||
const auto input = box->addRow(object_ptr<Ui::InputField>(
|
|
||||||
box,
|
|
||||||
st::groupCallField,
|
|
||||||
rpl::single(placeholder),
|
|
||||||
title));
|
|
||||||
box->setFocusCallback([=] {
|
|
||||||
input->setFocusFast();
|
|
||||||
});
|
|
||||||
box->addButton(tr::lng_settings_save(), [=] {
|
|
||||||
const auto result = input->getLastText().trimmed();
|
|
||||||
box->closeBox();
|
|
||||||
done(result);
|
|
||||||
});
|
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void StartGroupCallRecordingBox(
|
|
||||||
not_null<Ui::GenericBox*> box,
|
|
||||||
const QString &title,
|
|
||||||
Fn<void(QString)> done) {
|
|
||||||
box->setTitle(tr::lng_group_call_recording_start());
|
|
||||||
|
|
||||||
box->addRow(
|
|
||||||
object_ptr<Ui::FlatLabel>(
|
|
||||||
box.get(),
|
|
||||||
tr::lng_group_call_recording_start_sure(),
|
|
||||||
st::groupCallBoxLabel));
|
|
||||||
|
|
||||||
const auto input = box->addRow(object_ptr<Ui::InputField>(
|
|
||||||
box,
|
|
||||||
st::groupCallField,
|
|
||||||
tr::lng_group_call_recording_start_field(),
|
|
||||||
title));
|
|
||||||
box->setFocusCallback([=] {
|
|
||||||
input->setFocusFast();
|
|
||||||
});
|
|
||||||
box->addButton(tr::lng_group_call_recording_start_button(), [=] {
|
|
||||||
const auto result = input->getLastText().trimmed();
|
|
||||||
if (result.isEmpty()) {
|
|
||||||
input->showError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
box->closeBox();
|
|
||||||
done(result);
|
|
||||||
});
|
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void StopGroupCallRecordingBox(
|
|
||||||
not_null<Ui::GenericBox*> box,
|
|
||||||
Fn<void(QString)> done) {
|
|
||||||
box->addRow(
|
|
||||||
object_ptr<Ui::FlatLabel>(
|
|
||||||
box.get(),
|
|
||||||
tr::lng_group_call_recording_stop_sure(),
|
|
||||||
st::groupCallBoxLabel),
|
|
||||||
style::margins(
|
|
||||||
st::boxRowPadding.left(),
|
|
||||||
st::boxPadding.top(),
|
|
||||||
st::boxRowPadding.right(),
|
|
||||||
st::boxPadding.bottom()));
|
|
||||||
|
|
||||||
box->addButton(tr::lng_box_ok(), [=] {
|
|
||||||
box->closeBox();
|
|
||||||
done(QString());
|
|
||||||
});
|
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void GroupCallSettingsBox(
|
void GroupCallSettingsBox(
|
||||||
|
@ -179,7 +104,6 @@ void GroupCallSettingsBox(
|
||||||
float micLevel = 0.;
|
float micLevel = 0.;
|
||||||
Ui::Animations::Simple micLevelAnimation;
|
Ui::Animations::Simple micLevelAnimation;
|
||||||
base::Timer levelUpdateTimer;
|
base::Timer levelUpdateTimer;
|
||||||
Group::ChooseJoinAsProcess joinAsProcess;
|
|
||||||
bool generatingLink = false;
|
bool generatingLink = false;
|
||||||
};
|
};
|
||||||
const auto state = box->lifetime().make_state<State>();
|
const auto state = box->lifetime().make_state<State>();
|
||||||
|
@ -195,130 +119,16 @@ void GroupCallSettingsBox(
|
||||||
const auto joinMuted = goodReal ? real->joinMuted() : false;
|
const auto joinMuted = goodReal ? real->joinMuted() : false;
|
||||||
const auto canChangeJoinMuted = (goodReal && real->canChangeJoinMuted());
|
const auto canChangeJoinMuted = (goodReal && real->canChangeJoinMuted());
|
||||||
const auto addCheck = (peer->canManageGroupCall() && canChangeJoinMuted);
|
const auto addCheck = (peer->canManageGroupCall() && canChangeJoinMuted);
|
||||||
const auto addEditJoinAs = (call->possibleJoinAs().size() > 1); // #TODO calls when to show
|
if (addCheck) {
|
||||||
const auto addEditTitle = peer->canManageGroupCall() && goodReal;
|
|
||||||
const auto addEditRecording = peer->canManageGroupCall() && goodReal;
|
|
||||||
if (addCheck || addEditJoinAs) {
|
|
||||||
AddSkip(layout);
|
AddSkip(layout);
|
||||||
}
|
}
|
||||||
const auto editJoinAs = addEditJoinAs
|
|
||||||
? AddButton(
|
|
||||||
layout,
|
|
||||||
tr::lng_group_call_display_as_header(),
|
|
||||||
st::groupCallSettingsButton).get()
|
|
||||||
: nullptr;
|
|
||||||
const auto editTitle = addEditTitle
|
|
||||||
? AddButton(
|
|
||||||
layout,
|
|
||||||
tr::lng_group_call_edit_title(),
|
|
||||||
st::groupCallSettingsButton).get()
|
|
||||||
: nullptr;
|
|
||||||
static const auto ToDurationFrom = [](TimeId startDate) {
|
|
||||||
return [=] {
|
|
||||||
const auto now = base::unixtime::now();
|
|
||||||
const auto elapsed = std::max(now - startDate, 0);
|
|
||||||
const auto hours = elapsed / 3600;
|
|
||||||
const auto minutes = (elapsed % 3600) / 60;
|
|
||||||
const auto seconds = (elapsed % 60);
|
|
||||||
return hours
|
|
||||||
? QString("%1:%2:%3"
|
|
||||||
).arg(hours
|
|
||||||
).arg(minutes, 2, 10, QChar('0')
|
|
||||||
).arg(seconds, 2, 10, QChar('0'))
|
|
||||||
: QString("%1:%2"
|
|
||||||
).arg(minutes
|
|
||||||
).arg(seconds, 2, 10, QChar('0'));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
static const auto ToRecordDuration = [](TimeId startDate) {
|
|
||||||
return !startDate
|
|
||||||
? (rpl::single(QString()) | rpl::type_erased())
|
|
||||||
: rpl::single(
|
|
||||||
rpl::empty_value()
|
|
||||||
) | rpl::then(base::timer_each(
|
|
||||||
crl::time(1000)
|
|
||||||
)) | rpl::map(ToDurationFrom(startDate));
|
|
||||||
};
|
|
||||||
using namespace rpl::mappers;
|
|
||||||
const auto editRecording = !addEditRecording
|
|
||||||
? nullptr
|
|
||||||
: AddButtonWithLabel(
|
|
||||||
layout,
|
|
||||||
rpl::conditional(
|
|
||||||
real->recordStartDateValue() | rpl::map(!!_1),
|
|
||||||
tr::lng_group_call_recording_stop(),
|
|
||||||
tr::lng_group_call_recording_start()),
|
|
||||||
real->recordStartDateValue(
|
|
||||||
) | rpl::map(
|
|
||||||
ToRecordDuration
|
|
||||||
) | rpl::flatten_latest(),
|
|
||||||
st::groupCallSettingsButton).get();
|
|
||||||
if (editJoinAs) {
|
|
||||||
editJoinAs->setClickedCallback([=] {
|
|
||||||
const auto context = Group::ChooseJoinAsProcess::Context::Switch;
|
|
||||||
const auto callback = [=](Group::JoinInfo info) {
|
|
||||||
call->rejoinAs(info);
|
|
||||||
};
|
|
||||||
const auto showBox = [=](object_ptr<Ui::BoxContent> next) {
|
|
||||||
box->getDelegate()->show(std::move(next));
|
|
||||||
};
|
|
||||||
const auto showToast = [=](QString text) {
|
|
||||||
const auto container = box->getDelegate()->outerContainer();
|
|
||||||
Ui::Toast::Show(container, text);
|
|
||||||
};
|
|
||||||
state->joinAsProcess.start(
|
|
||||||
peer,
|
|
||||||
context,
|
|
||||||
showBox,
|
|
||||||
showToast,
|
|
||||||
callback,
|
|
||||||
call->joinAs());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (editTitle) {
|
|
||||||
editTitle->setClickedCallback([=] {
|
|
||||||
const auto done = [=](const QString &title) {
|
|
||||||
call->changeTitle(title);
|
|
||||||
box->closeBox();
|
|
||||||
};
|
|
||||||
box->getDelegate()->show(Box(
|
|
||||||
EditGroupCallTitleBox,
|
|
||||||
peer->name,
|
|
||||||
real->title(),
|
|
||||||
done));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (editRecording) {
|
|
||||||
editRecording->setClickedCallback([=] {
|
|
||||||
const auto real = peer->groupCall();
|
|
||||||
const auto id = call->id();
|
|
||||||
if (!real || real->id() != id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto recordStartDate = real->recordStartDate();
|
|
||||||
const auto done = [=](QString title) {
|
|
||||||
call->toggleRecording(!recordStartDate, title);
|
|
||||||
box->closeBox();
|
|
||||||
};
|
|
||||||
if (recordStartDate) {
|
|
||||||
box->getDelegate()->show(Box(
|
|
||||||
StopGroupCallRecordingBox,
|
|
||||||
done));
|
|
||||||
} else {
|
|
||||||
box->getDelegate()->show(Box(
|
|
||||||
StartGroupCallRecordingBox,
|
|
||||||
real->title(),
|
|
||||||
done));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const auto muteJoined = addCheck
|
const auto muteJoined = addCheck
|
||||||
? AddButton(
|
? AddButton(
|
||||||
layout,
|
layout,
|
||||||
tr::lng_group_call_new_muted(),
|
tr::lng_group_call_new_muted(),
|
||||||
st::groupCallSettingsButton)->toggleOn(rpl::single(joinMuted))
|
st::groupCallSettingsButton)->toggleOn(rpl::single(joinMuted))
|
||||||
: nullptr;
|
: nullptr;
|
||||||
if (addCheck || addEditJoinAs) {
|
if (addCheck) {
|
||||||
AddSkip(layout);
|
AddSkip(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ public:
|
||||||
const style::UserpicButton &st);
|
const style::UserpicButton &st);
|
||||||
UserpicButton(
|
UserpicButton(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<::Window::SessionController*> controller,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
Role role,
|
Role role,
|
||||||
const style::UserpicButton &st);
|
const style::UserpicButton &st);
|
||||||
|
@ -132,7 +132,7 @@ private:
|
||||||
void uploadNewPeerPhoto();
|
void uploadNewPeerPhoto();
|
||||||
|
|
||||||
const style::UserpicButton &_st;
|
const style::UserpicButton &_st;
|
||||||
Window::SessionController *_controller = nullptr;
|
::Window::SessionController *_controller = nullptr;
|
||||||
PeerData *_peer = nullptr;
|
PeerData *_peer = nullptr;
|
||||||
std::shared_ptr<Data::CloudImageView> _userpicView;
|
std::shared_ptr<Data::CloudImageView> _userpicView;
|
||||||
QString _cropTitle;
|
QString _cropTitle;
|
||||||
|
|
Loading…
Reference in New Issue