Correctly track mute button scheduled state.
This commit is contained in:
parent
15d17c8b0e
commit
088fda4ed8
|
@ -184,6 +184,7 @@ GroupCall::GroupCall(
|
||||||
, _joinAs(info.joinAs)
|
, _joinAs(info.joinAs)
|
||||||
, _possibleJoinAs(std::move(info.possibleJoinAs))
|
, _possibleJoinAs(std::move(info.possibleJoinAs))
|
||||||
, _joinHash(info.joinHash)
|
, _joinHash(info.joinHash)
|
||||||
|
, _id(inputCall.c_inputGroupCall().vid().v)
|
||||||
, _scheduleDate(info.scheduleDate)
|
, _scheduleDate(info.scheduleDate)
|
||||||
, _lastSpokeCheckTimer([=] { checkLastSpoke(); })
|
, _lastSpokeCheckTimer([=] { checkLastSpoke(); })
|
||||||
, _checkJoinedTimer([=] { checkJoined(); })
|
, _checkJoinedTimer([=] { checkJoined(); })
|
||||||
|
@ -216,14 +217,29 @@ GroupCall::GroupCall(
|
||||||
|
|
||||||
checkGlobalShortcutAvailability();
|
checkGlobalShortcutAvailability();
|
||||||
|
|
||||||
const auto id = inputCall.c_inputGroupCall().vid().v;
|
if (const auto real = lookupReal()) {
|
||||||
if (id) {
|
subscribeToReal(real);
|
||||||
if (const auto call = _peer->groupCall(); call && call->id() == id) {
|
if (!_peer->canManageGroupCall() && real->joinMuted()) {
|
||||||
_scheduleDate = call->scheduleDate();
|
_muted = MuteState::ForceMuted;
|
||||||
if (!_peer->canManageGroupCall() && call->joinMuted()) {
|
|
||||||
_muted = MuteState::ForceMuted;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
_peer->session().changes().peerFlagsValue(
|
||||||
|
_peer,
|
||||||
|
Data::PeerUpdate::Flag::GroupCall
|
||||||
|
) | rpl::map([=] {
|
||||||
|
return lookupReal();
|
||||||
|
}) | rpl::filter([](Data::GroupCall *real) {
|
||||||
|
return real != nullptr;
|
||||||
|
}) | rpl::map([](Data::GroupCall *real) {
|
||||||
|
return not_null{ real };
|
||||||
|
}) | rpl::take(
|
||||||
|
1
|
||||||
|
) | rpl::start_with_next([=](not_null<Data::GroupCall*> call) {
|
||||||
|
subscribeToReal(real);
|
||||||
|
_realChanges.fire_copy(call);
|
||||||
|
}, _lifetime);
|
||||||
|
}
|
||||||
|
if (_id) {
|
||||||
join(inputCall);
|
join(inputCall);
|
||||||
} else {
|
} else {
|
||||||
start(info.scheduleDate);
|
start(info.scheduleDate);
|
||||||
|
@ -250,6 +266,17 @@ GroupCall::~GroupCall() {
|
||||||
destroyController();
|
destroyController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
|
||||||
|
real->scheduleDateValue(
|
||||||
|
) | rpl::start_with_next([=](TimeId date) {
|
||||||
|
const auto was = _scheduleDate;
|
||||||
|
_scheduleDate = date;
|
||||||
|
if (was && !date) {
|
||||||
|
join(inputCall());
|
||||||
|
}
|
||||||
|
}, _lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
void GroupCall::checkGlobalShortcutAvailability() {
|
void GroupCall::checkGlobalShortcutAvailability() {
|
||||||
auto &settings = Core::App().settings();
|
auto &settings = Core::App().settings();
|
||||||
if (!settings.groupCallPushToTalk()) {
|
if (!settings.groupCallPushToTalk()) {
|
||||||
|
@ -327,6 +354,18 @@ bool GroupCall::showChooseJoinAs() const {
|
||||||
&& !_possibleJoinAs.front()->isSelf());
|
&& !_possibleJoinAs.front()->isSelf());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Data::GroupCall *GroupCall::lookupReal() const {
|
||||||
|
const auto real = _peer->groupCall();
|
||||||
|
return (real && real->id() == _id) ? real : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<not_null<Data::GroupCall*>> GroupCall::real() const {
|
||||||
|
if (const auto real = lookupReal()) {
|
||||||
|
return rpl::single(not_null{ real });
|
||||||
|
}
|
||||||
|
return _realChanges.events();
|
||||||
|
}
|
||||||
|
|
||||||
void GroupCall::start(TimeId scheduleDate) {
|
void GroupCall::start(TimeId scheduleDate) {
|
||||||
using Flag = MTPphone_CreateGroupCall::Flag;
|
using Flag = MTPphone_CreateGroupCall::Flag;
|
||||||
_createRequestId = _api.request(MTPphone_CreateGroupCall(
|
_createRequestId = _api.request(MTPphone_CreateGroupCall(
|
||||||
|
@ -699,6 +738,29 @@ void GroupCall::finish(FinishType type) {
|
||||||
})).send();
|
})).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GroupCall::startScheduledNow() {
|
||||||
|
if (!lookupReal()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_api.request(MTPphone_StartScheduledGroupCall(
|
||||||
|
inputCall()
|
||||||
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
_peer->session().api().applyUpdates(result);
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupCall::toggleScheduleStartSubscribed(bool subscribed) {
|
||||||
|
if (!lookupReal()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_api.request(MTPphone_ToggleGroupCallStartSubscription(
|
||||||
|
inputCall(),
|
||||||
|
MTP_bool(subscribed)
|
||||||
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
_peer->session().api().applyUpdates(result);
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
void GroupCall::setMuted(MuteState mute) {
|
void GroupCall::setMuted(MuteState mute) {
|
||||||
const auto set = [=] {
|
const auto set = [=] {
|
||||||
const auto wasMuted = (muted() == MuteState::Muted)
|
const auto wasMuted = (muted() == MuteState::Muted)
|
||||||
|
@ -744,6 +806,8 @@ void GroupCall::handlePossibleCreateOrJoinResponse(
|
||||||
const MTPDgroupCall &data) {
|
const MTPDgroupCall &data) {
|
||||||
if (const auto date = data.vschedule_date()) {
|
if (const auto date = data.vschedule_date()) {
|
||||||
_scheduleDate = date->v;
|
_scheduleDate = date->v;
|
||||||
|
} else {
|
||||||
|
_scheduleDate = 0;
|
||||||
}
|
}
|
||||||
if (_acceptFields) {
|
if (_acceptFields) {
|
||||||
if (!_instance && !_id) {
|
if (!_instance && !_id) {
|
||||||
|
@ -841,10 +905,8 @@ void GroupCall::handlePossibleDiscarded(const MTPDgroupCallDiscarded &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::addParticipantsToInstance() {
|
void GroupCall::addParticipantsToInstance() {
|
||||||
const auto real = _peer->groupCall();
|
const auto real = lookupReal();
|
||||||
if (!real
|
if (!real || (_instanceMode == InstanceMode::None)) {
|
||||||
|| (real->id() != _id)
|
|
||||||
|| (_instanceMode == InstanceMode::None)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const auto &participant : real->participants()) {
|
for (const auto &participant : real->participants()) {
|
||||||
|
@ -866,7 +928,7 @@ void GroupCall::addPreparedParticipants() {
|
||||||
if (!_preparedParticipants.empty()) {
|
if (!_preparedParticipants.empty()) {
|
||||||
_instance->addParticipants(base::take(_preparedParticipants));
|
_instance->addParticipants(base::take(_preparedParticipants));
|
||||||
}
|
}
|
||||||
if (const auto real = _peer->groupCall(); real && real->id() == _id) {
|
if (const auto real = lookupReal()) {
|
||||||
if (!_unresolvedSsrcs.empty()) {
|
if (!_unresolvedSsrcs.empty()) {
|
||||||
real->resolveParticipants(base::take(_unresolvedSsrcs));
|
real->resolveParticipants(base::take(_unresolvedSsrcs));
|
||||||
}
|
}
|
||||||
|
@ -989,8 +1051,8 @@ void GroupCall::handleUpdate(const MTPDupdateGroupCallParticipants &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::changeTitle(const QString &title) {
|
void GroupCall::changeTitle(const QString &title) {
|
||||||
const auto real = _peer->groupCall();
|
const auto real = lookupReal();
|
||||||
if (!real || real->id() != _id || real->title() == title) {
|
if (!real || real->title() == title) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,8 +1067,8 @@ void GroupCall::changeTitle(const QString &title) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::toggleRecording(bool enabled, const QString &title) {
|
void GroupCall::toggleRecording(bool enabled, const QString &title) {
|
||||||
const auto real = _peer->groupCall();
|
const auto real = lookupReal();
|
||||||
if (!real || real->id() != _id) {
|
if (!real) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1185,10 +1247,8 @@ void GroupCall::broadcastPartCancel(not_null<LoadPartTask*> task) {
|
||||||
|
|
||||||
void GroupCall::requestParticipantsInformation(
|
void GroupCall::requestParticipantsInformation(
|
||||||
const std::vector<uint32_t> &ssrcs) {
|
const std::vector<uint32_t> &ssrcs) {
|
||||||
const auto real = _peer->groupCall();
|
const auto real = lookupReal();
|
||||||
if (!real
|
if (!real || (_instanceMode == InstanceMode::None)) {
|
||||||
|| (real->id() != _id)
|
|
||||||
|| (_instanceMode == InstanceMode::None)) {
|
|
||||||
for (const auto ssrc : ssrcs) {
|
for (const auto ssrc : ssrcs) {
|
||||||
_unresolvedSsrcs.emplace(ssrc);
|
_unresolvedSsrcs.emplace(ssrc);
|
||||||
}
|
}
|
||||||
|
@ -1222,8 +1282,8 @@ void GroupCall::updateInstanceMuteState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::updateInstanceVolumes() {
|
void GroupCall::updateInstanceVolumes() {
|
||||||
const auto real = _peer->groupCall();
|
const auto real = lookupReal();
|
||||||
if (!real || real->id() != _id) {
|
if (!real) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1299,8 +1359,8 @@ void GroupCall::audioLevelsUpdated(const tgcalls::GroupLevelsUpdate &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::checkLastSpoke() {
|
void GroupCall::checkLastSpoke() {
|
||||||
const auto real = _peer->groupCall();
|
const auto real = lookupReal();
|
||||||
if (!real || real->id() != _id) {
|
if (!real) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1511,8 +1571,8 @@ void GroupCall::editParticipant(
|
||||||
|
|
||||||
std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
|
std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
|
||||||
const std::vector<not_null<UserData*>> &users) {
|
const std::vector<not_null<UserData*>> &users) {
|
||||||
const auto real = _peer->groupCall();
|
const auto real = lookupReal();
|
||||||
if (!real || real->id() != _id) {
|
if (!real) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const auto owner = &_peer->owner();
|
const auto owner = &_peer->owner();
|
||||||
|
|
|
@ -34,6 +34,7 @@ class MediaDevices;
|
||||||
namespace Data {
|
namespace Data {
|
||||||
struct LastSpokeTimes;
|
struct LastSpokeTimes;
|
||||||
struct GroupCallParticipant;
|
struct GroupCallParticipant;
|
||||||
|
class GroupCall;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
namespace Calls {
|
namespace Calls {
|
||||||
|
@ -113,6 +114,9 @@ public:
|
||||||
return _scheduleDate;
|
return _scheduleDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Data::GroupCall *lookupReal() const;
|
||||||
|
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
|
||||||
|
|
||||||
void start(TimeId scheduleDate);
|
void start(TimeId scheduleDate);
|
||||||
void hangup();
|
void hangup();
|
||||||
void discard();
|
void discard();
|
||||||
|
@ -126,6 +130,8 @@ public:
|
||||||
[[nodiscard]] bool recordingStoppedByMe() const {
|
[[nodiscard]] bool recordingStoppedByMe() const {
|
||||||
return _recordingStoppedByMe;
|
return _recordingStoppedByMe;
|
||||||
}
|
}
|
||||||
|
void startScheduledNow();
|
||||||
|
void toggleScheduleStartSubscribed(bool subscribed);
|
||||||
|
|
||||||
void setMuted(MuteState mute);
|
void setMuted(MuteState mute);
|
||||||
void setMutedAndUpdate(MuteState mute);
|
void setMutedAndUpdate(MuteState mute);
|
||||||
|
@ -249,6 +255,7 @@ private:
|
||||||
void applyMeInCallLocally();
|
void applyMeInCallLocally();
|
||||||
void rejoin();
|
void rejoin();
|
||||||
void rejoin(not_null<PeerData*> as);
|
void rejoin(not_null<PeerData*> as);
|
||||||
|
void subscribeToReal(not_null<Data::GroupCall*> real);
|
||||||
|
|
||||||
void audioLevelsUpdated(const tgcalls::GroupLevelsUpdate &data);
|
void audioLevelsUpdated(const tgcalls::GroupLevelsUpdate &data);
|
||||||
void setInstanceConnected(tgcalls::GroupNetworkState networkState);
|
void setInstanceConnected(tgcalls::GroupNetworkState networkState);
|
||||||
|
@ -288,6 +295,7 @@ private:
|
||||||
rpl::event_stream<PeerData*> _peerStream;
|
rpl::event_stream<PeerData*> _peerStream;
|
||||||
not_null<History*> _history; // Can change in legacy group migration.
|
not_null<History*> _history; // Can change in legacy group migration.
|
||||||
MTP::Sender _api;
|
MTP::Sender _api;
|
||||||
|
rpl::event_stream<not_null<Data::GroupCall*>> _realChanges;
|
||||||
rpl::variable<State> _state = State::Creating;
|
rpl::variable<State> _state = State::Creating;
|
||||||
rpl::variable<InstanceState> _instanceState
|
rpl::variable<InstanceState> _instanceState
|
||||||
= InstanceState::Disconnected;
|
= InstanceState::Disconnected;
|
||||||
|
|
|
@ -317,7 +317,7 @@ private:
|
||||||
not_null<PeerData*> participantPeer,
|
not_null<PeerData*> participantPeer,
|
||||||
bool participantIsCallAdmin,
|
bool participantIsCallAdmin,
|
||||||
not_null<Row*> row);
|
not_null<Row*> row);
|
||||||
void setupListChangeViewers(not_null<GroupCall*> call);
|
void setupListChangeViewers();
|
||||||
void subscribeToChanges(not_null<Data::GroupCall*> real);
|
void subscribeToChanges(not_null<Data::GroupCall*> real);
|
||||||
void updateRow(
|
void updateRow(
|
||||||
const std::optional<Data::GroupCall::Participant> &was,
|
const std::optional<Data::GroupCall::Participant> &was,
|
||||||
|
@ -335,16 +335,11 @@ private:
|
||||||
uint64 raiseHandRating) const;
|
uint64 raiseHandRating) const;
|
||||||
Row *findRow(not_null<PeerData*> participantPeer) const;
|
Row *findRow(not_null<PeerData*> participantPeer) const;
|
||||||
|
|
||||||
[[nodiscard]] Data::GroupCall *resolvedRealCall() const;
|
|
||||||
void appendInvitedUsers();
|
void appendInvitedUsers();
|
||||||
void scheduleRaisedHandStatusRemove();
|
void scheduleRaisedHandStatusRemove();
|
||||||
|
|
||||||
const base::weak_ptr<GroupCall> _call;
|
const not_null<GroupCall*> _call;
|
||||||
not_null<PeerData*> _peer;
|
not_null<PeerData*> _peer;
|
||||||
|
|
||||||
// Use only resolvedRealCall() method, not this value directly.
|
|
||||||
Data::GroupCall *_realCallRawValue = nullptr;
|
|
||||||
uint64 _realId = 0;
|
|
||||||
bool _prepared = false;
|
bool _prepared = false;
|
||||||
|
|
||||||
rpl::event_stream<MuteRequest> _toggleMuteRequests;
|
rpl::event_stream<MuteRequest> _toggleMuteRequests;
|
||||||
|
@ -909,7 +904,7 @@ MembersController::MembersController(
|
||||||
, _raisedHandStatusRemoveTimer([=] { scheduleRaisedHandStatusRemove(); })
|
, _raisedHandStatusRemoveTimer([=] { scheduleRaisedHandStatusRemove(); })
|
||||||
, _inactiveCrossLine(st::groupCallMemberInactiveCrossLine)
|
, _inactiveCrossLine(st::groupCallMemberInactiveCrossLine)
|
||||||
, _coloredCrossLine(st::groupCallMemberColoredCrossLine) {
|
, _coloredCrossLine(st::groupCallMemberColoredCrossLine) {
|
||||||
setupListChangeViewers(call);
|
setupListChangeViewers();
|
||||||
|
|
||||||
style::PaletteChanged(
|
style::PaletteChanged(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
|
@ -964,32 +959,20 @@ MembersController::~MembersController() {
|
||||||
base::take(_menu);
|
base::take(_menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MembersController::setupListChangeViewers(not_null<GroupCall*> call) {
|
void MembersController::setupListChangeViewers() {
|
||||||
const auto peer = call->peer();
|
_call->real(
|
||||||
peer->session().changes().peerFlagsValue(
|
|
||||||
peer,
|
|
||||||
Data::PeerUpdate::Flag::GroupCall
|
|
||||||
) | rpl::map([=] {
|
|
||||||
return peer->groupCall();
|
|
||||||
}) | rpl::filter([=](Data::GroupCall *real) {
|
|
||||||
const auto call = _call.get();
|
|
||||||
return call && real && (real->id() == call->id());
|
|
||||||
}) | rpl::take(
|
|
||||||
1
|
|
||||||
) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) {
|
) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) {
|
||||||
subscribeToChanges(real);
|
subscribeToChanges(real);
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
call->stateValue(
|
_call->stateValue(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
const auto call = _call.get();
|
if (const auto real = _call->lookupReal()) {
|
||||||
const auto real = peer->groupCall();
|
|
||||||
if (call && real && (real->id() == call->id())) {
|
|
||||||
//updateRow(channel->session().user());
|
//updateRow(channel->session().user());
|
||||||
}
|
}
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
call->levelUpdates(
|
_call->levelUpdates(
|
||||||
) | rpl::start_with_next([=](const LevelUpdate &update) {
|
) | rpl::start_with_next([=](const LevelUpdate &update) {
|
||||||
const auto i = _soundingRowBySsrc.find(update.ssrc);
|
const auto i = _soundingRowBySsrc.find(update.ssrc);
|
||||||
if (i != end(_soundingRowBySsrc)) {
|
if (i != end(_soundingRowBySsrc)) {
|
||||||
|
@ -997,7 +980,7 @@ void MembersController::setupListChangeViewers(not_null<GroupCall*> call) {
|
||||||
}
|
}
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
call->rejoinEvents(
|
_call->rejoinEvents(
|
||||||
) | rpl::start_with_next([=](const Group::RejoinEvent &event) {
|
) | rpl::start_with_next([=](const Group::RejoinEvent &event) {
|
||||||
const auto guard = gsl::finally([&] {
|
const auto guard = gsl::finally([&] {
|
||||||
delegate()->peerListRefreshRows();
|
delegate()->peerListRefreshRows();
|
||||||
|
@ -1014,9 +997,6 @@ void MembersController::setupListChangeViewers(not_null<GroupCall*> call) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||||
_realCallRawValue = real;
|
|
||||||
_realId = real->id();
|
|
||||||
|
|
||||||
_fullCount = real->fullCountValue();
|
_fullCount = real->fullCountValue();
|
||||||
|
|
||||||
real->participantsSliceAdded(
|
real->participantsSliceAdded(
|
||||||
|
@ -1053,17 +1033,19 @@ void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MembersController::appendInvitedUsers() {
|
void MembersController::appendInvitedUsers() {
|
||||||
for (const auto user : _peer->owner().invitedToCallUsers(_realId)) {
|
if (const auto id = _call->id()) {
|
||||||
if (auto row = createInvitedRow(user)) {
|
for (const auto user : _peer->owner().invitedToCallUsers(id)) {
|
||||||
delegate()->peerListAppendRow(std::move(row));
|
if (auto row = createInvitedRow(user)) {
|
||||||
|
delegate()->peerListAppendRow(std::move(row));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
delegate()->peerListRefreshRows();
|
||||||
}
|
}
|
||||||
delegate()->peerListRefreshRows();
|
|
||||||
|
|
||||||
using Invite = Data::Session::InviteToCall;
|
using Invite = Data::Session::InviteToCall;
|
||||||
_peer->owner().invitesToCalls(
|
_peer->owner().invitesToCalls(
|
||||||
) | rpl::filter([=](const Invite &invite) {
|
) | rpl::filter([=](const Invite &invite) {
|
||||||
return (invite.id == _realId);
|
return (invite.id == _call->id());
|
||||||
}) | rpl::start_with_next([=](const Invite &invite) {
|
}) | rpl::start_with_next([=](const Invite &invite) {
|
||||||
if (auto row = createInvitedRow(invite.user)) {
|
if (auto row = createInvitedRow(invite.user)) {
|
||||||
delegate()->peerListAppendRow(std::move(row));
|
delegate()->peerListAppendRow(std::move(row));
|
||||||
|
@ -1120,7 +1102,7 @@ void MembersController::updateRow(
|
||||||
if (checkPosition) {
|
if (checkPosition) {
|
||||||
checkRowPosition(checkPosition);
|
checkRowPosition(checkPosition);
|
||||||
} else if (addedToBottom) {
|
} else if (addedToBottom) {
|
||||||
const auto real = resolvedRealCall();
|
const auto real = _call->lookupReal();
|
||||||
if (real && real->joinedToTop()) {
|
if (real && real->joinedToTop()) {
|
||||||
const auto proj = [&](const PeerListRow &other) {
|
const auto proj = [&](const PeerListRow &other) {
|
||||||
const auto &real = static_cast<const Row&>(other);
|
const auto &real = static_cast<const Row&>(other);
|
||||||
|
@ -1314,14 +1296,6 @@ Row *MembersController::findRow(not_null<PeerData*> participantPeer) const {
|
||||||
delegate()->peerListFindRow(participantPeer->id));
|
delegate()->peerListFindRow(participantPeer->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::GroupCall *MembersController::resolvedRealCall() const {
|
|
||||||
return (_realCallRawValue
|
|
||||||
&& (_peer->groupCall() == _realCallRawValue)
|
|
||||||
&& (_realCallRawValue->id() == _realId))
|
|
||||||
? _realCallRawValue
|
|
||||||
: nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Main::Session &MembersController::session() const {
|
Main::Session &MembersController::session() const {
|
||||||
return _call->peer()->session();
|
return _call->peer()->session();
|
||||||
}
|
}
|
||||||
|
@ -1332,9 +1306,7 @@ void MembersController::prepare() {
|
||||||
setDescriptionText(tr::lng_contacts_loading(tr::now));
|
setDescriptionText(tr::lng_contacts_loading(tr::now));
|
||||||
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
|
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
|
||||||
|
|
||||||
const auto call = _call.get();
|
if (const auto real = _call->lookupReal()) {
|
||||||
if (const auto real = _peer->groupCall()
|
|
||||||
; real && call && real->id() == call->id()) {
|
|
||||||
prepareRows(real);
|
prepareRows(real);
|
||||||
} else if (auto row = createRowForMe()) {
|
} else if (auto row = createRowForMe()) {
|
||||||
delegate()->peerListAppendRow(std::move(row));
|
delegate()->peerListAppendRow(std::move(row));
|
||||||
|
@ -1342,15 +1314,12 @@ void MembersController::prepare() {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMoreRows();
|
loadMoreRows();
|
||||||
if (_realId) {
|
appendInvitedUsers();
|
||||||
appendInvitedUsers();
|
|
||||||
}
|
|
||||||
_prepared = true;
|
_prepared = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MembersController::isMe(not_null<PeerData*> participantPeer) const {
|
bool MembersController::isMe(not_null<PeerData*> participantPeer) const {
|
||||||
const auto call = _call.get();
|
return (_call->joinAs() == participantPeer);
|
||||||
return call && (call->joinAs() == participantPeer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
|
void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
|
||||||
|
@ -1379,19 +1348,17 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!foundMe) {
|
if (!foundMe) {
|
||||||
if (const auto call = _call.get()) {
|
const auto me = _call->joinAs();
|
||||||
const auto me = call->joinAs();
|
const auto i = ranges::find(
|
||||||
const auto i = ranges::find(
|
participants,
|
||||||
participants,
|
me,
|
||||||
me,
|
&Data::GroupCall::Participant::peer);
|
||||||
&Data::GroupCall::Participant::peer);
|
auto row = (i != end(participants))
|
||||||
auto row = (i != end(participants))
|
? createRow(*i)
|
||||||
? createRow(*i)
|
: createRowForMe();
|
||||||
: createRowForMe();
|
if (row) {
|
||||||
if (row) {
|
changed = true;
|
||||||
changed = true;
|
delegate()->peerListAppendRow(std::move(row));
|
||||||
delegate()->peerListAppendRow(std::move(row));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto &participant : participants) {
|
for (const auto &participant : participants) {
|
||||||
|
@ -1406,7 +1373,7 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MembersController::loadMoreRows() {
|
void MembersController::loadMoreRows() {
|
||||||
if (const auto real = _peer->groupCall()) {
|
if (const auto real = _call->lookupReal()) {
|
||||||
real->requestParticipants();
|
real->requestParticipants();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1634,12 +1601,10 @@ base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMe(participantPeer)) {
|
if (isMe(participantPeer)) {
|
||||||
if (const auto strong = _call.get()
|
if (_call->muted() == MuteState::RaisedHand) {
|
||||||
; strong && strong->muted() == MuteState::RaisedHand) {
|
|
||||||
const auto removeHand = [=] {
|
const auto removeHand = [=] {
|
||||||
if (const auto strong = _call.get()
|
if (_call->muted() == MuteState::RaisedHand) {
|
||||||
; strong && strong->muted() == MuteState::RaisedHand) {
|
_call->setMutedAndUpdate(MuteState::ForceMuted);
|
||||||
strong->setMutedAndUpdate(MuteState::ForceMuted);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
result->addAction(
|
result->addAction(
|
||||||
|
@ -1728,14 +1693,12 @@ void MembersController::addMuteActionsToContextMenu(
|
||||||
|
|
||||||
auto mutesFromVolume = rpl::never<bool>() | rpl::type_erased();
|
auto mutesFromVolume = rpl::never<bool>() | rpl::type_erased();
|
||||||
|
|
||||||
const auto call = _call.get();
|
if (!isMuted || _call->joinAs() == participantPeer) {
|
||||||
if (!isMuted || (call && call->joinAs() == participantPeer)) {
|
auto otherParticipantStateValue
|
||||||
auto otherParticipantStateValue = call
|
= _call->otherParticipantStateValue(
|
||||||
? call->otherParticipantStateValue(
|
) | rpl::filter([=](const Group::ParticipantState &data) {
|
||||||
) | rpl::filter([=](const Group::ParticipantState &data) {
|
return data.peer == participantPeer;
|
||||||
return data.peer == participantPeer;
|
});
|
||||||
})
|
|
||||||
: rpl::never<Group::ParticipantState>() | rpl::type_erased();
|
|
||||||
|
|
||||||
auto volumeItem = base::make_unique_q<MenuVolumeItem>(
|
auto volumeItem = base::make_unique_q<MenuVolumeItem>(
|
||||||
menu->menu(),
|
menu->menu(),
|
||||||
|
@ -1814,11 +1777,7 @@ void MembersController::addMuteActionsToContextMenu(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Row> MembersController::createRowForMe() {
|
std::unique_ptr<Row> MembersController::createRowForMe() {
|
||||||
const auto call = _call.get();
|
auto result = std::make_unique<Row>(this, _call->joinAs());
|
||||||
if (!call) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
auto result = std::make_unique<Row>(this, call->joinAs());
|
|
||||||
updateRow(result.get(), nullptr);
|
updateRow(result.get(), nullptr);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1877,12 +1836,8 @@ auto Members::kickParticipantRequests() const
|
||||||
int Members::desiredHeight() const {
|
int Members::desiredHeight() const {
|
||||||
const auto top = _addMember ? _addMember->height() : 0;
|
const auto top = _addMember ? _addMember->height() : 0;
|
||||||
auto count = [&] {
|
auto count = [&] {
|
||||||
if (const auto call = _call.get()) {
|
if (const auto real = _call->lookupReal()) {
|
||||||
if (const auto real = call->peer()->groupCall()) {
|
return real->fullCount();
|
||||||
if (call->id() == real->id()) {
|
|
||||||
return real->fullCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}();
|
}();
|
||||||
|
@ -1911,16 +1866,7 @@ void Members::setupAddMember(not_null<GroupCall*> call) {
|
||||||
if (const auto channel = peer->asBroadcast()) {
|
if (const auto channel = peer->asBroadcast()) {
|
||||||
_canAddMembers = rpl::single(
|
_canAddMembers = rpl::single(
|
||||||
false
|
false
|
||||||
) | rpl::then(peer->session().changes().peerFlagsValue(
|
) | rpl::then(_call->real(
|
||||||
peer,
|
|
||||||
Data::PeerUpdate::Flag::GroupCall
|
|
||||||
) | rpl::map([=] {
|
|
||||||
return peer->groupCall();
|
|
||||||
}) | rpl::filter([=](Data::GroupCall *real) {
|
|
||||||
const auto call = _call.get();
|
|
||||||
return call && real && (real->id() == call->id());
|
|
||||||
}) | rpl::take(
|
|
||||||
1
|
|
||||||
) | rpl::map([=] {
|
) | rpl::map([=] {
|
||||||
return Data::PeerFlagValue(
|
return Data::PeerFlagValue(
|
||||||
channel,
|
channel,
|
||||||
|
|
|
@ -75,7 +75,7 @@ private:
|
||||||
|
|
||||||
void updateControlsGeometry();
|
void updateControlsGeometry();
|
||||||
|
|
||||||
const base::weak_ptr<GroupCall> _call;
|
const not_null<GroupCall*> _call;
|
||||||
object_ptr<Ui::ScrollArea> _scroll;
|
object_ptr<Ui::ScrollArea> _scroll;
|
||||||
std::unique_ptr<PeerListController> _listController;
|
std::unique_ptr<PeerListController> _listController;
|
||||||
object_ptr<Ui::SettingsButton> _addMember = { nullptr };
|
object_ptr<Ui::SettingsButton> _addMember = { nullptr };
|
||||||
|
|
|
@ -34,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_group_call.h"
|
#include "data/data_group_call.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
#include "data/data_peer_values.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "base/event_filter.h"
|
#include "base/event_filter.h"
|
||||||
#include "boxes/peers/edit_participants_box.h"
|
#include "boxes/peers/edit_participants_box.h"
|
||||||
|
@ -259,14 +260,17 @@ Panel::Panel(not_null<GroupCall*> call)
|
||||||
_window->body(),
|
_window->body(),
|
||||||
st::groupCallTitle))
|
st::groupCallTitle))
|
||||||
#endif // !Q_OS_MAC
|
#endif // !Q_OS_MAC
|
||||||
, _scheduleDate(call->scheduleDate())
|
|
||||||
, _settings(widget(), st::groupCallSettings)
|
, _settings(widget(), st::groupCallSettings)
|
||||||
, _mute(std::make_unique<Ui::CallMuteButton>(
|
, _mute(std::make_unique<Ui::CallMuteButton>(
|
||||||
widget(),
|
widget(),
|
||||||
Core::App().appDeactivatedValue(),
|
Core::App().appDeactivatedValue(),
|
||||||
Ui::CallMuteButtonState{
|
Ui::CallMuteButtonState{
|
||||||
.text = tr::lng_group_call_connecting(tr::now),
|
.text = (_call->scheduleDate()
|
||||||
.type = Ui::CallMuteButtonType::Connecting,
|
? "Start Now" // #TODO voice chats
|
||||||
|
: tr::lng_group_call_connecting(tr::now)),
|
||||||
|
.type = (_call->scheduleDate()
|
||||||
|
? Ui::CallMuteButtonType::ScheduledCanStart
|
||||||
|
: Ui::CallMuteButtonType::Connecting),
|
||||||
}))
|
}))
|
||||||
, _hangup(widget(), st::groupCallHangup) {
|
, _hangup(widget(), st::groupCallHangup) {
|
||||||
_layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox);
|
_layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox);
|
||||||
|
@ -277,7 +281,7 @@ Panel::Panel(not_null<GroupCall*> call)
|
||||||
_peer,
|
_peer,
|
||||||
_window->lifetime(),
|
_window->lifetime(),
|
||||||
[=](not_null<ChannelData*> channel) { migrate(channel); });
|
[=](not_null<ChannelData*> channel) { migrate(channel); });
|
||||||
setupRealCallViewers(call);
|
setupRealCallViewers();
|
||||||
|
|
||||||
initWindow();
|
initWindow();
|
||||||
initWidget();
|
initWidget();
|
||||||
|
@ -295,17 +299,8 @@ Panel::~Panel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::setupRealCallViewers(not_null<GroupCall*> call) {
|
void Panel::setupRealCallViewers() {
|
||||||
const auto peer = call->peer();
|
_call->real(
|
||||||
peer->session().changes().peerFlagsValue(
|
|
||||||
peer,
|
|
||||||
Data::PeerUpdate::Flag::GroupCall
|
|
||||||
) | rpl::map([=] {
|
|
||||||
return peer->groupCall();
|
|
||||||
}) | rpl::filter([=](Data::GroupCall *real) {
|
|
||||||
return real && (real->id() == _call->id());
|
|
||||||
}) | rpl::take(
|
|
||||||
1
|
|
||||||
) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) {
|
) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) {
|
||||||
subscribeToChanges(real);
|
subscribeToChanges(real);
|
||||||
}, _window->lifetime());
|
}, _window->lifetime());
|
||||||
|
@ -430,6 +425,15 @@ void Panel::initControls() {
|
||||||
) | rpl::filter([=](Qt::MouseButton button) {
|
) | rpl::filter([=](Qt::MouseButton button) {
|
||||||
return (button == Qt::LeftButton);
|
return (button == Qt::LeftButton);
|
||||||
}) | rpl::start_with_next([=] {
|
}) | rpl::start_with_next([=] {
|
||||||
|
if (_call->scheduleDate()) {
|
||||||
|
if (_peer->canManageGroupCall()) {
|
||||||
|
_call->startScheduledNow();
|
||||||
|
} else if (const auto real = _call->lookupReal()) {
|
||||||
|
_call->toggleScheduleStartSubscribed(
|
||||||
|
!real->scheduleStartSubscribed());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto oldState = _call->muted();
|
const auto oldState = _call->muted();
|
||||||
const auto newState = (oldState == MuteState::ForceMuted)
|
const auto newState = (oldState == MuteState::ForceMuted)
|
||||||
? MuteState::RaisedHand
|
? MuteState::RaisedHand
|
||||||
|
@ -449,10 +453,6 @@ void Panel::initControls() {
|
||||||
_settings->setText(tr::lng_group_call_settings());
|
_settings->setText(tr::lng_group_call_settings());
|
||||||
_hangup->setText(tr::lng_group_call_leave());
|
_hangup->setText(tr::lng_group_call_leave());
|
||||||
|
|
||||||
if (!_call->scheduleDate()) {
|
|
||||||
setupMembers();
|
|
||||||
}
|
|
||||||
|
|
||||||
_call->stateValue(
|
_call->stateValue(
|
||||||
) | rpl::filter([](State state) {
|
) | rpl::filter([](State state) {
|
||||||
return (state == State::HangingUp)
|
return (state == State::HangingUp)
|
||||||
|
@ -470,18 +470,38 @@ void Panel::initControls() {
|
||||||
_mute->setLevel(update.value);
|
_mute->setLevel(update.value);
|
||||||
}, _callLifetime);
|
}, _callLifetime);
|
||||||
|
|
||||||
|
_call->real(
|
||||||
|
) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) {
|
||||||
|
setupRealMuteButtonState(real);
|
||||||
|
}, _callLifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::setupRealMuteButtonState(not_null<Data::GroupCall*> real) {
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
rpl::combine(
|
rpl::combine(
|
||||||
_call->mutedValue() | MapPushToTalkToActive(),
|
_call->mutedValue() | MapPushToTalkToActive(),
|
||||||
_call->instanceStateValue()
|
_call->instanceStateValue(),
|
||||||
|
real->scheduleDateValue(),
|
||||||
|
real->scheduleStartSubscribedValue(),
|
||||||
|
Data::CanManageGroupCallValue(_peer)
|
||||||
) | rpl::distinct_until_changed(
|
) | rpl::distinct_until_changed(
|
||||||
) | rpl::filter(
|
) | rpl::filter(
|
||||||
_2 != GroupCall::InstanceState::TransitionToRtc
|
_2 != GroupCall::InstanceState::TransitionToRtc
|
||||||
) | rpl::start_with_next([=](
|
) | rpl::start_with_next([=](
|
||||||
MuteState mute,
|
MuteState mute,
|
||||||
GroupCall::InstanceState state) {
|
GroupCall::InstanceState state,
|
||||||
|
TimeId scheduleDate,
|
||||||
|
bool scheduleStartSubscribed,
|
||||||
|
bool canManage) {
|
||||||
|
using Type = Ui::CallMuteButtonType;
|
||||||
_mute->setState(Ui::CallMuteButtonState{
|
_mute->setState(Ui::CallMuteButtonState{
|
||||||
.text = (state == GroupCall::InstanceState::Disconnected
|
.text = (scheduleDate
|
||||||
|
? (canManage
|
||||||
|
? "Start Now" // #TODO voice chats
|
||||||
|
: scheduleStartSubscribed
|
||||||
|
? "Cancel Reminder"
|
||||||
|
: "Set Reminder")
|
||||||
|
: state == GroupCall::InstanceState::Disconnected
|
||||||
? tr::lng_group_call_connecting(tr::now)
|
? tr::lng_group_call_connecting(tr::now)
|
||||||
: mute == MuteState::ForceMuted
|
: mute == MuteState::ForceMuted
|
||||||
? tr::lng_group_call_force_muted(tr::now)
|
? tr::lng_group_call_force_muted(tr::now)
|
||||||
|
@ -490,7 +510,9 @@ void Panel::initControls() {
|
||||||
: mute == MuteState::Muted
|
: mute == MuteState::Muted
|
||||||
? tr::lng_group_call_unmute(tr::now)
|
? tr::lng_group_call_unmute(tr::now)
|
||||||
: tr::lng_group_call_you_are_live(tr::now)),
|
: tr::lng_group_call_you_are_live(tr::now)),
|
||||||
.subtext = (state == GroupCall::InstanceState::Disconnected
|
.subtext = (scheduleDate
|
||||||
|
? QString()
|
||||||
|
: state == GroupCall::InstanceState::Disconnected
|
||||||
? QString()
|
? QString()
|
||||||
: mute == MuteState::ForceMuted
|
: mute == MuteState::ForceMuted
|
||||||
? tr::lng_group_call_raise_hand_tip(tr::now)
|
? tr::lng_group_call_raise_hand_tip(tr::now)
|
||||||
|
@ -499,15 +521,21 @@ void Panel::initControls() {
|
||||||
: mute == MuteState::Muted
|
: mute == MuteState::Muted
|
||||||
? tr::lng_group_call_unmute_sub(tr::now)
|
? tr::lng_group_call_unmute_sub(tr::now)
|
||||||
: QString()),
|
: QString()),
|
||||||
.type = (state == GroupCall::InstanceState::Disconnected
|
.type = (scheduleDate
|
||||||
? Ui::CallMuteButtonType::Connecting
|
? (canManage
|
||||||
|
? Type::ScheduledCanStart
|
||||||
|
: scheduleStartSubscribed
|
||||||
|
? Type::ScheduledNotify
|
||||||
|
: Type::ScheduledSilent)
|
||||||
|
: state == GroupCall::InstanceState::Disconnected
|
||||||
|
? Type::Connecting
|
||||||
: mute == MuteState::ForceMuted
|
: mute == MuteState::ForceMuted
|
||||||
? Ui::CallMuteButtonType::ForceMuted
|
? Type::ForceMuted
|
||||||
: mute == MuteState::RaisedHand
|
: mute == MuteState::RaisedHand
|
||||||
? Ui::CallMuteButtonType::RaisedHand
|
? Type::RaisedHand
|
||||||
: mute == MuteState::Muted
|
: mute == MuteState::Muted
|
||||||
? Ui::CallMuteButtonType::Muted
|
? Type::Muted
|
||||||
: Ui::CallMuteButtonType::Active),
|
: Type::Active),
|
||||||
});
|
});
|
||||||
}, _callLifetime);
|
}, _callLifetime);
|
||||||
}
|
}
|
||||||
|
@ -590,8 +618,7 @@ void Panel::setupJoinAsChangedToasts() {
|
||||||
void Panel::setupTitleChangedToasts() {
|
void Panel::setupTitleChangedToasts() {
|
||||||
_call->titleChanged(
|
_call->titleChanged(
|
||||||
) | rpl::filter([=] {
|
) | rpl::filter([=] {
|
||||||
const auto real = _peer->groupCall();
|
return (_call->lookupReal() != nullptr);
|
||||||
return real && (real->id() == _call->id());
|
|
||||||
}) | rpl::map([=] {
|
}) | rpl::map([=] {
|
||||||
return _peer->groupCall()->title().isEmpty()
|
return _peer->groupCall()->title().isEmpty()
|
||||||
? _peer->name
|
? _peer->name
|
||||||
|
@ -617,10 +644,8 @@ void Panel::setupAllowedToSpeakToasts() {
|
||||||
.text = { tr::lng_group_call_can_speak_here(tr::now) },
|
.text = { tr::lng_group_call_can_speak_here(tr::now) },
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const auto real = _peer->groupCall();
|
const auto real = _call->lookupReal();
|
||||||
const auto name = (real
|
const auto name = (real && !real->title().isEmpty())
|
||||||
&& (real->id() == _call->id())
|
|
||||||
&& !real->title().isEmpty())
|
|
||||||
? real->title()
|
? real->title()
|
||||||
: _peer->name;
|
: _peer->name;
|
||||||
Ui::ShowMultilineToast({
|
Ui::ShowMultilineToast({
|
||||||
|
@ -635,18 +660,6 @@ void Panel::setupAllowedToSpeakToasts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||||
if (!_members) {
|
|
||||||
real->scheduleDateValue(
|
|
||||||
) | rpl::filter([=](TimeId scheduleDate) {
|
|
||||||
return !scheduleDate;
|
|
||||||
}) | rpl::take(1) | rpl::start_with_next([=] {
|
|
||||||
setupMembers();
|
|
||||||
}, _callLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
_titleText = real->titleValue();
|
|
||||||
_scheduleDate = real->scheduleDateValue();
|
|
||||||
|
|
||||||
const auto validateRecordingMark = [=](bool recording) {
|
const auto validateRecordingMark = [=](bool recording) {
|
||||||
if (!recording && _recordingMark) {
|
if (!recording && _recordingMark) {
|
||||||
_recordingMark.destroy();
|
_recordingMark.destroy();
|
||||||
|
@ -823,8 +836,8 @@ void Panel::showMainMenu() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::addMembers() {
|
void Panel::addMembers() {
|
||||||
const auto real = _peer->groupCall();
|
const auto real = _call->lookupReal();
|
||||||
if (!real || real->id() != _call->id()) {
|
if (!real) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto alreadyIn = _peer->owner().invitedToCallUsers(real->id());
|
auto alreadyIn = _peer->owner().invitedToCallUsers(real->id());
|
||||||
|
@ -1135,7 +1148,12 @@ void Panel::refreshTitle() {
|
||||||
if (!_title) {
|
if (!_title) {
|
||||||
auto text = rpl::combine(
|
auto text = rpl::combine(
|
||||||
Info::Profile::NameValue(_peer),
|
Info::Profile::NameValue(_peer),
|
||||||
_titleText.value()
|
rpl::single(
|
||||||
|
QString()
|
||||||
|
) | rpl::then(_call->real(
|
||||||
|
) | rpl::map([=](not_null<Data::GroupCall*> real) {
|
||||||
|
return real->titleValue();
|
||||||
|
}) | rpl::flatten_latest())
|
||||||
) | rpl::map([=](
|
) | rpl::map([=](
|
||||||
const TextWithEntities &name,
|
const TextWithEntities &name,
|
||||||
const QString &title) {
|
const QString &title) {
|
||||||
|
@ -1154,15 +1172,24 @@ void Panel::refreshTitle() {
|
||||||
if (!_subtitle) {
|
if (!_subtitle) {
|
||||||
_subtitle.create(
|
_subtitle.create(
|
||||||
widget(),
|
widget(),
|
||||||
_scheduleDate.value(
|
rpl::single(
|
||||||
|
_call->scheduleDate()
|
||||||
|
) | rpl::then(
|
||||||
|
_call->real(
|
||||||
|
) | rpl::map([=](not_null<Data::GroupCall*> real) {
|
||||||
|
return real->scheduleDateValue();
|
||||||
|
}) | rpl::flatten_latest()
|
||||||
) | rpl::map([=](TimeId scheduleDate) {
|
) | rpl::map([=](TimeId scheduleDate) {
|
||||||
return scheduleDate
|
if (scheduleDate) {
|
||||||
? tr::lng_group_call_scheduled_status()
|
return tr::lng_group_call_scheduled_status();
|
||||||
: tr::lng_group_call_members(
|
} else if (!_members) {
|
||||||
lt_count_decimal,
|
setupMembers();
|
||||||
_members->fullCountValue() | rpl::map([](int value) {
|
}
|
||||||
return (value > 0) ? float64(value) : 1.;
|
return tr::lng_group_call_members(
|
||||||
}));
|
lt_count_decimal,
|
||||||
|
_members->fullCountValue() | rpl::map([](int value) {
|
||||||
|
return (value > 0) ? float64(value) : 1.;
|
||||||
|
}));
|
||||||
}) | rpl::flatten_latest(),
|
}) | rpl::flatten_latest(),
|
||||||
st::groupCallSubtitleLabel);
|
st::groupCallSubtitleLabel);
|
||||||
_subtitle->show();
|
_subtitle->show();
|
||||||
|
|
|
@ -79,6 +79,7 @@ private:
|
||||||
void setupJoinAsChangedToasts();
|
void setupJoinAsChangedToasts();
|
||||||
void setupTitleChangedToasts();
|
void setupTitleChangedToasts();
|
||||||
void setupAllowedToSpeakToasts();
|
void setupAllowedToSpeakToasts();
|
||||||
|
void setupRealMuteButtonState(not_null<Data::GroupCall*> real);
|
||||||
|
|
||||||
bool handleClose();
|
bool handleClose();
|
||||||
|
|
||||||
|
@ -96,7 +97,7 @@ private:
|
||||||
[[nodiscard]] QRect computeTitleRect() const;
|
[[nodiscard]] QRect computeTitleRect() const;
|
||||||
void refreshTitle();
|
void refreshTitle();
|
||||||
void refreshTitleGeometry();
|
void refreshTitleGeometry();
|
||||||
void setupRealCallViewers(not_null<GroupCall*> call);
|
void setupRealCallViewers();
|
||||||
void subscribeToChanges(not_null<Data::GroupCall*> real);
|
void subscribeToChanges(not_null<Data::GroupCall*> real);
|
||||||
|
|
||||||
void migrate(not_null<ChannelData*> channel);
|
void migrate(not_null<ChannelData*> channel);
|
||||||
|
@ -121,8 +122,6 @@ private:
|
||||||
object_ptr<Ui::DropdownMenu> _menu = { nullptr };
|
object_ptr<Ui::DropdownMenu> _menu = { nullptr };
|
||||||
object_ptr<Ui::AbstractButton> _joinAsToggle = { nullptr };
|
object_ptr<Ui::AbstractButton> _joinAsToggle = { nullptr };
|
||||||
object_ptr<Members> _members = { nullptr };
|
object_ptr<Members> _members = { nullptr };
|
||||||
rpl::variable<QString> _titleText;
|
|
||||||
rpl::variable<TimeId> _scheduleDate;
|
|
||||||
ChooseJoinAsProcess _joinAsProcess;
|
ChooseJoinAsProcess _joinAsProcess;
|
||||||
|
|
||||||
object_ptr<Ui::CallButton> _settings;
|
object_ptr<Ui::CallButton> _settings;
|
||||||
|
|
|
@ -330,6 +330,7 @@ void GroupCall::applyCallFields(const MTPDgroupCall &data) {
|
||||||
_title = qs(data.vtitle().value_or_empty());
|
_title = qs(data.vtitle().value_or_empty());
|
||||||
_recordStartDate = data.vrecord_start_date().value_or_empty();
|
_recordStartDate = data.vrecord_start_date().value_or_empty();
|
||||||
_scheduleDate = data.vschedule_date().value_or_empty();
|
_scheduleDate = data.vschedule_date().value_or_empty();
|
||||||
|
_scheduleStartSubscribed = data.is_schedule_start_subscribed();
|
||||||
_allParticipantsLoaded
|
_allParticipantsLoaded
|
||||||
= (_serverParticipantsCount == _participants.size());
|
= (_serverParticipantsCount == _participants.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,12 @@ public:
|
||||||
[[nodiscard]] rpl::producer<TimeId> scheduleDateChanges() const {
|
[[nodiscard]] rpl::producer<TimeId> scheduleDateChanges() const {
|
||||||
return _scheduleDate.changes();
|
return _scheduleDate.changes();
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool scheduleStartSubscribed() const {
|
||||||
|
return _scheduleStartSubscribed.current();
|
||||||
|
}
|
||||||
|
[[nodiscard]] rpl::producer<bool> scheduleStartSubscribedValue() const {
|
||||||
|
return _scheduleStartSubscribed.value();
|
||||||
|
}
|
||||||
|
|
||||||
void setPeer(not_null<PeerData*> peer);
|
void setPeer(not_null<PeerData*> peer);
|
||||||
|
|
||||||
|
@ -173,6 +179,7 @@ private:
|
||||||
rpl::variable<int> _fullCount = 0;
|
rpl::variable<int> _fullCount = 0;
|
||||||
rpl::variable<TimeId> _recordStartDate = 0;
|
rpl::variable<TimeId> _recordStartDate = 0;
|
||||||
rpl::variable<TimeId> _scheduleDate = 0;
|
rpl::variable<TimeId> _scheduleDate = 0;
|
||||||
|
rpl::variable<bool> _scheduleStartSubscribed = false;
|
||||||
|
|
||||||
base::flat_map<uint32, LastSpokeTimes> _unknownSpokenSsrcs;
|
base::flat_map<uint32, LastSpokeTimes> _unknownSpokenSsrcs;
|
||||||
base::flat_map<PeerId, LastSpokeTimes> _unknownSpokenPeerIds;
|
base::flat_map<PeerId, LastSpokeTimes> _unknownSpokenPeerIds;
|
||||||
|
|
|
@ -320,6 +320,20 @@ rpl::producer<bool> CanPinMessagesValue(not_null<PeerData*> peer) {
|
||||||
Unexpected("Peer type in CanPinMessagesValue.");
|
Unexpected("Peer type in CanPinMessagesValue.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<bool> CanManageGroupCallValue(not_null<PeerData*> peer) {
|
||||||
|
const auto flag = MTPDchatAdminRights::Flag::f_manage_call;
|
||||||
|
if (const auto chat = peer->asChat()) {
|
||||||
|
return chat->amCreator()
|
||||||
|
? (rpl::single(true) | rpl::type_erased())
|
||||||
|
: AdminRightValue(chat, flag);
|
||||||
|
} else if (const auto channel = peer->asChannel()) {
|
||||||
|
return channel->amCreator()
|
||||||
|
? (rpl::single(true) | rpl::type_erased())
|
||||||
|
: AdminRightValue(channel, flag);
|
||||||
|
}
|
||||||
|
return rpl::single(false);
|
||||||
|
}
|
||||||
|
|
||||||
TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now) {
|
TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now) {
|
||||||
if (user->isServiceUser() || user->isBot()) {
|
if (user->isServiceUser() || user->isBot()) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -111,6 +111,7 @@ inline auto PeerFullFlagValue(
|
||||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(ChannelData *channel);
|
[[nodiscard]] rpl::producer<bool> CanWriteValue(ChannelData *channel);
|
||||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(not_null<PeerData*> peer);
|
[[nodiscard]] rpl::producer<bool> CanWriteValue(not_null<PeerData*> peer);
|
||||||
[[nodiscard]] rpl::producer<bool> CanPinMessagesValue(not_null<PeerData*> peer);
|
[[nodiscard]] rpl::producer<bool> CanPinMessagesValue(not_null<PeerData*> peer);
|
||||||
|
[[nodiscard]] rpl::producer<bool> CanManageGroupCallValue(not_null<PeerData*> peer);
|
||||||
|
|
||||||
[[nodiscard]] TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now);
|
[[nodiscard]] TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now);
|
||||||
[[nodiscard]] crl::time OnlineChangeTimeout(TimeId online, TimeId now);
|
[[nodiscard]] crl::time OnlineChangeTimeout(TimeId online, TimeId now);
|
||||||
|
|
|
@ -102,21 +102,7 @@ auto MuteBlobs() {
|
||||||
auto Colors() {
|
auto Colors() {
|
||||||
using Vector = std::vector<QColor>;
|
using Vector = std::vector<QColor>;
|
||||||
using Colors = anim::gradient_colors;
|
using Colors = anim::gradient_colors;
|
||||||
return base::flat_map<CallMuteButtonType, Colors>{
|
auto result = base::flat_map<CallMuteButtonType, Colors>{
|
||||||
{
|
|
||||||
CallMuteButtonType::ForceMuted,
|
|
||||||
Colors(QGradientStops{
|
|
||||||
{ .0, st::groupCallForceMuted3->c },
|
|
||||||
{ .5, st::groupCallForceMuted2->c },
|
|
||||||
{ 1., st::groupCallForceMuted1->c } })
|
|
||||||
},
|
|
||||||
{
|
|
||||||
CallMuteButtonType::RaisedHand,
|
|
||||||
Colors(QGradientStops{
|
|
||||||
{ .0, st::groupCallForceMuted3->c },
|
|
||||||
{ .5, st::groupCallForceMuted2->c },
|
|
||||||
{ 1., st::groupCallForceMuted1->c } })
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
CallMuteButtonType::Active,
|
CallMuteButtonType::Active,
|
||||||
Colors(Vector{ st::groupCallLive1->c, st::groupCallLive2->c })
|
Colors(Vector{ st::groupCallLive1->c, st::groupCallLive2->c })
|
||||||
|
@ -130,6 +116,21 @@ auto Colors() {
|
||||||
Colors(Vector{ st::groupCallMuted1->c, st::groupCallMuted2->c })
|
Colors(Vector{ st::groupCallMuted1->c, st::groupCallMuted2->c })
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const auto forceMutedColors = Colors(QGradientStops{
|
||||||
|
{ .0, st::groupCallForceMuted3->c },
|
||||||
|
{ .5, st::groupCallForceMuted2->c },
|
||||||
|
{ 1., st::groupCallForceMuted1->c } });
|
||||||
|
const auto forceMutedTypes = {
|
||||||
|
CallMuteButtonType::ForceMuted,
|
||||||
|
CallMuteButtonType::RaisedHand,
|
||||||
|
CallMuteButtonType::ScheduledCanStart,
|
||||||
|
CallMuteButtonType::ScheduledNotify,
|
||||||
|
CallMuteButtonType::ScheduledSilent,
|
||||||
|
};
|
||||||
|
for (const auto type : forceMutedTypes) {
|
||||||
|
result.emplace(type, forceMutedColors);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsMuted(CallMuteButtonType type) {
|
bool IsMuted(CallMuteButtonType type) {
|
||||||
|
@ -143,7 +144,10 @@ bool IsConnecting(CallMuteButtonType type) {
|
||||||
bool IsInactive(CallMuteButtonType type) {
|
bool IsInactive(CallMuteButtonType type) {
|
||||||
return IsConnecting(type)
|
return IsConnecting(type)
|
||||||
|| (type == CallMuteButtonType::ForceMuted)
|
|| (type == CallMuteButtonType::ForceMuted)
|
||||||
|| (type == CallMuteButtonType::RaisedHand);
|
|| (type == CallMuteButtonType::RaisedHand)
|
||||||
|
|| (type == CallMuteButtonType::ScheduledCanStart)
|
||||||
|
|| (type == CallMuteButtonType::ScheduledNotify)
|
||||||
|
|| (type == CallMuteButtonType::ScheduledSilent);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Clamp(float64 value) {
|
auto Clamp(float64 value) {
|
||||||
|
@ -585,6 +589,9 @@ CallMuteButton::IconState CallMuteButton::iconStateFrom(
|
||||||
.frameTo = 62,
|
.frameTo = 62,
|
||||||
};
|
};
|
||||||
} break;
|
} break;
|
||||||
|
case CallMuteButtonType::ScheduledCanStart: // #TODO voice chats
|
||||||
|
case CallMuteButtonType::ScheduledNotify:
|
||||||
|
case CallMuteButtonType::ScheduledSilent:
|
||||||
case CallMuteButtonType::ForceMuted:
|
case CallMuteButtonType::ForceMuted:
|
||||||
case CallMuteButtonType::RaisedHand: {
|
case CallMuteButtonType::RaisedHand: {
|
||||||
return { // Active -> Hand
|
return { // Active -> Hand
|
||||||
|
@ -615,6 +622,9 @@ CallMuteButton::IconState CallMuteButton::iconStateFrom(
|
||||||
.frameTo = 22,
|
.frameTo = 22,
|
||||||
};
|
};
|
||||||
} break;
|
} break;
|
||||||
|
case CallMuteButtonType::ScheduledCanStart: // #TODO voice chats
|
||||||
|
case CallMuteButtonType::ScheduledNotify:
|
||||||
|
case CallMuteButtonType::ScheduledSilent:
|
||||||
case CallMuteButtonType::ForceMuted:
|
case CallMuteButtonType::ForceMuted:
|
||||||
case CallMuteButtonType::RaisedHand: {
|
case CallMuteButtonType::RaisedHand: {
|
||||||
return { // Muted -> Hand
|
return { // Muted -> Hand
|
||||||
|
@ -626,6 +636,9 @@ CallMuteButton::IconState CallMuteButton::iconStateFrom(
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case CallMuteButtonType::ScheduledCanStart: // #TODO voice chats
|
||||||
|
case CallMuteButtonType::ScheduledNotify:
|
||||||
|
case CallMuteButtonType::ScheduledSilent:
|
||||||
case CallMuteButtonType::ForceMuted:
|
case CallMuteButtonType::ForceMuted:
|
||||||
case CallMuteButtonType::RaisedHand: {
|
case CallMuteButtonType::RaisedHand: {
|
||||||
switch (current) {
|
switch (current) {
|
||||||
|
@ -645,6 +658,9 @@ CallMuteButton::IconState CallMuteButton::iconStateFrom(
|
||||||
.frameTo = 20,
|
.frameTo = 20,
|
||||||
};
|
};
|
||||||
} break;
|
} break;
|
||||||
|
case CallMuteButtonType::ScheduledCanStart: // #TODO voice chats
|
||||||
|
case CallMuteButtonType::ScheduledNotify:
|
||||||
|
case CallMuteButtonType::ScheduledSilent:
|
||||||
case CallMuteButtonType::ForceMuted:
|
case CallMuteButtonType::ForceMuted:
|
||||||
case CallMuteButtonType::RaisedHand: {
|
case CallMuteButtonType::RaisedHand: {
|
||||||
return { // Hand
|
return { // Hand
|
||||||
|
@ -1015,6 +1031,9 @@ CallMuteButton::HandleMouseState CallMuteButton::HandleMouseStateFromType(
|
||||||
return HandleMouseState::Enabled;
|
return HandleMouseState::Enabled;
|
||||||
case CallMuteButtonType::Connecting:
|
case CallMuteButtonType::Connecting:
|
||||||
return HandleMouseState::Disabled;
|
return HandleMouseState::Disabled;
|
||||||
|
case CallMuteButtonType::ScheduledCanStart:
|
||||||
|
case CallMuteButtonType::ScheduledNotify:
|
||||||
|
case CallMuteButtonType::ScheduledSilent:
|
||||||
case CallMuteButtonType::ForceMuted:
|
case CallMuteButtonType::ForceMuted:
|
||||||
case CallMuteButtonType::RaisedHand:
|
case CallMuteButtonType::RaisedHand:
|
||||||
return HandleMouseState::Enabled;
|
return HandleMouseState::Enabled;
|
||||||
|
@ -1098,7 +1117,10 @@ void CallMuteButton::overridesColors(
|
||||||
float64 progress) {
|
float64 progress) {
|
||||||
const auto forceMutedToConnecting = [](CallMuteButtonType &type) {
|
const auto forceMutedToConnecting = [](CallMuteButtonType &type) {
|
||||||
if (type == CallMuteButtonType::ForceMuted
|
if (type == CallMuteButtonType::ForceMuted
|
||||||
|| type == CallMuteButtonType::RaisedHand) {
|
|| type == CallMuteButtonType::RaisedHand
|
||||||
|
|| type == CallMuteButtonType::ScheduledCanStart
|
||||||
|
|| type == CallMuteButtonType::ScheduledNotify
|
||||||
|
|| type == CallMuteButtonType::ScheduledSilent) {
|
||||||
type = CallMuteButtonType::Connecting;
|
type = CallMuteButtonType::Connecting;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,6 +30,9 @@ enum class CallMuteButtonType {
|
||||||
Muted,
|
Muted,
|
||||||
ForceMuted,
|
ForceMuted,
|
||||||
RaisedHand,
|
RaisedHand,
|
||||||
|
ScheduledCanStart,
|
||||||
|
ScheduledSilent,
|
||||||
|
ScheduledNotify,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CallMuteButtonState {
|
struct CallMuteButtonState {
|
||||||
|
|
Loading…
Reference in New Issue