Improve screencast source choosing design.

This commit is contained in:
John Preston 2021-04-29 20:28:12 +04:00
parent 022c0a1327
commit a48649987e
12 changed files with 304 additions and 74 deletions

View file

@ -2000,6 +2000,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_share_button" = "Share"; "lng_group_call_share_button" = "Share";
"lng_group_call_video" = "Video"; "lng_group_call_video" = "Video";
"lng_group_call_screen_share" = "Share"; "lng_group_call_screen_share" = "Share";
"lng_group_call_screen_share_start" = "Share Screen";
"lng_group_call_screen_share_stop" = "Stop Sharing";
"lng_group_call_screen_title" = "Screen {index}";
"lng_group_call_unmute_small" = "Unmute"; "lng_group_call_unmute_small" = "Unmute";
"lng_group_call_you_are_live_small" = "Mute"; "lng_group_call_you_are_live_small" = "Mute";
"lng_group_call_force_muted_small" = "Muted"; "lng_group_call_force_muted_small" = "Muted";

View file

@ -856,8 +856,7 @@ groupCallTopBarOpen: RoundButton(groupCallTopBarJoin) {
color: shadowFg; color: shadowFg;
} }
} }
groupCallBox: Box(defaultBox) { groupCallBoxButton: RoundButton(defaultBoxButton) {
button: RoundButton(defaultBoxButton) {
textFg: groupCallActiveFg; textFg: groupCallActiveFg;
textFgOver: groupCallActiveFg; textFgOver: groupCallActiveFg;
numbersTextFg: groupCallActiveFg; numbersTextFg: groupCallActiveFg;
@ -867,6 +866,8 @@ groupCallBox: Box(defaultBox) {
ripple: groupCallRipple; ripple: groupCallRipple;
} }
groupCallBox: Box(defaultBox) {
button: groupCallBoxButton;
margin: margins(0px, 56px, 0px, 10px); margin: margins(0px, 56px, 0px, 10px);
bg: groupCallMembersBg; bg: groupCallMembersBg;
title: FlatLabel(boxTitle) { title: FlatLabel(boxTitle) {
@ -1092,8 +1093,46 @@ groupCallStartsWhenTop: 160px;
groupCallCountdownFont: font(64px semibold); groupCallCountdownFont: font(64px semibold);
groupCallCountdownTop: 52px; groupCallCountdownTop: 52px;
desktopCaptureSourceSize: size(160px, 120px); desktopCaptureMargins: margins(12px, 8px, 12px, 6px);
desktopCaptureSourceSkip: 12px; desktopCaptureSourceSize: size(235px, 165px);
desktopCaptureSourceSkips: size(2px, 10px);
desktopCaptureSourceTitle: WindowTitle(groupCallTitle) {
height: 21px;
}
desktopCapturePadding: margins(7px, 7px, 7px, 33px);
desktopCaptureLabelBottom: 7px;
desktopCaptureLabel: FlatLabel(defaultFlatLabel) {
minWidth: 200px;
maxHeight: 20px;
textFg: groupCallMembersFg;
style: semiboldTextStyle;
}
desktopCaptureCancel: RoundButton(defaultBoxButton) {
textFg: groupCallActiveFg;
textFgOver: groupCallActiveFg;
numbersTextFg: groupCallActiveFg;
numbersTextFgOver: groupCallActiveFg;
textBg: groupCallBg;
textBgOver: groupCallMembersBg;
ripple: groupCallRipple;
}
desktopCaptureFinish: RoundButton(desktopCaptureCancel) {
textFg: groupCallMemberMutedIcon;
textFgOver: groupCallMemberMutedIcon;
}
desktopCaptureSubmit: RoundButton(desktopCaptureCancel) {
textFg: groupCallIconFg;
textFgOver: groupCallIconFg;
numbersTextFg: groupCallIconFg;
numbersTextFgOver: groupCallIconFg;
textBg: groupCallMuted1;
textBgOver: groupCallMuted1;
ripple: RippleAnimation(groupCallRipple) {
color: groupCallMuted2;
}
}
groupCallNarrowSkip: 9px; groupCallNarrowSkip: 9px;
groupCallNarrowRowSkip: 8px; groupCallNarrowRowSkip: 8px;

View file

@ -322,7 +322,12 @@ GroupCall::~GroupCall() {
} }
bool GroupCall::isScreenSharing() const { bool GroupCall::isScreenSharing() const {
return (_videoDeviceId != _videoInputId); return (_videoDeviceId != _videoInputId)
&& (_videoOutgoing->state() == Webrtc::VideoState::Active);
}
QString GroupCall::screenSharingDeviceId() const {
return isScreenSharing() ? _videoDeviceId : QString();
} }
void GroupCall::toggleVideo(bool active) { void GroupCall::toggleVideo(bool active) {

View file

@ -248,7 +248,8 @@ public:
void setCurrentAudioDevice(bool input, const QString &deviceId); void setCurrentAudioDevice(bool input, const QString &deviceId);
void setCurrentVideoDevice(const QString &deviceId); void setCurrentVideoDevice(const QString &deviceId);
bool isScreenSharing() const; [[nodiscard]] bool isScreenSharing() const;
[[nodiscard]] QString screenSharingDeviceId() const;
void toggleVideo(bool active); void toggleVideo(bool active);
void switchToScreenSharing(const QString &uniqueId); void switchToScreenSharing(const QString &uniqueId);

View file

@ -1460,9 +1460,9 @@ void MembersController::updateRow(
Assert(nowSsrc != 0); Assert(nowSsrc != 0);
_soundingRowBySsrc.emplace(nowSsrc, row); _soundingRowBySsrc.emplace(nowSsrc, row);
} }
if (isMe(row->peer())) { //if (isMe(row->peer())) {
row->setVideoTrack(_call->outgoingVideoTrack()); // row->setVideoTrack(_call->outgoingVideoTrack());
} //}
} }
const auto nowNoSounding = _soundingRowBySsrc.empty(); const auto nowNoSounding = _soundingRowBySsrc.empty();
if (wasNoSounding && !nowNoSounding) { if (wasNoSounding && !nowNoSounding) {

View file

@ -484,6 +484,10 @@ QWidget *Panel::chooseSourceParent() {
return _window.get(); return _window.get();
} }
QString Panel::chooseSourceActiveDeviceId() {
return _call->screenSharingDeviceId();
}
rpl::lifetime &Panel::chooseSourceInstanceLifetime() { rpl::lifetime &Panel::chooseSourceInstanceLifetime() {
return _window->lifetime(); return _window->lifetime();
} }
@ -492,6 +496,10 @@ void Panel::chooseSourceAccepted(const QString &deviceId) {
_call->switchToScreenSharing(deviceId); _call->switchToScreenSharing(deviceId);
} }
void Panel::chooseSourceStop() {
_call->toggleVideo(false);
}
void Panel::initWindow() { void Panel::initWindow() {
_window->setAttribute(Qt::WA_OpaquePaintEvent); _window->setAttribute(Qt::WA_OpaquePaintEvent);
_window->setAttribute(Qt::WA_NoSystemBackground); _window->setAttribute(Qt::WA_NoSystemBackground);

View file

@ -116,8 +116,10 @@ private:
void subscribeToPeerChanges(); void subscribeToPeerChanges();
QWidget *chooseSourceParent() override; QWidget *chooseSourceParent() override;
QString chooseSourceActiveDeviceId() override;
rpl::lifetime &chooseSourceInstanceLifetime() override; rpl::lifetime &chooseSourceInstanceLifetime() override;
void chooseSourceAccepted(const QString &deviceId) override; void chooseSourceAccepted(const QString &deviceId) override;
void chooseSourceStop() override;
const not_null<GroupCall*> _call; const not_null<GroupCall*> _call;
not_null<PeerData*> _peer; not_null<PeerData*> _peer;

View file

@ -11,8 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/effects/ripple_animation.h"
#include "ui/image/image.h"
#include "ui/platform/ui_platform_window_title.h"
#include "base/platform/base_platform_info.h" #include "base/platform/base_platform_info.h"
#include "webrtc/webrtc_video_track.h" #include "webrtc/webrtc_video_track.h"
#include "lang/lang_keys.h"
#include "styles/style_calls.h" #include "styles/style_calls.h"
#include <tgcalls/desktop_capturer/DesktopCaptureSourceManager.h> #include <tgcalls/desktop_capturer/DesktopCaptureSourceManager.h>
@ -33,6 +37,19 @@ struct Preview {
rpl::lifetime lifetime; rpl::lifetime lifetime;
}; };
class SourceButton final : public RippleButton {
public:
using RippleButton::RippleButton;
private:
QImage prepareRippleMask() const override;
};
QImage SourceButton::prepareRippleMask() const {
return RippleAnimation::roundRectMask(size(), st::roundRadiusLarge);
}
class Source final { class Source final {
public: public:
Source( Source(
@ -43,19 +60,23 @@ public:
void setGeometry(QRect geometry); void setGeometry(QRect geometry);
void clearHelper(); void clearHelper();
[[nodiscard]] bool ready() const; [[nodiscard]] rpl::producer<> activations() const;
[[nodiscard]] rpl::producer<> clicks() const; void setActive(bool active);
[[nodiscard]] rpl::lifetime &lifetime(); [[nodiscard]] rpl::lifetime &lifetime();
private: private:
void paint(); void paint();
void setupPreview(); void setupPreview();
AbstractButton _widget; SourceButton _widget;
FlatLabel _label; FlatLabel _label;
RoundRect _selectedRect;
RoundRect _activeRect;
tgcalls::DesktopCaptureSource _source; tgcalls::DesktopCaptureSource _source;
std::unique_ptr<Preview> _preview; std::unique_ptr<Preview> _preview;
rpl::event_stream<> _activations;
QImage _frame; QImage _frame;
bool _active = false;
}; };
@ -80,11 +101,16 @@ private:
std::unique_ptr<ChooseSourceProcess>> &Map(); std::unique_ptr<ChooseSourceProcess>> &Map();
const not_null<ChooseSourceDelegate*> _delegate; const not_null<ChooseSourceDelegate*> _delegate;
const std::unique_ptr<::Ui::Window> _window; const std::unique_ptr<Ui::Window> _window;
const std::unique_ptr<ScrollArea> _scroll; const std::unique_ptr<ScrollArea> _scroll;
const not_null<RpWidget*> _inner; const not_null<RpWidget*> _inner;
const not_null<RpWidget*> _bottom;
const not_null<RoundButton*> _submit;
const not_null<RoundButton*> _finish;
std::vector<std::unique_ptr<Source>> _sources; std::vector<std::unique_ptr<Source>> _sources;
Source *_selected = nullptr;
QString _selectedId;
}; };
@ -109,25 +135,45 @@ Source::Source(
not_null<QWidget*> parent, not_null<QWidget*> parent,
tgcalls::DesktopCaptureSource source, tgcalls::DesktopCaptureSource source,
const QString &title) const QString &title)
: _widget(parent) : _widget(parent, st::groupCallRipple)
, _label(&_widget, title) , _label(&_widget, title, st::desktopCaptureLabel)
, _selectedRect(ImageRoundRadius::Large, st::groupCallMembersBgOver)
, _activeRect(ImageRoundRadius::Large, st::groupCallMuted1)
, _source(source) { , _source(source) {
_widget.paintRequest( _widget.paintRequest(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
paint(); paint();
}, _widget.lifetime()); }, _widget.lifetime());
_label.setAttribute(Qt::WA_TransparentForMouseEvents);
_widget.sizeValue( _widget.sizeValue(
) | rpl::start_with_next([=](QSize size) { ) | rpl::start_with_next([=](QSize size) {
_label.resizeToNaturalWidth(size.width()); const auto padding = st::desktopCapturePadding;
_label.resizeToNaturalWidth(
size.width() - padding.left() - padding.right());
_label.move( _label.move(
(size.width() - _label.width()) / 2, (size.width() - _label.width()) / 2,
size.height() - _label.height()); size.height() - _label.height() - st::desktopCaptureLabelBottom);
}, _label.lifetime()); }, _label.lifetime());
_widget.setClickedCallback([=] {
setActive(true);
});
} }
rpl::producer<> Source::clicks() const { rpl::producer<> Source::activations() const {
return _widget.clicks() | rpl::to_empty; return _activations.events();
}
void Source::setActive(bool active) {
if (_active != active) {
_active = active;
_widget.update();
if (active) {
_activations.fire({});
}
}
} }
void Source::setGeometry(QRect geometry) { void Source::setGeometry(QRect geometry) {
@ -144,14 +190,21 @@ void Source::paint() {
if (_frame.isNull() && !_preview) { if (_frame.isNull() && !_preview) {
setupPreview(); setupPreview();
} }
if (_active) {
_activeRect.paint(p, _widget.rect());
} else if (_widget.isOver() || _widget.isDown()) {
_selectedRect.paint(p, _widget.rect());
}
_widget.paintRipple(
p,
{ 0, 0 },
_active ? &st::groupCallMuted2->c : nullptr);
const auto size = _preview ? _preview->track.frameSize() : QSize(); const auto size = _preview ? _preview->track.frameSize() : QSize();
const auto factor = style::DevicePixelRatio(); const auto factor = style::DevicePixelRatio();
const auto padding = st::desktopCapturePadding;
const auto rect = _widget.rect(); const auto rect = _widget.rect();
const auto inner = QRect( const auto inner = rect.marginsRemoved(padding);
rect.x(),
rect.y(),
rect.width(),
rect.height() - _label.height());
if (!size.isEmpty()) { if (!size.isEmpty()) {
const auto scaled = size.scaled(inner.size(), Qt::KeepAspectRatio); const auto scaled = size.scaled(inner.size(), Qt::KeepAspectRatio);
const auto request = Webrtc::FrameRequest{ const auto request = Webrtc::FrameRequest{
@ -190,9 +243,20 @@ rpl::lifetime &Source::lifetime() {
ChooseSourceProcess::ChooseSourceProcess( ChooseSourceProcess::ChooseSourceProcess(
not_null<ChooseSourceDelegate*> delegate) not_null<ChooseSourceDelegate*> delegate)
: _delegate(delegate) : _delegate(delegate)
, _window(std::make_unique<::Ui::Window>()) , _window(std::make_unique<Ui::Window>())
, _scroll(std::make_unique<ScrollArea>(_window->body())) , _scroll(std::make_unique<ScrollArea>(_window->body()))
, _inner(_scroll->setOwnedWidget(object_ptr<RpWidget>(_scroll.get()))) { , _inner(_scroll->setOwnedWidget(object_ptr<RpWidget>(_scroll.get())))
, _bottom(CreateChild<RpWidget>(_window->body().get()))
, _submit(
CreateChild<RoundButton>(
_bottom.get(),
tr::lng_group_call_screen_share_start(),
st::desktopCaptureSubmit))
, _finish(
CreateChild<RoundButton>(
_bottom.get(),
tr::lng_group_call_screen_share_stop(),
st::desktopCaptureFinish)) {
setupPanel(); setupPanel();
setupSources(); setupSources();
activate(); activate();
@ -233,25 +297,102 @@ void ChooseSourceProcess::activate() {
} }
void ChooseSourceProcess::setupPanel() { void ChooseSourceProcess::setupPanel() {
const auto width = kColumns * st::desktopCaptureSourceSize.width() _window->setAttribute(Qt::WA_OpaquePaintEvent);
+ (kColumns + 1) * st::desktopCaptureSourceSkip; _window->setAttribute(Qt::WA_NoSystemBackground);
const auto height = kRows * st::desktopCaptureSourceSize.height() _window->setWindowIcon(QIcon(
+ (kRows + 1) * st::desktopCaptureSourceSkip QPixmap::fromImage(Image::Empty()->original(), Qt::ColorOnly)));
+ (st::desktopCaptureSourceSize.height() / 2); _window->setTitleStyle(st::desktopCaptureSourceTitle);
const auto skips = st::desktopCaptureSourceSkips;
const auto margins = st::desktopCaptureMargins;
const auto padding = st::desktopCapturePadding;
const auto bottomSkip = margins.right() + padding.right();
const auto bottomHeight = 2 * bottomSkip
+ st::desktopCaptureCancel.height;
const auto width = margins.left()
+ kColumns * st::desktopCaptureSourceSize.width()
+ (kColumns - 1) * skips.width()
+ margins.right();
const auto height = margins.top()
+ kRows * st::desktopCaptureSourceSize.height()
+ (kRows - 1) * skips.height()
+ (st::desktopCaptureSourceSize.height() / 2)
+ bottomHeight;
_window->setFixedSize({ width, height }); _window->setFixedSize({ width, height });
_window->setWindowFlags(Qt::WindowStaysOnTopHint); _window->setWindowFlags(Qt::WindowStaysOnTopHint);
_window->body()->paintRequest(
) | rpl::start_with_next([=](QRect clip) {
QPainter(_window->body()).fillRect(clip, st::groupCallBg);
}, _window->lifetime());
_bottom->setGeometry(0, height - bottomHeight, width, bottomHeight);
_submit->setClickedCallback([=] {
if (_selectedId.isEmpty()) {
return;
}
const auto weak = MakeWeak(_window.get());
_delegate->chooseSourceAccepted(_selectedId);
if (const auto strong = weak.data()) {
strong->close();
}
});
_finish->setClickedCallback([=] {
const auto weak = MakeWeak(_window.get());
_delegate->chooseSourceStop();
if (const auto strong = weak.data()) {
strong->close();
}
});
const auto cancel = CreateChild<RoundButton>(
_bottom.get(),
tr::lng_cancel(),
st::desktopCaptureCancel);
cancel->setClickedCallback([=] {
_window->close();
});
rpl::combine(
_submit->widthValue(),
_submit->shownValue(),
_finish->widthValue(),
_finish->shownValue(),
cancel->widthValue()
) | rpl::start_with_next([=](
int submitWidth,
bool submitShown,
int finishWidth,
bool finishShown,
int cancelWidth) {
_finish->moveToRight(bottomSkip, bottomSkip);
_submit->moveToRight(bottomSkip, bottomSkip);
cancel->moveToRight(
bottomSkip * 2 + (submitShown ? submitWidth : finishWidth),
bottomSkip);
}, _bottom->lifetime());
const auto sharing = !_delegate->chooseSourceActiveDeviceId().isEmpty();
_finish->setVisible(sharing);
_submit->setVisible(!sharing);
_window->body()->sizeValue( _window->body()->sizeValue(
) | rpl::start_with_next([=](QSize size) { ) | rpl::start_with_next([=](QSize size) {
_scroll->setGeometry({ QPoint(), size }); _scroll->setGeometry(
0,
0,
size.width(),
size.height() - _bottom->height());
}, _scroll->lifetime()); }, _scroll->lifetime());
_scroll->widthValue( _scroll->widthValue(
) | rpl::start_with_next([=](int width) { ) | rpl::start_with_next([=](int width) {
const auto rows = int(std::ceil(_sources.size() / float(kColumns))); const auto rows = int(std::ceil(_sources.size() / float(kColumns)));
const auto height = rows * st::desktopCaptureSourceSize.height() const auto innerHeight = margins.top()
+ (rows + 1) * st::desktopCaptureSourceSkip; + rows * st::desktopCaptureSourceSize.height()
_inner->resize(width, height); + (rows - 1) * skips.height()
+ margins.bottom();
_inner->resize(width, std::max(height, innerHeight));
}, _inner->lifetime()); }, _inner->lifetime());
if (const auto parent = _delegate->chooseSourceParent()) { if (const auto parent = _delegate->chooseSourceParent()) {
@ -278,17 +419,42 @@ void ChooseSourceProcess::fillSources() {
auto screenIndex = 0; auto screenIndex = 0;
auto windowIndex = 0; auto windowIndex = 0;
const auto active = _delegate->chooseSourceActiveDeviceId();
const auto append = [&](const tgcalls::DesktopCaptureSource &source) { const auto append = [&](const tgcalls::DesktopCaptureSource &source) {
const auto title = !source.title().empty() const auto title = !source.isWindow()
? tr::lng_group_call_screen_title(
tr::now,
lt_index,
QString::number(++screenIndex))
: !source.title().empty()
? QString::fromStdString(source.title()) ? QString::fromStdString(source.title())
: source.isWindow() : "Window " + QString::number(++windowIndex);
? "Window " + QString::number(++windowIndex) const auto id = source.deviceIdKey();
: "Screen " + QString::number(++screenIndex);
_sources.push_back(std::make_unique<Source>(_inner, source, title)); _sources.push_back(std::make_unique<Source>(_inner, source, title));
_sources.back()->clicks(
) | rpl::start_with_next([=, id = source.deviceIdKey()]{ const auto raw = _sources.back().get();
_delegate->chooseSourceAccepted(QString::fromStdString(id)); if (!active.isEmpty() && active.toStdString() == id) {
}, _sources.back()->lifetime()); _selected = raw;
raw->setActive(true);
}
_sources.back()->activations(
) | rpl::filter([=] {
return (_selected != raw);
}) | rpl::start_with_next([=]{
if (_selected) {
_selected->setActive(false);
}
_selected = raw;
_selectedId = QString::fromStdString(id);
if (_selectedId == _delegate->chooseSourceActiveDeviceId()) {
_selectedId = QString();
_finish->setVisible(true);
_submit->setVisible(false);
} else {
_finish->setVisible(false);
_submit->setVisible(true);
}
}, raw->lifetime());
}; };
for (const auto &source : screensManager.sources()) { for (const auto &source : screensManager.sources()) {
append(source); append(source);
@ -300,31 +466,34 @@ void ChooseSourceProcess::fillSources() {
void ChooseSourceProcess::setupSourcesGeometry() { void ChooseSourceProcess::setupSourcesGeometry() {
if (_sources.empty()) { if (_sources.empty()) {
//LOG(());
destroy(); destroy();
return; return;
} }
_inner->widthValue( _inner->widthValue(
) | rpl::start_with_next([=](int width) { ) | rpl::start_with_next([=](int width) {
const auto rows = int(std::ceil(_sources.size() / float(kColumns))); const auto rows = int(std::ceil(_sources.size() / float(kColumns)));
const auto skip = st::desktopCaptureSourceSkip; const auto margins = st::desktopCaptureMargins;
const auto single = (width - (kColumns + 1) * skip) / kColumns; const auto skips = st::desktopCaptureSourceSkips;
const auto single = (width
- margins.left()
- margins.right()
- (kColumns - 1) * skips.width()) / kColumns;
const auto height = st::desktopCaptureSourceSize.height(); const auto height = st::desktopCaptureSourceSize.height();
auto top = skip; auto top = margins.top();
auto index = 0; auto index = 0;
for (auto row = 0; row != rows; ++row) { for (auto row = 0; row != rows; ++row) {
auto left = skip; auto left = margins.left();
for (auto column = 0; column != kColumns; ++column) { for (auto column = 0; column != kColumns; ++column) {
_sources[index]->setGeometry({ left, top, single, height }); _sources[index]->setGeometry({ left, top, single, height });
if (++index == _sources.size()) { if (++index == _sources.size()) {
break; break;
} }
left += single + skip; left += single + skips.width();
} }
if (index >= _sources.size()) { if (index >= _sources.size()) {
break; break;
} }
top += height + skip; top += height + skips.height();
} }
}, _inner->lifetime()); }, _inner->lifetime());
@ -333,9 +502,10 @@ void ChooseSourceProcess::setupSourcesGeometry() {
_scroll->heightValue() _scroll->heightValue()
) | rpl::start_with_next([=](int scrollTop, int scrollHeight) { ) | rpl::start_with_next([=](int scrollTop, int scrollHeight) {
const auto rows = int(std::ceil(_sources.size() / float(kColumns))); const auto rows = int(std::ceil(_sources.size() / float(kColumns)));
const auto skip = st::desktopCaptureSourceSkip; const auto margins = st::desktopCaptureMargins;
const auto skips = st::desktopCaptureSourceSkips;
const auto height = st::desktopCaptureSourceSize.height(); const auto height = st::desktopCaptureSourceSize.height();
auto top = skip; auto top = margins.top();
auto index = 0; auto index = 0;
for (auto row = 0; row != rows; ++row) { for (auto row = 0; row != rows; ++row) {
const auto hidden = (top + height <= scrollTop) const auto hidden = (top + height <= scrollTop)
@ -353,7 +523,7 @@ void ChooseSourceProcess::setupSourcesGeometry() {
if (index >= _sources.size()) { if (index >= _sources.size()) {
break; break;
} }
top += height + skip; top += height + skips.height();
} }
}, _inner->lifetime()); }, _inner->lifetime());
} }

View file

@ -19,8 +19,10 @@ namespace Calls::Group::Ui::DesktopCapture {
class ChooseSourceDelegate { class ChooseSourceDelegate {
public: public:
virtual QWidget *chooseSourceParent() = 0; virtual QWidget *chooseSourceParent() = 0;
virtual QString chooseSourceActiveDeviceId() = 0;
virtual rpl::lifetime &chooseSourceInstanceLifetime() = 0; virtual rpl::lifetime &chooseSourceInstanceLifetime() = 0;
virtual void chooseSourceAccepted(const QString &deviceId) = 0; virtual void chooseSourceAccepted(const QString &deviceId) = 0;
virtual void chooseSourceStop() = 0;
}; };
void ChooseSource(not_null<ChooseSourceDelegate*> delegate); void ChooseSource(not_null<ChooseSourceDelegate*> delegate);

View file

@ -93,16 +93,6 @@ QImage FromInlineBytes(const QByteArray &bytes) {
return App::readImage(ExpandInlineBytes(bytes)); return App::readImage(ExpandInlineBytes(bytes));
} }
QSize GetSizeForDocument(const QVector<MTPDocumentAttribute> &attributes) {
for (const auto &attribute : attributes) {
if (attribute.type() == mtpc_documentAttributeImageSize) {
auto &size = attribute.c_documentAttributeImageSize();
return QSize(size.vw().v, size.vh().v);
}
}
return QSize();
}
} // namespace Images } // namespace Images
Image::Image(const QString &path) : Image(ReadContent(path)) { Image::Image(const QString &path) : Image(ReadContent(path)) {

View file

@ -14,9 +14,6 @@ namespace Images {
[[nodiscard]] QByteArray ExpandInlineBytes(const QByteArray &bytes); [[nodiscard]] QByteArray ExpandInlineBytes(const QByteArray &bytes);
[[nodiscard]] QImage FromInlineBytes(const QByteArray &bytes); [[nodiscard]] QImage FromInlineBytes(const QByteArray &bytes);
[[nodiscard]] QSize GetSizeForDocument(
const QVector<MTPDocumentAttribute> &attributes);
} // namespace Images } // namespace Images
class Image final { class Image final {

View file

@ -13,6 +13,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QBuffer> #include <QtCore/QBuffer>
namespace Images { namespace Images {
namespace {
QSize GetSizeForDocument(const QVector<MTPDocumentAttribute> &attributes) {
for (const auto &attribute : attributes) {
if (attribute.type() == mtpc_documentAttributeImageSize) {
auto &size = attribute.c_documentAttributeImageSize();
return QSize(size.vw().v, size.vh().v);
}
}
return QSize();
}
} // namespace
ImageWithLocation FromPhotoSize( ImageWithLocation FromPhotoSize(
not_null<Main::Session*> session, not_null<Main::Session*> session,