Allow enable/disable video in a call.
Before Width: | Height: | Size: 456 B After Width: | Height: | Size: 595 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/call_camera_active.png
Normal file
After Width: | Height: | Size: 377 B |
BIN
Telegram/Resources/icons/call_camera_active@2x.png
Normal file
After Width: | Height: | Size: 733 B |
BIN
Telegram/Resources/icons/call_camera_active@3x.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/call_camera_muted.png
Normal file
After Width: | Height: | Size: 727 B |
BIN
Telegram/Resources/icons/call_camera_muted@2x.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/call_camera_muted@3x.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 405 B After Width: | Height: | Size: 460 B |
Before Width: | Height: | Size: 736 B After Width: | Height: | Size: 970 B |
Before Width: | Height: | Size: 886 B After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 412 B After Width: | Height: | Size: 489 B |
Before Width: | Height: | Size: 800 B After Width: | Height: | Size: 1,002 B |
Before Width: | Height: | Size: 945 B After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 459 B After Width: | Height: | Size: 744 B |
Before Width: | Height: | Size: 843 B After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 2.4 KiB |
|
@ -84,6 +84,13 @@ callMuteToggle: IconButton(callButton) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callUnmuteIcon: icon {{ "call_record_muted", callIconFg }};
|
callUnmuteIcon: icon {{ "call_record_muted", callIconFg }};
|
||||||
|
callCameraToggle: IconButton(callButton) {
|
||||||
|
icon: icon {{ "call_camera_active", callIconFg }};
|
||||||
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
color: callMuteRipple;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callNoCameraIcon: icon {{ "call_camera_muted", callIconFg }};
|
||||||
|
|
||||||
callControlsTop: 80px;
|
callControlsTop: 80px;
|
||||||
callControlsSkip: 0px;
|
callControlsSkip: 0px;
|
||||||
|
@ -124,7 +131,7 @@ callBarMuteToggle: IconButton {
|
||||||
height: 38px;
|
height: 38px;
|
||||||
|
|
||||||
icon: icon {{ "call_record_active", callBarFg }};
|
icon: icon {{ "call_record_active", callBarFg }};
|
||||||
iconPosition: point(9px, 8px);
|
iconPosition: point(3px, 2px);
|
||||||
|
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: callBarMuteRipple;
|
color: callBarMuteRipple;
|
||||||
|
@ -137,7 +144,7 @@ callBarRightSkip: 12px;
|
||||||
callBarSkip: 10px;
|
callBarSkip: 10px;
|
||||||
callBarHangup: IconButton(callBarMuteToggle) {
|
callBarHangup: IconButton(callBarMuteToggle) {
|
||||||
icon: icon {{ "call_discard", callBarFg }};
|
icon: icon {{ "call_discard", callBarFg }};
|
||||||
iconPosition: point(9px, 11px);
|
iconPosition: point(3px, 1px);
|
||||||
}
|
}
|
||||||
callBarLabel: LabelSimple(defaultLabelSimple) {
|
callBarLabel: LabelSimple(defaultLabelSimple) {
|
||||||
font: semiboldFont;
|
font: semiboldFont;
|
||||||
|
|
|
@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "facades.h"
|
#include "facades.h"
|
||||||
|
|
||||||
#include <tgcalls/Instance.h>
|
#include <tgcalls/Instance.h>
|
||||||
|
#include <tgcalls/VideoCaptureInterface.h>
|
||||||
|
|
||||||
namespace tgcalls {
|
namespace tgcalls {
|
||||||
class InstanceImpl;
|
class InstanceImpl;
|
||||||
|
@ -42,6 +43,7 @@ namespace {
|
||||||
constexpr auto kMinLayer = 65;
|
constexpr auto kMinLayer = 65;
|
||||||
constexpr auto kHangupTimeoutMs = 5000;
|
constexpr auto kHangupTimeoutMs = 5000;
|
||||||
constexpr auto kSha256Size = 32;
|
constexpr auto kSha256Size = 32;
|
||||||
|
constexpr auto kDropFramesWhileInactive = 5 * crl::time(1000);
|
||||||
const auto kDefaultVersion = "2.4.4"_q;
|
const auto kDefaultVersion = "2.4.4"_q;
|
||||||
|
|
||||||
const auto RegisterTag = tgcalls::Register<tgcalls::InstanceImpl>();
|
const auto RegisterTag = tgcalls::Register<tgcalls::InstanceImpl>();
|
||||||
|
@ -319,12 +321,31 @@ void Call::actuallyAnswer() {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Call::setMute(bool mute) {
|
void Call::setMuted(bool mute) {
|
||||||
_mute = mute;
|
_muted = mute;
|
||||||
if (_instance) {
|
if (_instance) {
|
||||||
_instance->setMuteMicrophone(_mute);
|
_instance->setMuteMicrophone(mute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Call::setVideoEnabled(bool enabled) {
|
||||||
|
if (_state.current() != State::Established) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_videoEnabled = enabled;
|
||||||
|
if (enabled) {
|
||||||
|
if (!_videoCapture) {
|
||||||
|
_videoCapture = tgcalls::VideoCaptureInterface::Create();
|
||||||
|
}
|
||||||
|
if (_instance) {
|
||||||
|
_instance->requestVideo(_videoCapture);
|
||||||
|
} else {
|
||||||
|
_videoState = VideoState::OutgoingRequested;
|
||||||
|
}
|
||||||
|
_videoCapture->setIsVideoEnabled(true);
|
||||||
|
} else if (_videoCapture) {
|
||||||
|
_videoCapture->setIsVideoEnabled(false);
|
||||||
}
|
}
|
||||||
_muteChanged.notify(_mute);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crl::time Call::getDurationMs() const {
|
crl::time Call::getDurationMs() const {
|
||||||
|
@ -430,6 +451,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||||
}
|
}
|
||||||
_id = data.vid().v;
|
_id = data.vid().v;
|
||||||
_accessHash = data.vaccess_hash().v;
|
_accessHash = data.vaccess_hash().v;
|
||||||
|
setVideoEnabled(data.is_video());
|
||||||
auto gaHashBytes = bytes::make_span(data.vg_a_hash().v);
|
auto gaHashBytes = bytes::make_span(data.vg_a_hash().v);
|
||||||
if (gaHashBytes.size() != kSha256Size) {
|
if (gaHashBytes.size() != kSha256Size) {
|
||||||
LOG(("Call Error: Wrong g_a_hash size %1, expected %2."
|
LOG(("Call Error: Wrong g_a_hash size %1, expected %2."
|
||||||
|
@ -650,7 +672,7 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||||
.encryptionKey = tgcalls::EncryptionKey(
|
.encryptionKey = tgcalls::EncryptionKey(
|
||||||
std::move(encryptionKeyValue),
|
std::move(encryptionKeyValue),
|
||||||
(_type == Type::Outgoing)),
|
(_type == Type::Outgoing)),
|
||||||
.videoCapture = nullptr,
|
.videoCapture = _videoEnabled.current() ? _videoCapture : nullptr,
|
||||||
.stateUpdated = [=](tgcalls::State state, tgcalls::VideoState videoState) {
|
.stateUpdated = [=](tgcalls::State state, tgcalls::VideoState videoState) {
|
||||||
crl::on_main(weak, [=] {
|
crl::on_main(weak, [=] {
|
||||||
handleControllerStateChange(state, videoState);
|
handleControllerStateChange(state, videoState);
|
||||||
|
@ -662,6 +684,14 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.remoteVideoIsActiveUpdated = [=](bool active) {
|
.remoteVideoIsActiveUpdated = [=](bool active) {
|
||||||
|
crl::on_main(weak, [=] {
|
||||||
|
if (!active) {
|
||||||
|
_frames.fire(QImage());
|
||||||
|
_remoteVideoInactiveFrom = crl::now();
|
||||||
|
} else {
|
||||||
|
_remoteVideoInactiveFrom = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
.signalingDataEmitted = [=](const std::vector<uint8_t> &data) {
|
.signalingDataEmitted = [=](const std::vector<uint8_t> &data) {
|
||||||
const auto bytes = QByteArray(
|
const auto bytes = QByteArray(
|
||||||
|
@ -706,8 +736,6 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptor.videoCapture = tgcalls::CreateVideoCapture();
|
|
||||||
|
|
||||||
const auto version = call.vprotocol().match([&](
|
const auto version = call.vprotocol().match([&](
|
||||||
const MTPDphoneCallProtocol &data) {
|
const MTPDphoneCallProtocol &data) {
|
||||||
return data.vlibrary_versions().v;
|
return data.vlibrary_versions().v;
|
||||||
|
@ -727,13 +755,18 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto raw = _instance.get();
|
const auto raw = _instance.get();
|
||||||
if (_mute) {
|
if (_muted.current()) {
|
||||||
raw->setMuteMicrophone(_mute);
|
raw->setMuteMicrophone(_muted.current());
|
||||||
}
|
}
|
||||||
const auto &settings = Core::App().settings();
|
const auto &settings = Core::App().settings();
|
||||||
raw->setIncomingVideoOutput(webrtc::CreateVideoSink([=](QImage frame) {
|
raw->setIncomingVideoOutput(webrtc::CreateVideoSink([=](QImage frame) {
|
||||||
crl::on_main(weak, [=] {
|
crl::on_main(weak, [=] {
|
||||||
_frames.fire_copy(frame);
|
if (_remoteVideoInactiveFrom > 0
|
||||||
|
&& (_remoteVideoInactiveFrom + kDropFramesWhileInactive
|
||||||
|
> crl::now())) {
|
||||||
|
} else {
|
||||||
|
_frames.fire_copy(frame);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
raw->setAudioOutputDevice(
|
raw->setAudioOutputDevice(
|
||||||
|
@ -748,6 +781,18 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||||
void Call::handleControllerStateChange(
|
void Call::handleControllerStateChange(
|
||||||
tgcalls::State state,
|
tgcalls::State state,
|
||||||
tgcalls::VideoState videoState) {
|
tgcalls::VideoState videoState) {
|
||||||
|
_videoState = [&] {
|
||||||
|
switch (videoState) {
|
||||||
|
case tgcalls::VideoState::Possible: return VideoState::Disabled;
|
||||||
|
case tgcalls::VideoState::OutgoingRequested:
|
||||||
|
return VideoState::OutgoingRequested;
|
||||||
|
case tgcalls::VideoState::IncomingRequested:
|
||||||
|
return VideoState::IncomingRequested;
|
||||||
|
case tgcalls::VideoState::Active: return VideoState::Enabled;
|
||||||
|
}
|
||||||
|
Unexpected("VideoState value in Call::handleControllerStateChange.");
|
||||||
|
}();
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case tgcalls::State::WaitInit: {
|
case tgcalls::State::WaitInit: {
|
||||||
DEBUG_LOG(("Call Info: State changed to WaitingInit."));
|
DEBUG_LOG(("Call Info: State changed to WaitingInit."));
|
||||||
|
@ -780,10 +825,7 @@ void Call::handleControllerBarCountChange(int count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Call::setSignalBarCount(int count) {
|
void Call::setSignalBarCount(int count) {
|
||||||
if (_signalBarCount != count) {
|
_signalBarCount = count;
|
||||||
_signalBarCount = count;
|
|
||||||
_signalBarCountChanged.notify(count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -986,9 +1028,7 @@ void Call::handleControllerError(const QString &error) {
|
||||||
|
|
||||||
void Call::destroyController() {
|
void Call::destroyController() {
|
||||||
if (_instance) {
|
if (_instance) {
|
||||||
AssertIsDebug();
|
|
||||||
const auto state = _instance->stop();
|
const auto state = _instance->stop();
|
||||||
LOG(("CALL_LOG: %1").arg(QString::fromStdString(state.debugLog)));
|
|
||||||
|
|
||||||
DEBUG_LOG(("Call Info: Destroying call controller.."));
|
DEBUG_LOG(("Call Info: Destroying call controller.."));
|
||||||
_instance.reset();
|
_instance.reset();
|
||||||
|
|
|
@ -21,6 +21,7 @@ class Track;
|
||||||
|
|
||||||
namespace tgcalls {
|
namespace tgcalls {
|
||||||
class Instance;
|
class Instance;
|
||||||
|
class VideoCaptureInterface;
|
||||||
enum class State;
|
enum class State;
|
||||||
enum class VideoState;
|
enum class VideoState;
|
||||||
} // namespace tgcalls
|
} // namespace tgcalls
|
||||||
|
@ -91,29 +92,50 @@ public:
|
||||||
Ringing,
|
Ringing,
|
||||||
Busy,
|
Busy,
|
||||||
};
|
};
|
||||||
State state() const {
|
[[nodiscard]] State state() const {
|
||||||
return _state.current();
|
return _state.current();
|
||||||
}
|
}
|
||||||
rpl::producer<State> stateValue() const {
|
[[nodiscard]] rpl::producer<State> stateValue() const {
|
||||||
return _state.value();
|
return _state.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class VideoState {
|
||||||
|
Disabled,
|
||||||
|
OutgoingRequested,
|
||||||
|
IncomingRequested,
|
||||||
|
Enabled
|
||||||
|
};
|
||||||
|
[[nodiscard]] VideoState videoState() const {
|
||||||
|
return _videoState.current();
|
||||||
|
}
|
||||||
|
[[nodiscard]] rpl::producer<VideoState> videoStateValue() const {
|
||||||
|
return _videoState.value();
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr auto kSignalBarStarting = -1;
|
static constexpr auto kSignalBarStarting = -1;
|
||||||
static constexpr auto kSignalBarFinished = -2;
|
static constexpr auto kSignalBarFinished = -2;
|
||||||
static constexpr auto kSignalBarCount = 4;
|
static constexpr auto kSignalBarCount = 4;
|
||||||
base::Observable<int> &signalBarCountChanged() {
|
[[nodiscard]] rpl::producer<int> signalBarCountValue() const {
|
||||||
return _signalBarCountChanged;
|
return _signalBarCount.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMute(bool mute);
|
void setMuted(bool mute);
|
||||||
bool isMute() const {
|
[[nodiscard]] bool muted() const {
|
||||||
return _mute;
|
return _muted.current();
|
||||||
}
|
}
|
||||||
base::Observable<bool> &muteChanged() {
|
[[nodiscard]] rpl::producer<bool> mutedValue() const {
|
||||||
return _muteChanged;
|
return _muted.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<QImage> frames() const {
|
void setVideoEnabled(bool enabled);
|
||||||
|
[[nodiscard]] bool videoEnabled() const {
|
||||||
|
return _videoEnabled.current();
|
||||||
|
}
|
||||||
|
[[nodiscard]] rpl::producer<bool> videoEnabledValue() const {
|
||||||
|
return _videoEnabled.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<QImage> frames() const {
|
||||||
return _frames.events();
|
return _frames.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,17 +200,18 @@ private:
|
||||||
MTP::Sender _api;
|
MTP::Sender _api;
|
||||||
Type _type = Type::Outgoing;
|
Type _type = Type::Outgoing;
|
||||||
rpl::variable<State> _state = State::Starting;
|
rpl::variable<State> _state = State::Starting;
|
||||||
|
rpl::variable<VideoState> _videoState = VideoState::Disabled;
|
||||||
FinishType _finishAfterRequestingCall = FinishType::None;
|
FinishType _finishAfterRequestingCall = FinishType::None;
|
||||||
bool _answerAfterDhConfigReceived = false;
|
bool _answerAfterDhConfigReceived = false;
|
||||||
int _signalBarCount = kSignalBarStarting;
|
rpl::variable<int> _signalBarCount = kSignalBarStarting;
|
||||||
base::Observable<int> _signalBarCountChanged;
|
|
||||||
crl::time _startTime = 0;
|
crl::time _startTime = 0;
|
||||||
base::DelayedCallTimer _finishByTimeoutTimer;
|
base::DelayedCallTimer _finishByTimeoutTimer;
|
||||||
base::Timer _discardByTimeoutTimer;
|
base::Timer _discardByTimeoutTimer;
|
||||||
|
|
||||||
bool _mute = false;
|
rpl::variable<bool> _muted = false;
|
||||||
base::Observable<bool> _muteChanged;
|
rpl::variable<bool> _videoEnabled = false;
|
||||||
rpl::event_stream<QImage> _frames;
|
rpl::event_stream<QImage> _frames;
|
||||||
|
crl::time _remoteVideoInactiveFrom = 0;
|
||||||
|
|
||||||
DhConfig _dhConfig;
|
DhConfig _dhConfig;
|
||||||
bytes::vector _ga;
|
bytes::vector _ga;
|
||||||
|
@ -203,6 +226,7 @@ private:
|
||||||
uint64 _keyFingerprint = 0;
|
uint64 _keyFingerprint = 0;
|
||||||
|
|
||||||
std::unique_ptr<tgcalls::Instance> _instance;
|
std::unique_ptr<tgcalls::Instance> _instance;
|
||||||
|
std::shared_ptr<tgcalls::VideoCaptureInterface> _videoCapture;
|
||||||
|
|
||||||
std::unique_ptr<Media::Audio::Track> _waitingTrack;
|
std::unique_ptr<Media::Audio::Track> _waitingTrack;
|
||||||
|
|
||||||
|
|
|
@ -89,9 +89,10 @@ SignalBars::SignalBars(
|
||||||
resize(
|
resize(
|
||||||
_st.width + (_st.width + _st.skip) * (Call::kSignalBarCount - 1),
|
_st.width + (_st.width + _st.skip) * (Call::kSignalBarCount - 1),
|
||||||
_st.width * Call::kSignalBarCount);
|
_st.width * Call::kSignalBarCount);
|
||||||
subscribe(call->signalBarCountChanged(), [=](int count) {
|
call->signalBarCountValue(
|
||||||
|
) | rpl::start_with_next([=](int count) {
|
||||||
changed(count);
|
changed(count);
|
||||||
});
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SignalBars::isDisplayed() const {
|
bool SignalBars::isDisplayed() const {
|
||||||
|
@ -307,6 +308,7 @@ Panel::Panel(not_null<Call*> call)
|
||||||
, _answerHangupRedial(this, st::callAnswer, &st::callHangup)
|
, _answerHangupRedial(this, st::callAnswer, &st::callHangup)
|
||||||
, _decline(this, object_ptr<Button>(this, st::callHangup))
|
, _decline(this, object_ptr<Button>(this, st::callHangup))
|
||||||
, _cancel(this, object_ptr<Button>(this, st::callCancel))
|
, _cancel(this, object_ptr<Button>(this, st::callCancel))
|
||||||
|
, _camera(this, st::callCameraToggle)
|
||||||
, _mute(this, st::callMuteToggle)
|
, _mute(this, st::callMuteToggle)
|
||||||
, _name(this, st::callName)
|
, _name(this, st::callName)
|
||||||
, _status(this, st::callStatus)
|
, _status(this, st::callStatus)
|
||||||
|
@ -353,14 +355,24 @@ void Panel::hideDeactivated() {
|
||||||
|
|
||||||
void Panel::initControls() {
|
void Panel::initControls() {
|
||||||
_hangupShown = (_call->type() == Type::Outgoing);
|
_hangupShown = (_call->type() == Type::Outgoing);
|
||||||
_mute->setClickedCallback([this] {
|
_mute->setClickedCallback([=] {
|
||||||
if (_call) {
|
if (_call) {
|
||||||
_call->setMute(!_call->isMute());
|
_call->setMuted(!_call->muted());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
subscribe(_call->muteChanged(), [this](bool mute) {
|
_call->mutedValue(
|
||||||
|
) | rpl::start_with_next([=](bool mute) {
|
||||||
_mute->setIconOverride(mute ? &st::callUnmuteIcon : nullptr);
|
_mute->setIconOverride(mute ? &st::callUnmuteIcon : nullptr);
|
||||||
|
}, lifetime());
|
||||||
|
_camera->setClickedCallback([=] {
|
||||||
|
if (_call) {
|
||||||
|
_call->setVideoEnabled(!_call->videoEnabled());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
_call->videoEnabledValue(
|
||||||
|
) | rpl::start_with_next([=](bool enabled) {
|
||||||
|
_camera->setIconOverride(enabled ? nullptr : &st::callNoCameraIcon);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
_updateDurationTimer.setCallback([this] {
|
_updateDurationTimer.setCallback([this] {
|
||||||
if (_call) {
|
if (_call) {
|
||||||
|
@ -691,6 +703,7 @@ void Panel::updateControlsGeometry() {
|
||||||
updateHangupGeometry();
|
updateHangupGeometry();
|
||||||
|
|
||||||
_mute->moveToRight(_padding.right() + st::callMuteRight, controlsTop);
|
_mute->moveToRight(_padding.right() + st::callMuteRight, controlsTop);
|
||||||
|
_camera->moveToLeft(_padding.right() + st::callMuteRight, controlsTop);
|
||||||
|
|
||||||
const auto skip = st::callSignalMargin + st::callSignalPadding;
|
const auto skip = st::callSignalMargin + st::callSignalPadding;
|
||||||
const auto delta = (_signalBars->width() - _signalBars->height());
|
const auto delta = (_signalBars->width() - _signalBars->height());
|
||||||
|
|
|
@ -34,7 +34,7 @@ struct CallSignalBars;
|
||||||
|
|
||||||
namespace Calls {
|
namespace Calls {
|
||||||
|
|
||||||
class SignalBars : public Ui::RpWidget, private base::Subscriber {
|
class SignalBars final : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
SignalBars(
|
SignalBars(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
|
@ -56,10 +56,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Panel
|
class Panel final : public Ui::RpWidget, private Ui::AbstractTooltipShower {
|
||||||
: public Ui::RpWidget
|
|
||||||
, private base::Subscriber
|
|
||||||
, private Ui::AbstractTooltipShower {
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Panel(not_null<Call*> call);
|
Panel(not_null<Call*> call);
|
||||||
|
@ -138,6 +135,7 @@ private:
|
||||||
object_ptr<Ui::FadeWrap<Button>> _cancel;
|
object_ptr<Ui::FadeWrap<Button>> _cancel;
|
||||||
bool _hangupShown = false;
|
bool _hangupShown = false;
|
||||||
Ui::Animations::Simple _hangupShownProgress;
|
Ui::Animations::Simple _hangupShownProgress;
|
||||||
|
object_ptr<Ui::IconButton> _camera;
|
||||||
object_ptr<Ui::IconButton> _mute;
|
object_ptr<Ui::IconButton> _mute;
|
||||||
object_ptr<Ui::FlatLabel> _name;
|
object_ptr<Ui::FlatLabel> _name;
|
||||||
object_ptr<Ui::FlatLabel> _status;
|
object_ptr<Ui::FlatLabel> _status;
|
||||||
|
|
|
@ -94,14 +94,14 @@ TopBar::TopBar(
|
||||||
void TopBar::initControls() {
|
void TopBar::initControls() {
|
||||||
_mute->setClickedCallback([=] {
|
_mute->setClickedCallback([=] {
|
||||||
if (const auto call = _call.get()) {
|
if (const auto call = _call.get()) {
|
||||||
call->setMute(!call->isMute());
|
call->setMuted(!call->muted());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setMuted(_call->isMute());
|
_call->mutedValue(
|
||||||
subscribe(_call->muteChanged(), [=](bool mute) {
|
) | rpl::start_with_next([=](bool muted) {
|
||||||
setMuted(mute);
|
setMuted(muted);
|
||||||
update();
|
update();
|
||||||
});
|
}, lifetime());
|
||||||
|
|
||||||
_call->user()->session().changes().peerUpdates(
|
_call->user()->session().changes().peerUpdates(
|
||||||
Data::PeerUpdate::Flag::Name
|
Data::PeerUpdate::Flag::Name
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace Calls {
|
||||||
class Call;
|
class Call;
|
||||||
class SignalBars;
|
class SignalBars;
|
||||||
|
|
||||||
class TopBar : public Ui::RpWidget, private base::Subscriber {
|
class TopBar : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
TopBar(QWidget *parent, const base::weak_ptr<Call> &call);
|
TopBar(QWidget *parent, const base::weak_ptr<Call> &call);
|
||||||
|
|
||||||
|
|
2
Telegram/ThirdParty/tgcalls
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit beb6eac853c6f2caf037ab1c374c25cf81af7a95
|
Subproject commit 8364baddd1e731aec3ae71d6594c10750afce312
|
|
@ -19,6 +19,8 @@ PRIVATE
|
||||||
Instance.h
|
Instance.h
|
||||||
InstanceImpl.cpp
|
InstanceImpl.cpp
|
||||||
InstanceImpl.h
|
InstanceImpl.h
|
||||||
|
LogSinkImpl.cpp
|
||||||
|
LogSinkImpl.h
|
||||||
Manager.cpp
|
Manager.cpp
|
||||||
Manager.h
|
Manager.h
|
||||||
MediaManager.cpp
|
MediaManager.cpp
|
||||||
|
|