Added list of active group calls to Calls box.

This commit is contained in:
23rd 2023-01-20 18:18:24 +03:00 committed by John Preston
parent cd032f5c16
commit 37454b4ff4
5 changed files with 248 additions and 1 deletions

View File

@ -2694,6 +2694,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_call_box_clear_all" = "Clear All";
"lng_call_box_clear_sure" = "Are you sure you want to completely clear your calls log?";
"lng_call_box_clear_button" = "Clear";
"lng_call_box_groupcalls_subtitle" = "Active video chats";
"lng_call_outgoing" = "Outgoing call";
"lng_call_video_outgoing" = "Outgoing video call";

View File

@ -369,6 +369,10 @@ callCameraReDial: IconButton(callReDial) {
icon: icon {{ "calls/call_camera_active", menuIconFg }};
iconOver: icon {{ "calls/call_camera_active", menuIconFgOver }};
}
callGroupCall: IconButton(callCameraReDial) {
icon: icon {{ "top_bar_group_call", menuIconFg }};
iconOver: icon {{ "top_bar_group_call", menuIconFgOver }};
}
callRatingPadding: margins(24px, 12px, 24px, 0px);
callRatingStar: IconButton {

View File

@ -25,6 +25,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_changes.h"
#include "data/data_media_types.h"
#include "data/data_user.h"
#include "data/data_peer_values.h" // Data::ChannelHasActiveCall.
#include "data/data_group_call.h"
#include "data/data_channel.h"
#include "boxes/delete_messages_box.h"
#include "base/unixtime.h"
#include "api/api_updates.h"
@ -40,8 +43,201 @@ namespace {
constexpr auto kFirstPageCount = 20;
constexpr auto kPerPageCount = 100;
class GroupCallRow final : public PeerListRow {
public:
GroupCallRow(not_null<PeerData*> peer);
void rightActionAddRipple(
QPoint point,
Fn<void()> updateCallback) override;
void rightActionStopLastRipple() override;
int paintNameIconGetWidth(
Painter &p,
Fn<void()> repaint,
crl::time now,
int nameLeft,
int nameTop,
int nameWidth,
int availableWidth,
int outerWidth,
bool selected) override {
return 0;
}
QSize rightActionSize() const override {
return peer()->isChannel() ? QSize(_st.width, _st.height) : QSize();
}
QMargins rightActionMargins() const override {
return QMargins(
0,
0,
st::defaultPeerListItem.photoPosition.x(),
0);
}
void rightActionPaint(
Painter &p,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) override;
private:
const style::IconButton &_st;
std::unique_ptr<Ui::RippleAnimation> _actionRipple;
};
GroupCallRow::GroupCallRow(not_null<PeerData*> peer)
: PeerListRow(peer)
, _st(st::callGroupCall) {
if (const auto channel = peer->asChannel()) {
const auto status = (channel->isMegagroup()
? (channel->isPublic()
? tr::lng_create_public_channel_title
: tr::lng_create_private_channel_title)
: (channel->isPublic()
? tr::lng_create_public_group_title
: tr::lng_create_private_group_title))(tr::now);
setCustomStatus(status.toLower());
}
}
void GroupCallRow::rightActionPaint(
Painter &p,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) {
auto size = rightActionSize();
if (_actionRipple) {
_actionRipple->paint(
p,
x + _st.rippleAreaPosition.x(),
y + _st.rippleAreaPosition.y(),
outerWidth);
if (_actionRipple->empty()) {
_actionRipple.reset();
}
}
_st.icon.paintInCenter(
p,
style::rtlrect(x, y, size.width(), size.height(), outerWidth));
}
void GroupCallRow::rightActionAddRipple(
QPoint point,
Fn<void()> updateCallback) {
if (!_actionRipple) {
auto mask = Ui::RippleAnimation::EllipseMask(
QSize(_st.rippleAreaSize, _st.rippleAreaSize));
_actionRipple = std::make_unique<Ui::RippleAnimation>(
_st.ripple,
std::move(mask),
std::move(updateCallback));
}
_actionRipple->add(point - _st.rippleAreaPosition);
}
void GroupCallRow::rightActionStopLastRipple() {
if (_actionRipple) {
_actionRipple->lastStop();
}
}
} // namespace
namespace GroupCalls {
ListController::ListController(not_null<Window::SessionController*> window)
: _window(window) {
setStyleOverrides(&st::peerListSingleRow);
}
Main::Session &ListController::session() const {
return _window->session();
}
void ListController::prepare() {
const auto removeRow = [=](not_null<PeerData*> peer) {
const auto it = _groupCalls.find(peer->id);
if (it != end(_groupCalls)) {
const auto &row = it->second;
delegate()->peerListRemoveRow(row);
_groupCalls.erase(it);
}
};
const auto createRow = [=](not_null<PeerData*> peer) {
const auto it = _groupCalls.find(peer->id);
if (it == end(_groupCalls)) {
auto row = std::make_unique<GroupCallRow>(peer);
_groupCalls.emplace(peer->id, row.get());
delegate()->peerListAppendRow(std::move(row));
}
};
const auto processPeer = [=](PeerData *peer) {
if (!peer) {
return;
}
const auto channel = peer->asChannel();
if (channel && Data::ChannelHasActiveCall(channel)) {
createRow(peer);
} else {
removeRow(peer);
}
};
const auto finishProcess = [=] {
delegate()->peerListRefreshRows();
_fullCount = delegate()->peerListFullRowsCount();
};
session().changes().peerUpdates(
Data::PeerUpdate::Flag::GroupCall
) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
processPeer(update.peer);
finishProcess();
}, lifetime());
{
auto count = 0;
const auto list = session().data().chatsList(nullptr);
for (const auto &key : list->pinned()->order()) {
processPeer(key.peer());
}
for (const auto &key : list->indexed()->all()) {
if (count > kFirstPageCount) {
break;
}
processPeer(key->key().peer());
count++;
}
finishProcess();
}
}
rpl::producer<bool> ListController::shownValue() const {
return _fullCount.value(
) | rpl::map(rpl::mappers::_1 > 0) | rpl::distinct_until_changed();
}
void ListController::rowClicked(not_null<PeerListRow*> row) {
const auto window = _window;
const auto peer = row->peer();
crl::on_main(window, [=, peer = row->peer()] {
window->showPeerHistory(
peer,
Window::SectionShow::Way::ClearStack);
});
}
void ListController::rowRightActionClicked(not_null<PeerListRow*> row) {
_window->startOrJoinGroupCall(row->peer());
}
} // namespace GroupCalls
class BoxController::Row : public PeerListRow {
public:
Row(not_null<HistoryItem*> item);

View File

@ -15,6 +15,27 @@ class SessionController;
} // namespace Window
namespace Calls {
namespace GroupCalls {
class ListController : public PeerListController {
public:
explicit ListController(not_null<Window::SessionController*> window);
[[nodiscard]] rpl::producer<bool> shownValue() const;
Main::Session &session() const override;
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
void rowRightActionClicked(not_null<PeerListRow*> row) override;
private:
const not_null<Window::SessionController*> _window;
base::flat_map<PeerId, not_null<PeerListRow*>> _groupCalls;
rpl::variable<int> _fullCount;
};
} // namespace GroupCalls
class BoxController : public PeerListController {
public:
@ -34,6 +55,7 @@ private:
void receivedCalls(const QVector<MTPMessage> &result);
void refreshAbout();
class GroupCallRow;
class Row;
Row *rowForItem(not_null<const HistoryItem*> item);

View File

@ -96,16 +96,40 @@ constexpr auto kPlayStatusLimit = 2;
void ShowCallsBox(not_null<Window::SessionController*> window) {
struct State {
State(not_null<Window::SessionController*> window)
: callsController(window) {
: callsController(window)
, groupCallsController(window) {
}
Calls::BoxController callsController;
PeerListContentDelegateSimple callsDelegate;
Calls::GroupCalls::ListController groupCallsController;
PeerListContentDelegateSimple groupCallsDelegate;
base::unique_qptr<Ui::PopupMenu> menu;
};
window->show(Box([=](not_null<Ui::GenericBox*> box) {
const auto state = box->lifetime().make_state<State>(window);
const auto groupCalls = box->addRow(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
box,
object_ptr<Ui::VerticalLayout>(box)),
{});
groupCalls->hide(anim::type::instant);
groupCalls->toggleOn(state->groupCallsController.shownValue());
Settings::AddSubsectionTitle(
groupCalls->entity(),
tr::lng_call_box_groupcalls_subtitle());
state->groupCallsDelegate.setContent(groupCalls->entity()->add(
object_ptr<PeerListContent>(box, &state->groupCallsController),
{}));
state->groupCallsController.setDelegate(&state->groupCallsDelegate);
Settings::AddSkip(groupCalls->entity());
Settings::AddDivider(groupCalls->entity());
Settings::AddSkip(groupCalls->entity());
const auto content = box->addRow(
object_ptr<PeerListContent>(box, &state->callsController),
{});