mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-23 22:13:08 +02:00
Put prioritized users on top of inactive confcall.
This commit is contained in:
parent
844be11d43
commit
b583240d58
5 changed files with 284 additions and 36 deletions
|
@ -649,7 +649,7 @@ createCallListItem: PeerListItem(defaultPeerListItem) {
|
|||
}
|
||||
createCallList: PeerList(defaultPeerList) {
|
||||
item: createCallListItem;
|
||||
padding: margins(0px, 10px, 0px, 10px);
|
||||
padding: margins(0px, 6px, 0px, 6px);
|
||||
}
|
||||
|
||||
groupCallRecordingTimerPadding: margins(0px, 4px, 0px, 4px);
|
||||
|
|
|
@ -112,13 +112,21 @@ private:
|
|||
|
||||
};
|
||||
|
||||
struct PrioritizedSelector {
|
||||
object_ptr<Ui::RpWidget> content = { nullptr };
|
||||
Fn<bool(int, int, int)> overrideKey;
|
||||
Fn<void(PeerListRowId)> deselect;
|
||||
Fn<void()> activate;
|
||||
};
|
||||
|
||||
class ConfInviteController final : public ContactsBoxController {
|
||||
public:
|
||||
ConfInviteController(
|
||||
not_null<Main::Session*> session,
|
||||
ConfInviteStyles st,
|
||||
base::flat_set<not_null<UserData*>> alreadyIn,
|
||||
Fn<void()> shareLink);
|
||||
Fn<void()> shareLink,
|
||||
std::vector<not_null<UserData*>> prioritize);
|
||||
|
||||
[[nodiscard]] rpl::producer<bool> hasSelectedValue() const;
|
||||
[[nodiscard]] std::vector<InviteRequest> requests(
|
||||
|
@ -132,15 +140,27 @@ protected:
|
|||
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
void rowElementClicked(not_null<PeerListRow*> row, int element) override;
|
||||
bool handleDeselectForeignRow(PeerListRowId itemId) override;
|
||||
|
||||
bool overrideKeyboardNavigation(
|
||||
int direction,
|
||||
int fromIndex,
|
||||
int toIndex) override;
|
||||
private:
|
||||
[[nodiscard]] int fullCount() const;
|
||||
void toggleRowSelected(not_null<PeerListRow*> row, bool video);
|
||||
[[nodiscard]] bool toggleRowGetChecked(
|
||||
not_null<PeerListRow*> row,
|
||||
bool video);
|
||||
void addShareLinkButton();
|
||||
void addPriorityInvites();
|
||||
|
||||
const ConfInviteStyles _st;
|
||||
const base::flat_set<not_null<UserData*>> _alreadyIn;
|
||||
const std::vector<not_null<UserData*>> _prioritize;
|
||||
const Fn<void()> _shareLink;
|
||||
PrioritizedSelector _prioritizeRows;
|
||||
base::flat_set<not_null<UserData*>> _skip;
|
||||
rpl::variable<bool> _hasSelected;
|
||||
base::flat_set<not_null<UserData*>> _withVideo;
|
||||
bool _lastSelectWithVideo = false;
|
||||
|
@ -290,15 +310,160 @@ void ConfInviteRow::elementsPaint(
|
|||
paintElement(2);
|
||||
}
|
||||
|
||||
[[nodiscard]] PrioritizedSelector PrioritizedInviteSelector(
|
||||
const ConfInviteStyles &st,
|
||||
std::vector<not_null<UserData*>> users,
|
||||
Fn<bool(not_null<PeerListRow*>, bool)> toggleGetChecked,
|
||||
Fn<bool()> lastSelectWithVideo,
|
||||
Fn<void(bool)> setLastSelectWithVideo) {
|
||||
class PrioritizedController final : public PeerListController {
|
||||
public:
|
||||
PrioritizedController(
|
||||
const ConfInviteStyles &st,
|
||||
std::vector<not_null<UserData*>> users,
|
||||
Fn<bool(not_null<PeerListRow*>, bool)> toggleGetChecked,
|
||||
Fn<bool()> lastSelectWithVideo,
|
||||
Fn<void(bool)> setLastSelectWithVideo)
|
||||
: _st(st)
|
||||
, _users(std::move(users))
|
||||
, _toggleGetChecked(std::move(toggleGetChecked))
|
||||
, _lastSelectWithVideo(std::move(lastSelectWithVideo))
|
||||
, _setLastSelectWithVideo(std::move(setLastSelectWithVideo)) {
|
||||
Expects(!_users.empty());
|
||||
}
|
||||
|
||||
void prepare() override {
|
||||
for (const auto user : _users) {
|
||||
delegate()->peerListAppendRow(
|
||||
std::make_unique<ConfInviteRow>(user, _st));
|
||||
}
|
||||
delegate()->peerListRefreshRows();
|
||||
}
|
||||
void loadMoreRows() override {
|
||||
}
|
||||
void rowClicked(not_null<PeerListRow*> row) override {
|
||||
toggleRowSelected(row, _lastSelectWithVideo());
|
||||
}
|
||||
void rowElementClicked(
|
||||
not_null<PeerListRow*> row,
|
||||
int element) override {
|
||||
if (row->checked()) {
|
||||
static_cast<ConfInviteRow*>(row.get())->setVideo(
|
||||
element == 1);
|
||||
_setLastSelectWithVideo(element == 1);
|
||||
} else if (element == 1) {
|
||||
toggleRowSelected(row, true);
|
||||
} else if (element == 2) {
|
||||
toggleRowSelected(row, false);
|
||||
}
|
||||
}
|
||||
|
||||
void toggleRowSelected(not_null<PeerListRow*> row, bool video) {
|
||||
delegate()->peerListSetRowChecked(
|
||||
row,
|
||||
_toggleGetChecked(row, video));
|
||||
}
|
||||
|
||||
Main::Session &session() const override {
|
||||
return _users.front()->session();
|
||||
}
|
||||
|
||||
void toggleFirst() {
|
||||
Expects(delegate()->peerListFullRowsCount() > 0);
|
||||
|
||||
rowClicked(delegate()->peerListRowAt(0));
|
||||
}
|
||||
|
||||
private:
|
||||
const ConfInviteStyles &_st;
|
||||
std::vector<not_null<UserData*>> _users;
|
||||
Fn<bool(not_null<PeerListRow*>, bool)> _toggleGetChecked;
|
||||
Fn<bool()> _lastSelectWithVideo;
|
||||
Fn<void(bool)> _setLastSelectWithVideo;
|
||||
|
||||
};
|
||||
|
||||
auto result = object_ptr<Ui::VerticalLayout>((QWidget*)nullptr);
|
||||
const auto container = result.data();
|
||||
|
||||
const auto delegate = container->lifetime().make_state<
|
||||
PeerListContentDelegateSimple
|
||||
>();
|
||||
const auto controller = container->lifetime(
|
||||
).make_state<PrioritizedController>(
|
||||
st,
|
||||
users,
|
||||
toggleGetChecked,
|
||||
lastSelectWithVideo,
|
||||
setLastSelectWithVideo);
|
||||
const auto activate = [=] {
|
||||
controller->toggleFirst();
|
||||
};
|
||||
controller->setStyleOverrides(&st::createCallList);
|
||||
const auto content = container->add(object_ptr<PeerListContent>(
|
||||
container,
|
||||
controller));
|
||||
delegate->setContent(content);
|
||||
controller->setDelegate(delegate);
|
||||
|
||||
Ui::AddDivider(container);
|
||||
|
||||
const auto overrideKey = [=](int direction, int from, int to) {
|
||||
if (!content->isVisible()) {
|
||||
return false;
|
||||
} else if (direction > 0 && from < 0 && to >= 0) {
|
||||
if (content->hasSelection()) {
|
||||
const auto was = content->selectedIndex();
|
||||
const auto now = content->selectSkip(1).reallyMovedTo;
|
||||
if (was != now) {
|
||||
return true;
|
||||
}
|
||||
content->clearSelection();
|
||||
} else {
|
||||
content->selectSkip(1);
|
||||
return true;
|
||||
}
|
||||
} else if (direction < 0 && to < 0) {
|
||||
if (!content->hasSelection()) {
|
||||
content->selectLast();
|
||||
} else if (from >= 0 || content->hasSelection()) {
|
||||
content->selectSkip(-1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto deselect = [=](PeerListRowId rowId) {
|
||||
if (const auto row = delegate->peerListFindRow(rowId)) {
|
||||
delegate->peerListSetRowChecked(row, false);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
.content = std::move(result),
|
||||
.overrideKey = overrideKey,
|
||||
.deselect = deselect,
|
||||
.activate = activate,
|
||||
};
|
||||
}
|
||||
|
||||
ConfInviteController::ConfInviteController(
|
||||
not_null<Main::Session*> session,
|
||||
ConfInviteStyles st,
|
||||
base::flat_set<not_null<UserData*>> alreadyIn,
|
||||
Fn<void()> shareLink)
|
||||
Fn<void()> shareLink,
|
||||
std::vector<not_null<UserData*>> prioritize)
|
||||
: ContactsBoxController(session)
|
||||
, _st(st)
|
||||
, _alreadyIn(std::move(alreadyIn))
|
||||
, _prioritize(std::move(prioritize))
|
||||
, _shareLink(std::move(shareLink)) {
|
||||
if (!_shareLink) {
|
||||
_skip.reserve(_prioritize.size());
|
||||
for (const auto user : _prioritize) {
|
||||
_skip.emplace(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<bool> ConfInviteController::hasSelectedValue() const {
|
||||
|
@ -322,7 +487,8 @@ std::unique_ptr<PeerListRow> ConfInviteController::createRow(
|
|||
if (user->isSelf()
|
||||
|| user->isBot()
|
||||
|| user->isServiceUser()
|
||||
|| user->isInaccessible()) {
|
||||
|| user->isInaccessible()
|
||||
|| _skip.contains(user)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto result = std::make_unique<ConfInviteRow>(user, _st);
|
||||
|
@ -358,39 +524,87 @@ void ConfInviteController::rowElementClicked(
|
|||
}
|
||||
}
|
||||
|
||||
bool ConfInviteController::handleDeselectForeignRow(PeerListRowId itemId) {
|
||||
if (_prioritizeRows.deselect) {
|
||||
const auto userId = peerToUser(PeerId(itemId));
|
||||
if (ranges::contains(_prioritize, session().data().user(userId))) {
|
||||
_prioritizeRows.deselect(itemId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConfInviteController::overrideKeyboardNavigation(
|
||||
int direction,
|
||||
int fromIndex,
|
||||
int toIndex) {
|
||||
return _prioritizeRows.overrideKey
|
||||
&& _prioritizeRows.overrideKey(direction, fromIndex, toIndex);
|
||||
}
|
||||
|
||||
void ConfInviteController::toggleRowSelected(
|
||||
not_null<PeerListRow*> row,
|
||||
bool video) {
|
||||
delegate()->peerListSetRowChecked(row, toggleRowGetChecked(row, video));
|
||||
|
||||
// row may have been destroyed here, from search.
|
||||
_hasSelected = (delegate()->peerListSelectedRowsCount() > 0);
|
||||
}
|
||||
|
||||
bool ConfInviteController::toggleRowGetChecked(
|
||||
not_null<PeerListRow*> row,
|
||||
bool video) {
|
||||
auto count = fullCount();
|
||||
const auto conferenceLimit = session().appConfig().confcallSizeLimit();
|
||||
if (count < conferenceLimit || row->checked()) {
|
||||
const auto real = static_cast<ConfInviteRow*>(row.get());
|
||||
if (!row->checked()) {
|
||||
real->setVideo(video);
|
||||
_lastSelectWithVideo = video;
|
||||
}
|
||||
const auto user = row->peer()->asUser();
|
||||
if (!row->checked() && video) {
|
||||
_withVideo.emplace(user);
|
||||
} else {
|
||||
_withVideo.remove(user);
|
||||
}
|
||||
delegate()->peerListSetRowChecked(row, !row->checked());
|
||||
|
||||
// row may have been destroyed here, from search.
|
||||
_hasSelected = (delegate()->peerListSelectedRowsCount() > 0);
|
||||
} else {
|
||||
if (!row->checked() && count >= conferenceLimit) {
|
||||
delegate()->peerListUiShow()->showToast(
|
||||
tr::lng_group_call_invite_limit(tr::now));
|
||||
return false;
|
||||
}
|
||||
const auto real = static_cast<ConfInviteRow*>(row.get());
|
||||
if (!row->checked()) {
|
||||
real->setVideo(video);
|
||||
_lastSelectWithVideo = video;
|
||||
}
|
||||
const auto user = row->peer()->asUser();
|
||||
if (!row->checked() && video) {
|
||||
_withVideo.emplace(user);
|
||||
} else {
|
||||
_withVideo.remove(user);
|
||||
}
|
||||
return !row->checked();
|
||||
}
|
||||
|
||||
void ConfInviteController::prepareViewHook() {
|
||||
if (_shareLink) {
|
||||
addShareLinkButton();
|
||||
} else if (!_prioritize.empty()) {
|
||||
addPriorityInvites();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfInviteController::addPriorityInvites() {
|
||||
const auto toggleGetChecked = [=](not_null<PeerListRow*> row, bool video) {
|
||||
const auto result = toggleRowGetChecked(row, video);
|
||||
delegate()->peerListSetForeignRowChecked(
|
||||
row,
|
||||
result,
|
||||
anim::type::normal);
|
||||
|
||||
_hasSelected = (delegate()->peerListSelectedRowsCount() > 0);
|
||||
|
||||
return result;
|
||||
};
|
||||
_prioritizeRows = PrioritizedInviteSelector(
|
||||
_st,
|
||||
_prioritize,
|
||||
toggleGetChecked,
|
||||
[=] { return _lastSelectWithVideo; },
|
||||
[=](bool video) { _lastSelectWithVideo = video; });
|
||||
delegate()->peerListSetAboveWidget(std::move(_prioritizeRows.content));
|
||||
}
|
||||
|
||||
void ConfInviteController::addShareLinkButton() {
|
||||
auto button = object_ptr<Ui::PaddingWrap<Ui::SettingsButton>>(
|
||||
nullptr,
|
||||
|
@ -571,7 +785,8 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
|||
&real->session(),
|
||||
ConfInviteDarkStyles(),
|
||||
alreadyIn,
|
||||
shareLink);
|
||||
shareLink,
|
||||
std::vector<not_null<UserData*>>());
|
||||
const auto raw = controller.get();
|
||||
raw->setStyleOverrides(
|
||||
&st::groupCallInviteMembersList,
|
||||
|
@ -742,7 +957,8 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
|||
&user->session(),
|
||||
ConfInviteDarkStyles(),
|
||||
alreadyIn,
|
||||
shareLink);
|
||||
shareLink,
|
||||
std::vector<not_null<UserData*>>());
|
||||
const auto raw = controller.get();
|
||||
raw->setStyleOverrides(
|
||||
&st::groupCallInviteMembersList,
|
||||
|
@ -806,12 +1022,14 @@ void InitReActivate(not_null<PeerListBox*> box) {
|
|||
|
||||
object_ptr<Ui::BoxContent> PrepareInviteToEmptyBox(
|
||||
std::shared_ptr<Data::GroupCall> call,
|
||||
MsgId inviteMsgId) {
|
||||
MsgId inviteMsgId,
|
||||
std::vector<not_null<UserData*>> prioritize) {
|
||||
auto controller = std::make_unique<ConfInviteController>(
|
||||
&call->session(),
|
||||
ConfInviteDefaultStyles(),
|
||||
base::flat_set<not_null<UserData*>>(),
|
||||
nullptr);
|
||||
nullptr,
|
||||
std::move(prioritize));
|
||||
const auto raw = controller.get();
|
||||
raw->setStyleOverrides(&st::createCallList);
|
||||
const auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
|
@ -845,7 +1063,8 @@ object_ptr<Ui::BoxContent> PrepareInviteToEmptyBox(
|
|||
object_ptr<Ui::BoxContent> PrepareCreateCallBox(
|
||||
not_null<::Window::SessionController*> window,
|
||||
Fn<void()> created,
|
||||
MsgId discardedInviteMsgId) {
|
||||
MsgId discardedInviteMsgId,
|
||||
std::vector<not_null<UserData*>> prioritize) {
|
||||
struct State {
|
||||
bool creatingLink = false;
|
||||
QPointer<PeerListBox> box;
|
||||
|
@ -877,7 +1096,8 @@ object_ptr<Ui::BoxContent> PrepareCreateCallBox(
|
|||
&window->session(),
|
||||
ConfInviteDefaultStyles(),
|
||||
base::flat_set<not_null<UserData*>>(),
|
||||
discardedInviteMsgId ? Fn<void()>() : shareLink);
|
||||
discardedInviteMsgId ? Fn<void()>() : shareLink,
|
||||
std::move(prioritize));
|
||||
const auto raw = controller.get();
|
||||
if (discardedInviteMsgId) {
|
||||
raw->setStyleOverrides(&st::createCallList);
|
||||
|
|
|
@ -93,11 +93,13 @@ private:
|
|||
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareInviteToEmptyBox(
|
||||
std::shared_ptr<Data::GroupCall> call,
|
||||
MsgId inviteMsgId);
|
||||
MsgId inviteMsgId,
|
||||
std::vector<not_null<UserData*>> prioritize);
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareCreateCallBox(
|
||||
not_null<::Window::SessionController*> window,
|
||||
Fn<void()> created = nullptr,
|
||||
MsgId discardedInviteMsgId = 0);
|
||||
MsgId discardedInviteMsgId = 0,
|
||||
std::vector<not_null<UserData*>> prioritize = {});
|
||||
|
||||
} // namespace Calls::Group
|
||||
|
|
|
@ -115,8 +115,6 @@ int AppConfig::confcallSizeLimit() const {
|
|||
}
|
||||
|
||||
bool AppConfig::confcallPrioritizeVP8() const {
|
||||
AssertIsDebug();
|
||||
return false;
|
||||
return get<bool>(u"confcall_use_vp8"_q, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -853,6 +853,30 @@ void SessionNavigation::resolveConferenceCall(
|
|||
resolveConferenceCall({}, inviteMsgId, contextId);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<not_null<UserData*>> ExtractParticipantsForInvite(
|
||||
HistoryItem *item) {
|
||||
if (!item) {
|
||||
return {};
|
||||
}
|
||||
auto result = std::vector<not_null<UserData*>>();
|
||||
const auto add = [&](not_null<PeerData*> peer) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (!user->isSelf()
|
||||
&& !ranges::contains(result, not_null(user))) {
|
||||
result.push_back(user);
|
||||
}
|
||||
}
|
||||
};
|
||||
add(item->from());
|
||||
const auto media = item->media();
|
||||
if (const auto call = media ? media->call() : nullptr) {
|
||||
for (const auto &peer : call->otherParticipants) {
|
||||
add(peer);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SessionNavigation::resolveConferenceCall(
|
||||
QString slug,
|
||||
MsgId inviteMsgId,
|
||||
|
@ -877,6 +901,7 @@ void SessionNavigation::resolveConferenceCall(
|
|||
const auto slug = base::take(_conferenceCallSlug);
|
||||
const auto inviteMsgId = base::take(_conferenceCallInviteMsgId);
|
||||
const auto contextId = base::take(_conferenceCallResolveContextId);
|
||||
const auto context = session().data().message(contextId);
|
||||
result.data().vcall().match([&](const MTPDgroupCall &data) {
|
||||
const auto call = session().data().sharedConferenceCall(
|
||||
data.vid().v,
|
||||
|
@ -896,14 +921,14 @@ void SessionNavigation::resolveConferenceCall(
|
|||
close();
|
||||
}
|
||||
};
|
||||
const auto context = session().data().message(contextId);
|
||||
const auto inviter = context
|
||||
? context->from()->asUser()
|
||||
: nullptr;
|
||||
if (inviteMsgId && call->participants().empty()) {
|
||||
uiShow()->show(Calls::Group::PrepareInviteToEmptyBox(
|
||||
call,
|
||||
inviteMsgId));
|
||||
inviteMsgId,
|
||||
ExtractParticipantsForInvite(context)));
|
||||
} else {
|
||||
uiShow()->show(Box(
|
||||
Calls::Group::ConferenceCallJoinConfirm,
|
||||
|
@ -917,7 +942,8 @@ void SessionNavigation::resolveConferenceCall(
|
|||
Calls::Group::PrepareCreateCallBox(
|
||||
parentController(),
|
||||
nullptr,
|
||||
inviteMsgId));
|
||||
inviteMsgId,
|
||||
ExtractParticipantsForInvite(context)));
|
||||
} else {
|
||||
showToast(tr::lng_confcall_link_inactive(tr::now));
|
||||
}
|
||||
|
@ -925,14 +951,16 @@ void SessionNavigation::resolveConferenceCall(
|
|||
}).fail([=] {
|
||||
_conferenceCallRequestId = 0;
|
||||
_conferenceCallSlug = QString();
|
||||
_conferenceCallResolveContextId = FullMsgId();
|
||||
const auto contextId = base::take(_conferenceCallResolveContextId);
|
||||
const auto context = session().data().message(contextId);
|
||||
const auto inviteMsgId = base::take(_conferenceCallInviteMsgId);
|
||||
if (inviteMsgId) {
|
||||
uiShow()->show(
|
||||
Calls::Group::PrepareCreateCallBox(
|
||||
parentController(),
|
||||
nullptr,
|
||||
inviteMsgId));
|
||||
inviteMsgId,
|
||||
ExtractParticipantsForInvite(context)));
|
||||
} else {
|
||||
showToast(tr::lng_confcall_link_inactive(tr::now));
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue