mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-01 12:00:48 +00:00
Improve scheduled voice chat top bar design.
This commit is contained in:
parent
088fda4ed8
commit
66e7f05df1
@ -1992,6 +1992,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_leave" = "Leave";
|
||||
"lng_group_call_leave_title" = "Leave voice chat";
|
||||
"lng_group_call_leave_sure" = "Are you sure you want to leave this voice chat?";
|
||||
"lng_group_call_close" = "Close";
|
||||
"lng_group_call_close_sure" = "Voice chat is scheduled. You can cancel it or just close this panel.";
|
||||
"lng_group_call_also_cancel" = "Cancel voice chat";
|
||||
"lng_group_call_leave_to_other_sure" = "Do you want to leave your active voice chat and join a voice chat in this group?";
|
||||
"lng_group_call_create_sure" = "Do you really want to start a voice chat in this group?";
|
||||
"lng_group_call_create_sure_channel" = "Are you sure you want to start a voice chat in this channel as your personal account?";
|
||||
@ -2022,6 +2025,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_copy_speaker_link" = "Copy Speaker Link";
|
||||
"lng_group_call_copy_listener_link" = "Copy Listener Link";
|
||||
"lng_group_call_end" = "End Voice Chat";
|
||||
"lng_group_call_cancel" = "Cancel Voice Chat";
|
||||
"lng_group_call_join" = "Join";
|
||||
"lng_group_call_join_confirm" = "Do you want to join the voice chat {chat}?";
|
||||
"lng_group_call_invite_done_user" = "You invited {user} to the voice chat.";
|
||||
@ -2069,6 +2073,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_starts_tomorrow" = "tomorrow at {time}";
|
||||
"lng_group_call_starts_date" = "{date} at {time}";
|
||||
"lng_group_call_starts_in" = "Starts in";
|
||||
"lng_group_call_start_now" = "Start Now";
|
||||
"lng_group_call_set_reminder" = "Set Reminder";
|
||||
"lng_group_call_cancel_reminder" = "Cancel Reminder";
|
||||
"lng_group_call_join_as_personal" = "personal account";
|
||||
|
@ -720,6 +720,11 @@ groupCallTopBarJoin: RoundButton(defaultActiveButton) {
|
||||
height: 26px;
|
||||
textTop: 4px;
|
||||
}
|
||||
groupCallTopBarOpen: RoundButton(groupCallTopBarJoin) {
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: shadowFg;
|
||||
}
|
||||
}
|
||||
groupCallBox: Box(defaultBox) {
|
||||
button: RoundButton(defaultBoxButton) {
|
||||
textFg: groupCallActiveFg;
|
||||
|
@ -152,17 +152,17 @@ void ScheduleGroupCallBox(
|
||||
const auto now = base::unixtime::now();
|
||||
const auto duration = (date - now);
|
||||
if (duration >= 24 * 60 * 60) {
|
||||
return tr::lng_signin_reset_days(
|
||||
return tr::lng_group_call_duration_days(
|
||||
tr::now,
|
||||
lt_count,
|
||||
duration / (24 * 60 * 60));
|
||||
} else if (duration >= 60 * 60) {
|
||||
return tr::lng_signin_reset_hours(
|
||||
return tr::lng_group_call_duration_hours(
|
||||
tr::now,
|
||||
lt_count,
|
||||
duration / (60 * 60));
|
||||
}
|
||||
return tr::lng_signin_reset_minutes(
|
||||
return tr::lng_group_call_duration_minutes(
|
||||
tr::now,
|
||||
lt_count,
|
||||
std::max(duration / 60, 1));
|
||||
|
@ -234,9 +234,9 @@ GroupCall::GroupCall(
|
||||
return not_null{ real };
|
||||
}) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](not_null<Data::GroupCall*> call) {
|
||||
) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) {
|
||||
subscribeToReal(real);
|
||||
_realChanges.fire_copy(call);
|
||||
_realChanges.fire_copy(real);
|
||||
}, _lifetime);
|
||||
}
|
||||
if (_id) {
|
||||
|
@ -514,15 +514,6 @@ base::unique_qptr<Ui::Menu::ItemBase> MakeRecordingAction(
|
||||
std::move(callback));
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::Menu::ItemBase> MakeFinishAction(
|
||||
not_null<Ui::Menu::Menu*> menu,
|
||||
Fn<void()> callback) {
|
||||
return MakeAttentionAction(
|
||||
menu,
|
||||
tr::lng_group_call_end(tr::now),
|
||||
std::move(callback));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void LeaveBox(
|
||||
@ -530,16 +521,25 @@ void LeaveBox(
|
||||
not_null<GroupCall*> call,
|
||||
bool discardChecked,
|
||||
BoxContext context) {
|
||||
const auto scheduled = (call->scheduleDate() != 0);
|
||||
if (!scheduled) {
|
||||
box->setTitle(tr::lng_group_call_leave_title());
|
||||
}
|
||||
const auto inCall = (context == BoxContext::GroupCallPanel);
|
||||
box->addRow(object_ptr<Ui::FlatLabel>(
|
||||
box->addRow(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box.get(),
|
||||
tr::lng_group_call_leave_sure(),
|
||||
(inCall ? st::groupCallBoxLabel : st::boxLabel)));
|
||||
(scheduled
|
||||
? tr::lng_group_call_close_sure()
|
||||
: tr::lng_group_call_leave_sure()),
|
||||
(inCall ? st::groupCallBoxLabel : st::boxLabel)),
|
||||
scheduled ? st::boxPadding : st::boxRowPadding);
|
||||
const auto discard = call->peer()->canManageGroupCall()
|
||||
? box->addRow(object_ptr<Ui::Checkbox>(
|
||||
box.get(),
|
||||
tr::lng_group_call_end(),
|
||||
(scheduled
|
||||
? tr::lng_group_call_also_cancel()
|
||||
: tr::lng_group_call_also_end()),
|
||||
discardChecked,
|
||||
(inCall ? st::groupCallCheckbox : st::defaultBoxCheckbox),
|
||||
(inCall ? st::groupCallCheck : st::defaultCheck)),
|
||||
@ -550,7 +550,10 @@ void LeaveBox(
|
||||
st::boxRowPadding.bottom()))
|
||||
: nullptr;
|
||||
const auto weak = base::make_weak(call.get());
|
||||
box->addButton(tr::lng_group_call_leave(), [=] {
|
||||
auto label = scheduled
|
||||
? tr::lng_group_call_close()
|
||||
: tr::lng_group_call_leave();
|
||||
box->addButton(std::move(label), [=] {
|
||||
const auto discardCall = (discard && discard->checked());
|
||||
box->closeBox();
|
||||
|
||||
@ -603,7 +606,8 @@ void FillMenu(
|
||||
|
||||
const auto addEditJoinAs = call->showChooseJoinAs();
|
||||
const auto addEditTitle = peer->canManageGroupCall();
|
||||
const auto addEditRecording = peer->canManageGroupCall();
|
||||
const auto addEditRecording = peer->canManageGroupCall()
|
||||
&& !real->scheduleDate();
|
||||
if (addEditJoinAs) {
|
||||
menu->addAction(MakeJoinAsAction(
|
||||
menu->menu(),
|
||||
@ -660,7 +664,7 @@ void FillMenu(
|
||||
showBox(Box(SettingsBox, strong));
|
||||
}
|
||||
});
|
||||
menu->addAction(MakeFinishAction(menu->menu(), [=] {
|
||||
const auto finish = [=] {
|
||||
if (const auto strong = weak.get()) {
|
||||
showBox(Box(
|
||||
LeaveBox,
|
||||
@ -668,7 +672,13 @@ void FillMenu(
|
||||
true,
|
||||
BoxContext::GroupCallPanel));
|
||||
}
|
||||
}));
|
||||
};
|
||||
menu->addAction(MakeAttentionAction(
|
||||
menu->menu(),
|
||||
(real->scheduleDate()
|
||||
? tr::lng_group_call_cancel(tr::now)
|
||||
: tr::lng_group_call_end(tr::now)),
|
||||
finish));
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::Menu::ItemBase> MakeAttentionAction(
|
||||
|
@ -266,7 +266,7 @@ Panel::Panel(not_null<GroupCall*> call)
|
||||
Core::App().appDeactivatedValue(),
|
||||
Ui::CallMuteButtonState{
|
||||
.text = (_call->scheduleDate()
|
||||
? "Start Now" // #TODO voice chats
|
||||
? tr::lng_group_call_start_now(tr::now)
|
||||
: tr::lng_group_call_connecting(tr::now)),
|
||||
.type = (_call->scheduleDate()
|
||||
? Ui::CallMuteButtonType::ScheduledCanStart
|
||||
@ -451,7 +451,20 @@ void Panel::initControls() {
|
||||
});
|
||||
|
||||
_settings->setText(tr::lng_group_call_settings());
|
||||
const auto scheduled = (_call->scheduleDate() != 0);
|
||||
_hangup->setText(scheduled
|
||||
? tr::lng_group_call_close()
|
||||
: tr::lng_group_call_leave());
|
||||
if (scheduled) {
|
||||
_call->real(
|
||||
) | rpl::map([=](not_null<Data::GroupCall*> real) {
|
||||
return real->scheduleDateValue();
|
||||
}) | rpl::flatten_latest() | rpl::filter([](TimeId date) {
|
||||
return (date == 0);
|
||||
}) | rpl::take(1) | rpl::start_with_next([=] {
|
||||
_hangup->setText(tr::lng_group_call_leave());
|
||||
}, _callLifetime);
|
||||
}
|
||||
|
||||
_call->stateValue(
|
||||
) | rpl::filter([](State state) {
|
||||
@ -497,10 +510,10 @@ void Panel::setupRealMuteButtonState(not_null<Data::GroupCall*> real) {
|
||||
_mute->setState(Ui::CallMuteButtonState{
|
||||
.text = (scheduleDate
|
||||
? (canManage
|
||||
? "Start Now" // #TODO voice chats
|
||||
? tr::lng_group_call_start_now(tr::now)
|
||||
: scheduleStartSubscribed
|
||||
? "Cancel Reminder"
|
||||
: "Set Reminder")
|
||||
? tr::lng_group_call_cancel_reminder(tr::now)
|
||||
: tr::lng_group_call_set_reminder(tr::now))
|
||||
: state == GroupCall::InstanceState::Disconnected
|
||||
? tr::lng_group_call_connecting(tr::now)
|
||||
: mute == MuteState::ForceMuted
|
||||
|
@ -122,6 +122,9 @@ private:
|
||||
object_ptr<Ui::DropdownMenu> _menu = { nullptr };
|
||||
object_ptr<Ui::AbstractButton> _joinAsToggle = { nullptr };
|
||||
object_ptr<Members> _members = { nullptr };
|
||||
object_ptr<Ui::FlatLabel> _startsIn = { nullptr };
|
||||
object_ptr<Ui::RpWidget> _countdown = { nullptr };
|
||||
object_ptr<Ui::FlatLabel> _startsWhen = { nullptr };
|
||||
ChooseJoinAsProcess _joinAsProcess;
|
||||
|
||||
object_ptr<Ui::CallButton> _settings;
|
||||
|
@ -57,8 +57,13 @@ constexpr auto kHideBlobsDuration = crl::time(500);
|
||||
constexpr auto kBlobLevelDuration = crl::time(250);
|
||||
constexpr auto kBlobUpdateInterval = crl::time(100);
|
||||
|
||||
auto BarStateFromMuteState(MuteState state, GroupCall::InstanceState instanceState) {
|
||||
return (instanceState == GroupCall::InstanceState::Disconnected)
|
||||
auto BarStateFromMuteState(
|
||||
MuteState state,
|
||||
GroupCall::InstanceState instanceState,
|
||||
TimeId scheduledDate) {
|
||||
return scheduledDate
|
||||
? BarState::ForceMuted
|
||||
: (instanceState == GroupCall::InstanceState::Disconnected)
|
||||
? BarState::Connecting
|
||||
: (state == MuteState::ForceMuted || state == MuteState::RaisedHand)
|
||||
? BarState::ForceMuted
|
||||
@ -293,19 +298,27 @@ void TopBar::initControls() {
|
||||
_call
|
||||
? mapToState(_call->muted())
|
||||
: _groupCall->muted(),
|
||||
GroupCall::InstanceState::Connected));
|
||||
GroupCall::InstanceState::Connected,
|
||||
_call ? TimeId(0) : _groupCall->scheduleDate()));
|
||||
using namespace rpl::mappers;
|
||||
auto muted = _call
|
||||
? rpl::combine(
|
||||
_call->mutedValue() | rpl::map(mapToState),
|
||||
rpl::single(GroupCall::InstanceState::Connected)
|
||||
rpl::single(GroupCall::InstanceState::Connected),
|
||||
rpl::single(TimeId(0))
|
||||
) | rpl::type_erased()
|
||||
: rpl::combine(
|
||||
(_groupCall->mutedValue()
|
||||
| MapPushToTalkToActive()
|
||||
| rpl::distinct_until_changed()
|
||||
| rpl::type_erased()),
|
||||
_groupCall->instanceStateValue()
|
||||
_groupCall->instanceStateValue(),
|
||||
rpl::single(
|
||||
_groupCall->scheduleDate()
|
||||
) | rpl::then(_groupCall->real(
|
||||
) | rpl::map([](not_null<Data::GroupCall*> call) {
|
||||
return call->scheduleDateValue();
|
||||
}) | rpl::flatten_latest())
|
||||
) | rpl::filter(_2 != GroupCall::InstanceState::TransitionToRtc);
|
||||
std::move(
|
||||
muted
|
||||
|
@ -1025,12 +1025,15 @@ void History::applyServiceChanges(
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_messageActionGroupCall: {
|
||||
const auto &d = action.c_messageActionGroupCall();
|
||||
case mtpc_messageActionGroupCall:
|
||||
case mtpc_messageActionGroupCallScheduled: {
|
||||
const auto &call = (action.type() == mtpc_messageActionGroupCall)
|
||||
? action.c_messageActionGroupCall().vcall()
|
||||
: action.c_messageActionGroupCallScheduled().vcall();
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
channel->setGroupCall(d.vcall());
|
||||
channel->setGroupCall(call);
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
chat->setGroupCall(d.vcall());
|
||||
chat->setGroupCall(call);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
@ -21,16 +21,84 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Ui {
|
||||
|
||||
GroupCallScheduledLeft::GroupCallScheduledLeft(TimeId date)
|
||||
: _date(date)
|
||||
, _datePrecise(computePreciseDate())
|
||||
, _timer([=] { update(); }) {
|
||||
update();
|
||||
base::unixtime::updates(
|
||||
) | rpl::start_with_next([=] {
|
||||
restart();
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
crl::time GroupCallScheduledLeft::computePreciseDate() const {
|
||||
return crl::now() + (_date - base::unixtime::now()) * crl::time(1000);
|
||||
}
|
||||
|
||||
void GroupCallScheduledLeft::setDate(TimeId date) {
|
||||
if (_date == date) {
|
||||
return;
|
||||
}
|
||||
_date = date;
|
||||
restart();
|
||||
}
|
||||
|
||||
void GroupCallScheduledLeft::restart() {
|
||||
_datePrecise = computePreciseDate();
|
||||
_timer.cancel();
|
||||
update();
|
||||
}
|
||||
|
||||
rpl::producer<QString> GroupCallScheduledLeft::text() const {
|
||||
return _text.value();
|
||||
}
|
||||
|
||||
void GroupCallScheduledLeft::update() {
|
||||
const auto now = crl::now();
|
||||
const auto duration = (_datePrecise - now);
|
||||
const auto left = crl::time(std::round(std::abs(duration) / 1000.));
|
||||
constexpr auto kDay = 24 * 60 * 60;
|
||||
if (left >= kDay) {
|
||||
const auto days = ((left / kDay) + 1);
|
||||
_text = tr::lng_group_call_duration_days(
|
||||
tr::now,
|
||||
lt_count,
|
||||
(duration < 0) ? (-days) : days);
|
||||
} else {
|
||||
const auto hours = left / (60 * 60);
|
||||
const auto minutes = (left % (60 * 60)) / 60;
|
||||
const auto seconds = (left % 60);
|
||||
if (hours > 0) {
|
||||
_text = (duration < 0 ? u"\x2212%1:%2:%3"_q : u"%1:%2:%3"_q)
|
||||
.arg(hours, 2, 10, QChar('0'))
|
||||
.arg(minutes, 2, 10, QChar('0'))
|
||||
.arg(seconds, 2, 10, QChar('0'));
|
||||
} else {
|
||||
_text = (duration < 0 && left > 0 ? u"\x2212%1:%2"_q : u"%1:%2"_q)
|
||||
.arg(minutes, 2, 10, QChar('0'))
|
||||
.arg(seconds, 2, 10, QChar('0'));
|
||||
}
|
||||
}
|
||||
if (left >= kDay) {
|
||||
_timer.callOnce((left % kDay) * crl::time(1000));
|
||||
} else {
|
||||
const auto fraction = (std::abs(duration) + 500) % 1000;
|
||||
if (fraction < 400 || fraction > 600) {
|
||||
const auto next = std::abs(duration) % 1000;
|
||||
_timer.callOnce((duration < 0) ? (1000 - next) : next);
|
||||
} else if (!_timer.isActive()) {
|
||||
_timer.callEach(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GroupCallBar::GroupCallBar(
|
||||
not_null<QWidget*> parent,
|
||||
rpl::producer<GroupCallBarContent> content,
|
||||
rpl::producer<bool> &&hideBlobs)
|
||||
: _wrap(parent, object_ptr<RpWidget>(parent))
|
||||
, _inner(_wrap.entity())
|
||||
, _join(std::make_unique<RoundButton>(
|
||||
_inner.get(),
|
||||
tr::lng_group_call_join(),
|
||||
st::groupCallTopBarJoin))
|
||||
, _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget()))
|
||||
, _userpics(std::make_unique<GroupCallUserpics>(
|
||||
st::historyGroupCallUserpics,
|
||||
@ -55,6 +123,7 @@ GroupCallBar::GroupCallBar(
|
||||
_content = content;
|
||||
_userpics->update(_content.users, !_wrap.isHidden());
|
||||
_inner->update();
|
||||
refreshScheduledProcess();
|
||||
}, lifetime());
|
||||
|
||||
std::move(
|
||||
@ -76,6 +145,54 @@ GroupCallBar::GroupCallBar(
|
||||
|
||||
GroupCallBar::~GroupCallBar() = default;
|
||||
|
||||
void GroupCallBar::refreshOpenBrush() {
|
||||
Expects(_open != nullptr);
|
||||
|
||||
const auto width = _open->width();
|
||||
if (_openBrushForWidth == width) {
|
||||
return;
|
||||
}
|
||||
auto gradient = QLinearGradient(QPoint(width, 0), QPoint(-width, 0));
|
||||
gradient.setStops(QGradientStops{
|
||||
{ 0.0, st::groupCallForceMutedBar1->c },
|
||||
{ .35, st::groupCallForceMutedBar2->c },
|
||||
{ 1.0, st::groupCallForceMutedBar3->c }
|
||||
});
|
||||
_openBrushOverride = QBrush(std::move(gradient));
|
||||
_openBrushForWidth = width;
|
||||
_open->setBrushOverride(_openBrushOverride);
|
||||
}
|
||||
|
||||
void GroupCallBar::refreshScheduledProcess() {
|
||||
const auto date = _content.scheduleDate;
|
||||
if (!date) {
|
||||
if (_scheduledProcess) {
|
||||
_scheduledProcess = nullptr;
|
||||
_open = nullptr;
|
||||
_join = std::make_unique<RoundButton>(
|
||||
_inner.get(),
|
||||
tr::lng_group_call_join(),
|
||||
st::groupCallTopBarJoin);
|
||||
setupRightButton(_join.get());
|
||||
}
|
||||
return;
|
||||
} else if (!_scheduledProcess) {
|
||||
_scheduledProcess = std::make_unique<GroupCallScheduledLeft>(date);
|
||||
_join = nullptr;
|
||||
_open = std::make_unique<RoundButton>(
|
||||
_inner.get(),
|
||||
_scheduledProcess->text(),
|
||||
st::groupCallTopBarOpen);
|
||||
setupRightButton(_open.get());
|
||||
_open->widthValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshOpenBrush();
|
||||
}, _open->lifetime());
|
||||
} else {
|
||||
_scheduledProcess->setDate(date);
|
||||
}
|
||||
}
|
||||
|
||||
void GroupCallBar::setupInner() {
|
||||
_inner->resize(0, st::historyReplyHeight);
|
||||
_inner->paintRequest(
|
||||
@ -102,17 +219,6 @@ void GroupCallBar::setupInner() {
|
||||
return rpl::empty_value();
|
||||
}) | rpl::start_to_stream(_barClicks, _inner->lifetime());
|
||||
|
||||
rpl::combine(
|
||||
_inner->widthValue(),
|
||||
_join->widthValue()
|
||||
) | rpl::start_with_next([=](int outerWidth, int) {
|
||||
// Skip shadow of the bar above.
|
||||
const auto top = (st::historyReplyHeight
|
||||
- st::lineWidth
|
||||
- _join->height()) / 2 + st::lineWidth;
|
||||
_join->moveToRight(top, top, outerWidth);
|
||||
}, _join->lifetime());
|
||||
|
||||
_wrap.geometryValue(
|
||||
) | rpl::start_with_next([=](QRect rect) {
|
||||
updateShadowGeometry(rect);
|
||||
@ -120,6 +226,21 @@ void GroupCallBar::setupInner() {
|
||||
}, _inner->lifetime());
|
||||
}
|
||||
|
||||
void GroupCallBar::setupRightButton(not_null<RoundButton*> button) {
|
||||
rpl::combine(
|
||||
_inner->widthValue(),
|
||||
button->widthValue()
|
||||
) | rpl::start_with_next([=](int outerWidth, int) {
|
||||
// Skip shadow of the bar above.
|
||||
const auto top = (st::historyReplyHeight
|
||||
- st::lineWidth
|
||||
- button->height()) / 2 + st::lineWidth;
|
||||
button->moveToRight(top, top, outerWidth);
|
||||
}, button->lifetime());
|
||||
|
||||
button->clicks() | rpl::start_to_stream(_joinClicks, button->lifetime());
|
||||
}
|
||||
|
||||
void GroupCallBar::paint(Painter &p) {
|
||||
p.fillRect(_inner->rect(), st::historyComposeAreaBg);
|
||||
|
||||
@ -131,7 +252,7 @@ void GroupCallBar::paint(Painter &p) {
|
||||
p.setPen(st::defaultMessageBar.textFg);
|
||||
p.setFont(font);
|
||||
|
||||
const auto available = _join->x() - left;
|
||||
const auto available = (_join ? _join->x() : _open->x()) - left;
|
||||
const auto titleWidth = font->width(_content.title);
|
||||
p.drawTextLeft(
|
||||
left,
|
||||
@ -279,7 +400,7 @@ rpl::producer<> GroupCallBar::barClicks() const {
|
||||
}
|
||||
|
||||
rpl::producer<> GroupCallBar::joinClicks() const {
|
||||
return _join->clicks() | rpl::to_empty;
|
||||
return _joinClicks.events() | rpl::to_empty;
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "base/object_ptr.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
class Painter;
|
||||
|
||||
@ -28,6 +29,27 @@ struct GroupCallBarContent {
|
||||
std::vector<GroupCallUser> users;
|
||||
};
|
||||
|
||||
class GroupCallScheduledLeft final {
|
||||
public:
|
||||
explicit GroupCallScheduledLeft(TimeId date);
|
||||
|
||||
void setDate(TimeId date);
|
||||
|
||||
[[nodiscard]] rpl::producer<QString> text() const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] crl::time computePreciseDate() const;
|
||||
void restart();
|
||||
void update();
|
||||
|
||||
rpl::variable<QString> _text;
|
||||
TimeId _date = 0;
|
||||
crl::time _datePrecise = 0;
|
||||
base::Timer _timer;
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
class GroupCallBar final {
|
||||
public:
|
||||
GroupCallBar(
|
||||
@ -57,15 +79,22 @@ public:
|
||||
private:
|
||||
using User = GroupCallUser;
|
||||
|
||||
void refreshOpenBrush();
|
||||
void refreshScheduledProcess();
|
||||
void updateShadowGeometry(QRect wrapGeometry);
|
||||
void updateControlsGeometry(QRect wrapGeometry);
|
||||
void updateUserpics();
|
||||
void setupInner();
|
||||
void setupRightButton(not_null<RoundButton*> button);
|
||||
void paint(Painter &p);
|
||||
|
||||
SlideWrap<> _wrap;
|
||||
not_null<RpWidget*> _inner;
|
||||
std::unique_ptr<RoundButton> _join;
|
||||
std::unique_ptr<RoundButton> _open;
|
||||
rpl::event_stream<Qt::MouseButton> _joinClicks;
|
||||
QBrush _openBrushOverride;
|
||||
int _openBrushForWidth = 0;
|
||||
std::unique_ptr<PlainShadow> _shadow;
|
||||
rpl::event_stream<> _barClicks;
|
||||
Fn<QRect(QRect)> _shadowGeometryPostprocess;
|
||||
@ -73,6 +102,7 @@ private:
|
||||
bool _forceHidden = false;
|
||||
|
||||
GroupCallBarContent _content;
|
||||
std::unique_ptr<GroupCallScheduledLeft> _scheduledProcess;
|
||||
std::unique_ptr<GroupCallUserpics> _userpics;
|
||||
|
||||
};
|
||||
|
@ -1003,6 +1003,8 @@ void SessionController::startOrJoinGroupCall(
|
||||
&& calls.inGroupCall()) {
|
||||
if (calls.currentGroupCall()->peer() == peer) {
|
||||
calls.activateCurrentCall(joinHash);
|
||||
} else if (calls.currentGroupCall()->scheduleDate()) {
|
||||
calls.startOrJoinGroupCall(peer, joinHash);
|
||||
} else {
|
||||
askConfirmation(
|
||||
tr::lng_group_call_leave_to_other_sure(tr::now),
|
||||
|
Loading…
Reference in New Issue
Block a user