mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-06 15:13:57 +02:00
PoC confcall invite, emoji.
This commit is contained in:
parent
dfe6ad3a32
commit
4401ea388c
11 changed files with 238 additions and 42 deletions
|
@ -124,22 +124,22 @@ uint64 ComputeEmojiIndex(bytes::const_span bytes) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::vector<EmojiPtr> ComputeEmojiFingerprint(not_null<Call*> call) {
|
std::vector<EmojiPtr> ComputeEmojiFingerprint(not_null<Call*> call) {
|
||||||
|
if (!call->isKeyShaForFingerprintReady()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return ComputeEmojiFingerprint(call->getKeyShaForFingerprint());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<EmojiPtr> ComputeEmojiFingerprint(
|
||||||
|
bytes::const_span fingerprint) {
|
||||||
auto result = std::vector<EmojiPtr>();
|
auto result = std::vector<EmojiPtr>();
|
||||||
constexpr auto EmojiCount = (base::array_size(Offsets) - 1);
|
constexpr auto EmojiCount = (base::array_size(Offsets) - 1);
|
||||||
for (auto index = 0; index != EmojiCount; ++index) {
|
|
||||||
auto offset = Offsets[index];
|
|
||||||
auto size = Offsets[index + 1] - offset;
|
|
||||||
auto string = QString::fromRawData(
|
|
||||||
reinterpret_cast<const QChar*>(Data + offset),
|
|
||||||
size);
|
|
||||||
auto emoji = Ui::Emoji::Find(string);
|
|
||||||
Assert(emoji != nullptr);
|
|
||||||
}
|
|
||||||
if (call->isKeyShaForFingerprintReady()) {
|
|
||||||
auto sha256 = call->getKeyShaForFingerprint();
|
|
||||||
constexpr auto kPartSize = 8;
|
constexpr auto kPartSize = 8;
|
||||||
for (auto partOffset = 0; partOffset != sha256.size(); partOffset += kPartSize) {
|
for (auto partOffset = 0
|
||||||
auto value = ComputeEmojiIndex(gsl::make_span(sha256).subspan(partOffset, kPartSize));
|
; partOffset != fingerprint.size()
|
||||||
|
; partOffset += kPartSize) {
|
||||||
|
auto value = ComputeEmojiIndex(
|
||||||
|
fingerprint.subspan(partOffset, kPartSize));
|
||||||
auto index = value % EmojiCount;
|
auto index = value % EmojiCount;
|
||||||
auto offset = Offsets[index];
|
auto offset = Offsets[index];
|
||||||
auto size = Offsets[index + 1] - offset;
|
auto size = Offsets[index + 1] - offset;
|
||||||
|
@ -150,7 +150,6 @@ std::vector<EmojiPtr> ComputeEmojiFingerprint(not_null<Call*> call) {
|
||||||
Assert(emoji != nullptr);
|
Assert(emoji != nullptr);
|
||||||
result.push_back(emoji);
|
result.push_back(emoji);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ class Call;
|
||||||
|
|
||||||
[[nodiscard]] std::vector<EmojiPtr> ComputeEmojiFingerprint(
|
[[nodiscard]] std::vector<EmojiPtr> ComputeEmojiFingerprint(
|
||||||
not_null<Call*> call);
|
not_null<Call*> call);
|
||||||
|
[[nodiscard]] std::vector<EmojiPtr> ComputeEmojiFingerprint(
|
||||||
|
bytes::const_span fingerprint);
|
||||||
|
|
||||||
[[nodiscard]] object_ptr<Ui::RpWidget> CreateFingerprintAndSignalBars(
|
[[nodiscard]] object_ptr<Ui::RpWidget> CreateFingerprintAndSignalBars(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
|
|
|
@ -1112,6 +1112,10 @@ bool GroupCall::rtmp() const {
|
||||||
return _rtmp;
|
return _rtmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GroupCall::conference() const {
|
||||||
|
return _conferenceCall != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool GroupCall::listenersHidden() const {
|
bool GroupCall::listenersHidden() const {
|
||||||
return _listenersHidden;
|
return _listenersHidden;
|
||||||
}
|
}
|
||||||
|
@ -1152,6 +1156,12 @@ rpl::producer<not_null<Data::GroupCall*>> GroupCall::real() const {
|
||||||
return _realChanges.events();
|
return _realChanges.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<QByteArray> GroupCall::emojiHashValue() const {
|
||||||
|
Expects(_e2e != nullptr);
|
||||||
|
|
||||||
|
return _e2e->emojiHashValue();
|
||||||
|
}
|
||||||
|
|
||||||
void GroupCall::start(TimeId scheduleDate, bool rtmp) {
|
void GroupCall::start(TimeId scheduleDate, bool rtmp) {
|
||||||
using Flag = MTPphone_CreateGroupCall::Flag;
|
using Flag = MTPphone_CreateGroupCall::Flag;
|
||||||
_createRequestId = _api.request(MTPphone_CreateGroupCall(
|
_createRequestId = _api.request(MTPphone_CreateGroupCall(
|
||||||
|
@ -1610,8 +1620,13 @@ void GroupCall::requestSubchainBlocks(int subchain, int height) {
|
||||||
MTP_int(kShortPollChainBlocksPerRequest)
|
MTP_int(kShortPollChainBlocksPerRequest)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
auto &state = _subchains[subchain];
|
auto &state = _subchains[subchain];
|
||||||
_peer->session().api().applyUpdates(result);
|
|
||||||
state.requestId = 0;
|
state.requestId = 0;
|
||||||
|
state.inShortPoll = true;
|
||||||
|
_peer->session().api().applyUpdates(result);
|
||||||
|
state.inShortPoll = false;
|
||||||
|
for (const auto &data : base::take(state.pending)) {
|
||||||
|
applySubChainUpdate(subchain, data.blocks, data.next);
|
||||||
|
}
|
||||||
_e2e->subchainBlocksRequestFinished(subchain);
|
_e2e->subchainBlocksRequestFinished(subchain);
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
auto &state = _subchains[subchain];
|
auto &state = _subchains[subchain];
|
||||||
|
@ -2221,11 +2236,26 @@ void GroupCall::handleUpdate(const MTPDupdateGroupCallChainBlocks &data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto &entry = _subchains[subchain];
|
auto &entry = _subchains[subchain];
|
||||||
const auto inpoll = entry.requestId != 0;
|
const auto &blocks = data.vblocks().v;
|
||||||
const auto next = data.vnext_offset().v;
|
const auto next = data.vnext_offset().v;
|
||||||
auto now = next - int(data.vblocks().v.size());
|
if (entry.requestId) {
|
||||||
for (const auto &block : data.vblocks().v) {
|
Assert(!entry.inShortPoll);
|
||||||
_e2e->apply(subchain, now++, { block.v }, inpoll);
|
entry.pending.push_back({ blocks, next });
|
||||||
|
} else {
|
||||||
|
applySubChainUpdate(subchain, blocks, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupCall::applySubChainUpdate(
|
||||||
|
int subchain,
|
||||||
|
const QVector<MTPbytes> &blocks,
|
||||||
|
int next) {
|
||||||
|
Expects(subchain >= 0 && subchain < kSubChainsCount);
|
||||||
|
|
||||||
|
auto &entry = _subchains[subchain];
|
||||||
|
auto now = next - int(blocks.size());
|
||||||
|
for (const auto &block : blocks) {
|
||||||
|
_e2e->apply(subchain, now++, { block.v }, entry.inShortPoll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3667,6 +3697,22 @@ std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
|
||||||
}
|
}
|
||||||
const auto owner = &_peer->owner();
|
const auto owner = &_peer->owner();
|
||||||
|
|
||||||
|
if (_conferenceCall) {
|
||||||
|
for (const auto &user : users) {
|
||||||
|
_api.request(MTPphone_InviteConferenceCallParticipant(
|
||||||
|
inputCall(),
|
||||||
|
user->inputUser
|
||||||
|
)).send();
|
||||||
|
}
|
||||||
|
auto result = std::variant<int, not_null<UserData*>>(0);
|
||||||
|
if (users.size() != 1) {
|
||||||
|
result = int(users.size());
|
||||||
|
} else {
|
||||||
|
result = users.front();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
auto count = 0;
|
auto count = 0;
|
||||||
auto slice = QVector<MTPInputUser>();
|
auto slice = QVector<MTPInputUser>();
|
||||||
auto result = std::variant<int, not_null<UserData*>>(0);
|
auto result = std::variant<int, not_null<UserData*>>(0);
|
||||||
|
|
|
@ -245,6 +245,7 @@ public:
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool scheduleStartSubscribed() const;
|
[[nodiscard]] bool scheduleStartSubscribed() const;
|
||||||
[[nodiscard]] bool rtmp() const;
|
[[nodiscard]] bool rtmp() const;
|
||||||
|
[[nodiscard]] bool conference() const;
|
||||||
[[nodiscard]] bool listenersHidden() const;
|
[[nodiscard]] bool listenersHidden() const;
|
||||||
[[nodiscard]] bool emptyRtmp() const;
|
[[nodiscard]] bool emptyRtmp() const;
|
||||||
[[nodiscard]] rpl::producer<bool> emptyRtmpValue() const;
|
[[nodiscard]] rpl::producer<bool> emptyRtmpValue() const;
|
||||||
|
@ -256,6 +257,7 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] Data::GroupCall *lookupReal() const;
|
[[nodiscard]] Data::GroupCall *lookupReal() const;
|
||||||
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
|
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
|
||||||
|
[[nodiscard]] rpl::producer<QByteArray> emojiHashValue() const;
|
||||||
|
|
||||||
void start(TimeId scheduleDate, bool rtmp);
|
void start(TimeId scheduleDate, bool rtmp);
|
||||||
void hangup();
|
void hangup();
|
||||||
|
@ -479,8 +481,14 @@ private:
|
||||||
ssrc = updatedSsrc;
|
ssrc = updatedSsrc;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
struct SubChainPending {
|
||||||
|
QVector<MTPbytes> blocks;
|
||||||
|
int next = 0;
|
||||||
|
};
|
||||||
struct SubChainState {
|
struct SubChainState {
|
||||||
|
std::vector<SubChainPending> pending;
|
||||||
mtpRequestId requestId = 0;
|
mtpRequestId requestId = 0;
|
||||||
|
bool inShortPoll = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
friend inline constexpr bool is_flag_type(SendUpdateType) {
|
friend inline constexpr bool is_flag_type(SendUpdateType) {
|
||||||
|
@ -515,6 +523,10 @@ private:
|
||||||
void handleUpdate(const MTPDupdateGroupCall &data);
|
void handleUpdate(const MTPDupdateGroupCall &data);
|
||||||
void handleUpdate(const MTPDupdateGroupCallParticipants &data);
|
void handleUpdate(const MTPDupdateGroupCallParticipants &data);
|
||||||
void handleUpdate(const MTPDupdateGroupCallChainBlocks &data);
|
void handleUpdate(const MTPDupdateGroupCallChainBlocks &data);
|
||||||
|
void applySubChainUpdate(
|
||||||
|
int subchain,
|
||||||
|
const QVector<MTPbytes> &blocks,
|
||||||
|
int next);
|
||||||
bool tryCreateController();
|
bool tryCreateController();
|
||||||
void destroyController();
|
void destroyController();
|
||||||
bool tryCreateScreencast();
|
bool tryCreateScreencast();
|
||||||
|
|
|
@ -56,6 +56,43 @@ namespace {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConfInviteController final : public ContactsBoxController {
|
||||||
|
public:
|
||||||
|
ConfInviteController(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
base::flat_set<not_null<UserData*>> alreadyIn,
|
||||||
|
Fn<void(not_null<PeerData*>)> choose)
|
||||||
|
: ContactsBoxController(session)
|
||||||
|
, _alreadyIn(std::move(alreadyIn))
|
||||||
|
, _choose(std::move(choose)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<PeerListRow> createRow(
|
||||||
|
not_null<UserData*> user) override {
|
||||||
|
if (user->isSelf()
|
||||||
|
|| user->isBot()
|
||||||
|
|| user->isServiceUser()
|
||||||
|
|| user->isInaccessible()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto result = ContactsBoxController::createRow(user);
|
||||||
|
if (_alreadyIn.contains(user)) {
|
||||||
|
result->setDisabledState(PeerListRow::State::DisabledChecked);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rowClicked(not_null<PeerListRow*> row) override {
|
||||||
|
_choose(row->peer());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const base::flat_set<not_null<UserData*>> _alreadyIn;
|
||||||
|
const Fn<void(not_null<PeerData*>)> _choose;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
InviteController::InviteController(
|
InviteController::InviteController(
|
||||||
|
@ -173,6 +210,7 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const auto peer = call->peer();
|
const auto peer = call->peer();
|
||||||
|
const auto weak = base::make_weak(call);
|
||||||
auto alreadyIn = peer->owner().invitedToCallUsers(real->id());
|
auto alreadyIn = peer->owner().invitedToCallUsers(real->id());
|
||||||
for (const auto &participant : real->participants()) {
|
for (const auto &participant : real->participants()) {
|
||||||
if (const auto user = participant.peer->asUser()) {
|
if (const auto user = participant.peer->asUser()) {
|
||||||
|
@ -180,6 +218,39 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alreadyIn.emplace(peer->session().user());
|
alreadyIn.emplace(peer->session().user());
|
||||||
|
if (call->conference()) {
|
||||||
|
const auto close = std::make_shared<Fn<void()>>();
|
||||||
|
const auto invite = [=](not_null<PeerData*> peer) {
|
||||||
|
Expects(peer->isUser());
|
||||||
|
|
||||||
|
const auto call = weak.get();
|
||||||
|
if (!call) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto user = peer->asUser();
|
||||||
|
call->inviteUsers({ user });
|
||||||
|
showToast(tr::lng_group_call_invite_done_user(
|
||||||
|
tr::now,
|
||||||
|
lt_user,
|
||||||
|
Ui::Text::Bold(user->firstName),
|
||||||
|
Ui::Text::WithEntities));
|
||||||
|
(*close)();
|
||||||
|
};
|
||||||
|
auto controller = std::make_unique<ConfInviteController>(
|
||||||
|
&real->session(),
|
||||||
|
alreadyIn,
|
||||||
|
invite);
|
||||||
|
controller->setStyleOverrides(
|
||||||
|
&st::groupCallInviteMembersList,
|
||||||
|
&st::groupCallMultiSelect);
|
||||||
|
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||||
|
box->setTitle(tr::lng_group_call_invite_title());
|
||||||
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
|
*close = [=] { box->closeBox(); };
|
||||||
|
};
|
||||||
|
return Box<PeerListBox>(std::move(controller), initBox);
|
||||||
|
}
|
||||||
|
|
||||||
auto controller = std::make_unique<InviteController>(peer, alreadyIn);
|
auto controller = std::make_unique<InviteController>(peer, alreadyIn);
|
||||||
controller->setStyleOverrides(
|
controller->setStyleOverrides(
|
||||||
&st::groupCallInviteMembersList,
|
&st::groupCallInviteMembersList,
|
||||||
|
@ -194,7 +265,6 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||||
&st::groupCallInviteMembersList,
|
&st::groupCallInviteMembersList,
|
||||||
&st::groupCallMultiSelect);
|
&st::groupCallMultiSelect);
|
||||||
|
|
||||||
const auto weak = base::make_weak(call);
|
|
||||||
const auto invite = [=](const std::vector<not_null<UserData*>> &users) {
|
const auto invite = [=](const std::vector<not_null<UserData*>> &users) {
|
||||||
const auto call = weak.get();
|
const auto call = weak.get();
|
||||||
if (!call) {
|
if (!call) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "calls/group/calls_group_invite_controller.h"
|
#include "calls/group/calls_group_invite_controller.h"
|
||||||
#include "calls/group/ui/calls_group_scheduled_labels.h"
|
#include "calls/group/ui/calls_group_scheduled_labels.h"
|
||||||
#include "calls/group/ui/desktop_capture_choose_source.h"
|
#include "calls/group/ui/desktop_capture_choose_source.h"
|
||||||
|
#include "calls/calls_emoji_fingerprint.h"
|
||||||
#include "ui/platform/ui_platform_window_title.h"
|
#include "ui/platform/ui_platform_window_title.h"
|
||||||
#include "ui/platform/ui_platform_utility.h"
|
#include "ui/platform/ui_platform_utility.h"
|
||||||
#include "ui/controls/call_mute_button.h"
|
#include "ui/controls/call_mute_button.h"
|
||||||
|
@ -76,6 +77,19 @@ constexpr auto kControlsBackgroundOpacity = 0.8;
|
||||||
constexpr auto kOverrideActiveColorBgAlpha = 172;
|
constexpr auto kOverrideActiveColorBgAlpha = 172;
|
||||||
constexpr auto kHideControlsTimeout = 5 * crl::time(1000);
|
constexpr auto kHideControlsTimeout = 5 * crl::time(1000);
|
||||||
|
|
||||||
|
[[nodiscard]] QString ComposeTitle(const QByteArray &hash) {
|
||||||
|
auto result = tr::lng_confcall_join_title(tr::now);
|
||||||
|
if (hash.size() >= 32) {
|
||||||
|
const auto fp = bytes::make_span(hash).subspan(0, 32);
|
||||||
|
const auto emoji = Calls::ComputeEmojiFingerprint(fp);
|
||||||
|
result += QString::fromUtf8(" \xc2\xb7 ");
|
||||||
|
for (const auto &single : emoji) {
|
||||||
|
result += single->text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
class Show final : public Main::SessionShow {
|
class Show final : public Main::SessionShow {
|
||||||
public:
|
public:
|
||||||
explicit Show(not_null<Panel*> panel);
|
explicit Show(not_null<Panel*> panel);
|
||||||
|
@ -367,7 +381,13 @@ void Panel::initWindow() {
|
||||||
window()->setAttribute(Qt::WA_NoSystemBackground);
|
window()->setAttribute(Qt::WA_NoSystemBackground);
|
||||||
window()->setTitleStyle(st::groupCallTitle);
|
window()->setTitleStyle(st::groupCallTitle);
|
||||||
|
|
||||||
|
if (_call->conference()) {
|
||||||
|
titleText() | rpl::start_with_next([=](const QString &text) {
|
||||||
|
window()->setTitle(text);
|
||||||
|
}, lifetime());
|
||||||
|
} else {
|
||||||
subscribeToPeerChanges();
|
subscribeToPeerChanges();
|
||||||
|
}
|
||||||
|
|
||||||
base::install_event_filter(window().get(), [=](not_null<QEvent*> e) {
|
base::install_event_filter(window().get(), [=](not_null<QEvent*> e) {
|
||||||
if (e->type() == QEvent::Close && handleClose()) {
|
if (e->type() == QEvent::Close && handleClose()) {
|
||||||
|
@ -2445,9 +2465,11 @@ void Panel::updateMembersGeometry() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::refreshTitle() {
|
rpl::producer<QString> Panel::titleText() {
|
||||||
if (!_title) {
|
if (_call->conference()) {
|
||||||
auto text = rpl::combine(
|
return _call->emojiHashValue() | rpl::map(ComposeTitle);
|
||||||
|
}
|
||||||
|
return rpl::combine(
|
||||||
Info::Profile::NameValue(_peer),
|
Info::Profile::NameValue(_peer),
|
||||||
rpl::single(
|
rpl::single(
|
||||||
QString()
|
QString()
|
||||||
|
@ -2457,7 +2479,12 @@ void Panel::refreshTitle() {
|
||||||
}) | rpl::flatten_latest())
|
}) | rpl::flatten_latest())
|
||||||
) | rpl::map([=](const QString &name, const QString &title) {
|
) | rpl::map([=](const QString &name, const QString &title) {
|
||||||
return title.isEmpty() ? name : title;
|
return title.isEmpty() ? name : title;
|
||||||
}) | rpl::after_next([=] {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::refreshTitle() {
|
||||||
|
if (!_title) {
|
||||||
|
auto text = titleText() | rpl::after_next([=] {
|
||||||
refreshTitleGeometry();
|
refreshTitleGeometry();
|
||||||
});
|
});
|
||||||
_title.create(
|
_title.create(
|
||||||
|
|
|
@ -155,6 +155,7 @@ private:
|
||||||
void setupMembers();
|
void setupMembers();
|
||||||
void setupVideo(not_null<Viewport*> viewport);
|
void setupVideo(not_null<Viewport*> viewport);
|
||||||
void setupRealMuteButtonState(not_null<Data::GroupCall*> real);
|
void setupRealMuteButtonState(not_null<Data::GroupCall*> real);
|
||||||
|
[[nodiscard]] rpl::producer<QString> titleText();
|
||||||
|
|
||||||
bool handleClose();
|
bool handleClose();
|
||||||
void startScheduledNow();
|
void startScheduledNow();
|
||||||
|
|
|
@ -52,6 +52,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
|
#include "window/window_session_controller.h"
|
||||||
#include "calls/calls_instance.h"
|
#include "calls/calls_instance.h"
|
||||||
#include "spellcheck/spellcheck_types.h"
|
#include "spellcheck/spellcheck_types.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
|
@ -1225,6 +1226,12 @@ void History::applyServiceChanges(
|
||||||
topic->setHidden(mtpIsTrue(*hidden));
|
topic->setHidden(mtpIsTrue(*hidden));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, [&](const MTPDmessageActionConferenceCall &data) {
|
||||||
|
if (!data.is_active() && !data.is_missed()) {
|
||||||
|
if (const auto window = session().tryResolveWindow()) {
|
||||||
|
window->resolveConferenceCall(qs(data.vslug()), item->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}, [](const auto &) {
|
}, [](const auto &) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5634,6 +5634,22 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
|
||||||
: duration
|
: duration
|
||||||
? tr::lng_action_confcall_finished(tr::now)
|
? tr::lng_action_confcall_finished(tr::now)
|
||||||
: tr::lng_action_confcall_invitation(tr::now);
|
: tr::lng_action_confcall_invitation(tr::now);
|
||||||
|
|
||||||
|
if (duration) {
|
||||||
|
result.text.text += " (" + QString::number(duration) + " seconds)";
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto id = this->id;
|
||||||
|
const auto slug = qs(action.vslug());
|
||||||
|
setCustomServiceLink(std::make_shared<LambdaClickHandler>([=](
|
||||||
|
ClickContext context) {
|
||||||
|
const auto my = context.other.value<ClickHandlerContext>();
|
||||||
|
const auto weak = my.sessionWindow;
|
||||||
|
if (const auto strong = weak.get()) {
|
||||||
|
strong->resolveConferenceCall(slug, id);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -840,12 +840,16 @@ void SessionNavigation::resolveCollectible(
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionNavigation::resolveConferenceCall(const QString &slug) {
|
void SessionNavigation::resolveConferenceCall(
|
||||||
if (_conferenceCallSlug == slug) {
|
const QString &slug,
|
||||||
|
MsgId inviteMsgId) {
|
||||||
|
if (_conferenceCallSlug == slug
|
||||||
|
&& _conferenceCallInviteMsgId == inviteMsgId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_api.request(base::take(_conferenceCallRequestId)).cancel();
|
_api.request(base::take(_conferenceCallRequestId)).cancel();
|
||||||
_conferenceCallSlug = slug;
|
_conferenceCallSlug = slug;
|
||||||
|
_conferenceCallInviteMsgId = inviteMsgId;
|
||||||
|
|
||||||
const auto limit = 5;
|
const auto limit = 5;
|
||||||
_conferenceCallRequestId = _api.request(MTPphone_GetGroupCall(
|
_conferenceCallRequestId = _api.request(MTPphone_GetGroupCall(
|
||||||
|
@ -864,15 +868,26 @@ void SessionNavigation::resolveConferenceCall(const QString &slug) {
|
||||||
false, // rtmp
|
false, // rtmp
|
||||||
true); // conference
|
true); // conference
|
||||||
call->processFullCall(result);
|
call->processFullCall(result);
|
||||||
|
const auto confirmed = std::make_shared<bool>();
|
||||||
const auto join = [=] {
|
const auto join = [=] {
|
||||||
Core::App().calls().startOrJoinConferenceCall(
|
*confirmed = true;
|
||||||
uiShow(),
|
Core::App().calls().startOrJoinConferenceCall(uiShow(), {
|
||||||
{ .call = call, .linkSlug = slug });
|
.call = call,
|
||||||
|
.linkSlug = slug,
|
||||||
|
.joinMessageId = inviteMsgId,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
uiShow()->show(Box(
|
const auto box = uiShow()->show(Box(
|
||||||
Calls::Group::ConferenceCallJoinConfirm,
|
Calls::Group::ConferenceCallJoinConfirm,
|
||||||
call,
|
call,
|
||||||
join));
|
join));
|
||||||
|
box->boxClosing() | rpl::start_with_next([=] {
|
||||||
|
if (inviteMsgId && !*confirmed) {
|
||||||
|
_api.request(MTPphone_DeclineConferenceCallInvite(
|
||||||
|
MTP_int(inviteMsgId)
|
||||||
|
)).send();
|
||||||
|
}
|
||||||
|
}, box->lifetime());
|
||||||
});
|
});
|
||||||
}).fail([=] {
|
}).fail([=] {
|
||||||
_conferenceCallRequestId = 0;
|
_conferenceCallRequestId = 0;
|
||||||
|
|
|
@ -264,7 +264,7 @@ public:
|
||||||
PeerId ownerId,
|
PeerId ownerId,
|
||||||
const QString &entity,
|
const QString &entity,
|
||||||
Fn<void(QString)> fail = nullptr);
|
Fn<void(QString)> fail = nullptr);
|
||||||
void resolveConferenceCall(const QString &slug);
|
void resolveConferenceCall(const QString &slug, MsgId inviteMsgId = 0);
|
||||||
|
|
||||||
base::weak_ptr<Ui::Toast::Instance> showToast(
|
base::weak_ptr<Ui::Toast::Instance> showToast(
|
||||||
Ui::Toast::Config &&config);
|
Ui::Toast::Config &&config);
|
||||||
|
@ -331,6 +331,7 @@ private:
|
||||||
mtpRequestId _collectibleRequestId = 0;
|
mtpRequestId _collectibleRequestId = 0;
|
||||||
|
|
||||||
QString _conferenceCallSlug;
|
QString _conferenceCallSlug;
|
||||||
|
MsgId _conferenceCallInviteMsgId;
|
||||||
mtpRequestId _conferenceCallRequestId = 0;
|
mtpRequestId _conferenceCallRequestId = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue