Add 'invited' members to voice chats.

This commit is contained in:
John Preston 2020-12-16 15:58:53 +04:00
parent a85be4ccd0
commit cabd7a276b
7 changed files with 116 additions and 14 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -562,6 +562,8 @@ groupCallMemberColoredCrossLine: CrossLineAnimation(groupCallMemberInactiveCross
fg: groupCallMemberMutedIcon; fg: groupCallMemberMutedIcon;
icon: icon {{ "calls/group_calls_unmuted", groupCallMemberActiveIcon }}; icon: icon {{ "calls/group_calls_unmuted", groupCallMemberActiveIcon }};
} }
groupCallMemberInvited: icon {{ "calls/group_calls_invited", groupCallMemberInactiveIcon }};
groupCallMemberInvitedPosition: point(2px, 12px);
groupCallSettings: CallButton(callMicrophoneMute) { groupCallSettings: CallButton(callMicrophoneMute) {
button: IconButton(callButton) { button: IconButton(callButton) {

View file

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_group_call.h" #include "data/data_group_call.h"
#include "data/data_peer_values.h" // Data::CanWriteValue. #include "data/data_peer_values.h" // Data::CanWriteValue.
#include "data/data_session.h" // Data::Session::invitedToCallUsers.
#include "ui/paint/blobs.h" #include "ui/paint/blobs.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
@ -85,6 +86,7 @@ public:
Active, Active,
Inactive, Inactive,
Muted, Muted,
Invited,
}; };
void setSkipLevelUpdate(bool value); void setSkipLevelUpdate(bool value);
@ -116,7 +118,9 @@ public:
st::groupCallActiveButton.height); st::groupCallActiveButton.height);
} }
bool actionDisabled() const override { bool actionDisabled() const override {
return peer()->isSelf() || !_delegate->rowCanMuteMembers(); return peer()->isSelf()
|| (_state == State::Invited)
|| !_delegate->rowCanMuteMembers();
} }
QMargins actionMargins() const override { QMargins actionMargins() const override {
return QMargins( return QMargins(
@ -135,6 +139,15 @@ public:
auto generatePaintUserpicCallback() -> PaintRoundImageCallback override; auto generatePaintUserpicCallback() -> PaintRoundImageCallback override;
void paintStatusText(
Painter &p,
const style::PeerListItem &st,
int x,
int y,
int availableWidth,
int outerWidth,
bool selected) override;
private: private:
struct BlobsAnimation { struct BlobsAnimation {
BlobsAnimation( BlobsAnimation(
@ -223,6 +236,8 @@ private:
[[nodiscard]] std::unique_ptr<Row> createSelfRow(); [[nodiscard]] std::unique_ptr<Row> createSelfRow();
[[nodiscard]] std::unique_ptr<Row> createRow( [[nodiscard]] std::unique_ptr<Row> createRow(
const Data::GroupCall::Participant &participant); const Data::GroupCall::Participant &participant);
[[nodiscard]] std::unique_ptr<Row> createInvitedRow(
not_null<UserData*> user);
void prepareRows(not_null<Data::GroupCall*> real); void prepareRows(not_null<Data::GroupCall*> real);
//void repaintByTimer(); //void repaintByTimer();
@ -241,6 +256,7 @@ private:
Row *findRow(not_null<UserData*> user) const; Row *findRow(not_null<UserData*> user) const;
[[nodiscard]] Data::GroupCall *resolvedRealCall() const; [[nodiscard]] Data::GroupCall *resolvedRealCall() const;
void appendInvitedUsers();
const base::weak_ptr<GroupCall> _call; const base::weak_ptr<GroupCall> _call;
not_null<PeerData*> _peer; not_null<PeerData*> _peer;
@ -248,6 +264,7 @@ private:
// Use only resolvedRealCall() method, not this value directly. // Use only resolvedRealCall() method, not this value directly.
Data::GroupCall *_realCallRawValue = nullptr; Data::GroupCall *_realCallRawValue = nullptr;
uint64 _realId = 0; uint64 _realId = 0;
bool _prepared = false;
rpl::event_stream<MuteRequest> _toggleMuteRequests; rpl::event_stream<MuteRequest> _toggleMuteRequests;
rpl::event_stream<not_null<UserData*>> _kickMemberRequests; rpl::event_stream<not_null<UserData*>> _kickMemberRequests;
@ -283,12 +300,7 @@ void Row::setSkipLevelUpdate(bool value) {
void Row::updateState(const Data::GroupCall::Participant *participant) { void Row::updateState(const Data::GroupCall::Participant *participant) {
setSsrc(participant ? participant->ssrc : 0); setSsrc(participant ? participant->ssrc : 0);
if (!participant) { if (!participant) {
if (peer()->isSelf()) { setState(State::Invited);
setCustomStatus(tr::lng_group_call_connecting(tr::now));
} else {
setCustomStatus(QString());
}
setState(State::Inactive);
setSounding(false); setSounding(false);
setSpeaking(false); setSpeaking(false);
} else if (!participant->muted } else if (!participant->muted
@ -476,6 +488,34 @@ auto Row::generatePaintUserpicCallback() -> PaintRoundImageCallback {
}; };
} }
void Row::paintStatusText(
Painter &p,
const style::PeerListItem &st,
int x,
int y,
int availableWidth,
int outerWidth,
bool selected) {
if (_state != State::Invited) {
PeerListRow::paintStatusText(
p,
st,
x,
y,
availableWidth,
outerWidth,
selected);
return;
}
p.setFont(st::normalFont);
p.setPen(st::groupCallMemberNotJoinedStatus);
p.drawTextLeft(
x,
y,
outerWidth,
peer()->isSelf() ? "connecting..." : "invited");
}
void Row::paintAction( void Row::paintAction(
Painter &p, Painter &p,
int x, int x,
@ -484,6 +524,20 @@ void Row::paintAction(
bool selected, bool selected,
bool actionSelected) { bool actionSelected) {
auto size = actionSize(); auto size = actionSize();
const auto iconRect = style::rtlrect(
x,
y,
size.width(),
size.height(),
outerWidth);
if (_state == State::Invited) {
_actionRipple = nullptr;
st::groupCallMemberInvited.paint(
p,
QPoint(x, y) + st::groupCallMemberInvitedPosition,
outerWidth);
return;
}
if (_actionRipple) { if (_actionRipple) {
_actionRipple->paint( _actionRipple->paint(
p, p,
@ -494,12 +548,6 @@ void Row::paintAction(
_actionRipple.reset(); _actionRipple.reset();
} }
} }
const auto iconRect = style::rtlrect(
x,
y,
size.width(),
size.height(),
outerWidth);
const auto speaking = _speakingAnimation.value(_speaking ? 1. : 0.); const auto speaking = _speakingAnimation.value(_speaking ? 1. : 0.);
const auto active = _activeAnimation.value( const auto active = _activeAnimation.value(
(_state == State::Active) ? 1. : 0.); (_state == State::Active) ? 1. : 0.);
@ -649,6 +697,7 @@ void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
const auto user = update.was ? update.was->user : update.now->user; const auto user = update.was ? update.was->user : update.now->user;
if (!update.now) { if (!update.now) {
if (const auto row = findRow(user)) { if (const auto row = findRow(user)) {
const auto owner = &user->owner();
if (user->isSelf()) { if (user->isSelf()) {
updateRow(row, nullptr); updateRow(row, nullptr);
} else { } else {
@ -660,6 +709,30 @@ void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
updateRow(update.was, *update.now); updateRow(update.was, *update.now);
} }
}, _lifetime); }, _lifetime);
if (_prepared) {
appendInvitedUsers();
}
}
void MembersController::appendInvitedUsers() {
for (const auto user : _peer->owner().invitedToCallUsers(_realId)) {
if (auto row = createInvitedRow(user)) {
delegate()->peerListAppendRow(std::move(row));
}
}
delegate()->peerListRefreshRows();
using Invite = Data::Session::InviteToCall;
_peer->owner().invitesToCalls(
) | rpl::filter([=](const Invite &invite) {
return (invite.id == _realId);
}) | rpl::start_with_next([=](const Invite &invite) {
if (auto row = createInvitedRow(invite.user)) {
delegate()->peerListAppendRow(std::move(row));
delegate()->peerListRefreshRows();
}
}, _lifetime);
} }
void MembersController::updateRow( void MembersController::updateRow(
@ -796,7 +869,12 @@ void MembersController::prepare() {
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
loadMoreRows(); loadMoreRows();
if (_realId) {
appendInvitedUsers();
}
_prepared = true;
} }
void MembersController::prepareRows(not_null<Data::GroupCall*> real) { void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
@ -1056,7 +1134,9 @@ base::unique_qptr<Ui::PopupMenu> MembersController::rowContextMenu(
tr::lng_context_send_message(tr::now), tr::lng_context_send_message(tr::now),
showHistory); showHistory);
const auto canKick = [&] { const auto canKick = [&] {
if (const auto chat = _peer->asChat()) { if (static_cast<Row*>(row.get())->state() == Row::State::Invited) {
return false;
} else if (const auto chat = _peer->asChat()) {
return chat->amCreator() return chat->amCreator()
|| (chat->canBanMembers() && !chat->admins.contains(user)); || (chat->canBanMembers() && !chat->admins.contains(user));
} else if (const auto group = _peer->asMegagroup()) { } else if (const auto group = _peer->asMegagroup()) {
@ -1086,6 +1166,16 @@ std::unique_ptr<Row> MembersController::createRow(
return result; return result;
} }
std::unique_ptr<Row> MembersController::createInvitedRow(
not_null<UserData*> user) {
if (findRow(user)) {
return nullptr;
}
auto result = std::make_unique<Row>(this, user);
updateRow(result.get(), nullptr);
return result;
}
} // namespace } // namespace
GroupMembers::GroupMembers( GroupMembers::GroupMembers(

View file

@ -841,6 +841,7 @@ void Session::registerInvitedToCallUser(
} }
} }
_invitedToCallUsers[callId].emplace(user); _invitedToCallUsers[callId].emplace(user);
_invitesToCalls.fire({ callId, user });
} }
void Session::unregisterInvitedToCallUser( void Session::unregisterInvitedToCallUser(

View file

@ -166,6 +166,14 @@ public:
not_null<UserData*> user); not_null<UserData*> user);
void unregisterInvitedToCallUser(uint64 callId, not_null<UserData*> user); void unregisterInvitedToCallUser(uint64 callId, not_null<UserData*> user);
struct InviteToCall {
uint64 id = 0;
not_null<UserData*> user;
};
[[nodiscard]] rpl::producer<InviteToCall> invitesToCalls() const {
return _invitesToCalls.events();
}
void enumerateUsers(Fn<void(not_null<UserData*>)> action) const; void enumerateUsers(Fn<void(not_null<UserData*>)> action) const;
void enumerateGroups(Fn<void(not_null<PeerData*>)> action) const; void enumerateGroups(Fn<void(not_null<PeerData*>)> action) const;
void enumerateChannels(Fn<void(not_null<ChannelData*>)> action) const; void enumerateChannels(Fn<void(not_null<ChannelData*>)> action) const;
@ -923,6 +931,7 @@ private:
base::flat_set<not_null<ViewElement*>> _heavyViewParts; base::flat_set<not_null<ViewElement*>> _heavyViewParts;
base::flat_map<uint64, not_null<GroupCall*>> _groupCalls; base::flat_map<uint64, not_null<GroupCall*>> _groupCalls;
rpl::event_stream<InviteToCall> _invitesToCalls;
base::flat_map<uint64, base::flat_set<not_null<UserData*>>> _invitedToCallUsers; base::flat_map<uint64, base::flat_set<not_null<UserData*>>> _invitedToCallUsers;
History *_topPromoted = nullptr; History *_topPromoted = nullptr;