Hide member rows with active small videos.

This commit is contained in:
John Preston 2021-05-30 17:51:04 +04:00
parent 8a693bc932
commit 38506d27a1
14 changed files with 359 additions and 85 deletions

View file

@ -776,6 +776,10 @@ void PeerListContent::appendRow(std::unique_ptr<PeerListRow> row) {
if (_rowsById.find(row->id()) == _rowsById.cend()) { if (_rowsById.find(row->id()) == _rowsById.cend()) {
row->setAbsoluteIndex(_rows.size()); row->setAbsoluteIndex(_rows.size());
addRowEntry(row.get()); addRowEntry(row.get());
if (!_hiddenRows.empty()) {
Assert(!row->hidden());
_filterResults.push_back(row.get());
}
_rows.push_back(std::move(row)); _rows.push_back(std::move(row));
} }
} }
@ -813,6 +817,17 @@ void PeerListContent::changeCheckState(
[=] { updateRow(row); }); [=] { updateRow(row); });
} }
void PeerListContent::setRowHidden(not_null<PeerListRow*> row, bool hidden) {
Expects(!row->isSearchResult());
row->setHidden(hidden);
if (hidden) {
_hiddenRows.emplace(row);
} else {
_hiddenRows.remove(row);
}
}
void PeerListContent::addRowEntry(not_null<PeerListRow*> row) { void PeerListContent::addRowEntry(not_null<PeerListRow*> row) {
if (_controller->respectSavedMessagesChat() && !row->special()) { if (_controller->respectSavedMessagesChat() && !row->special()) {
if (row->peer()->isSelf()) { if (row->peer()->isSelf()) {
@ -879,6 +894,10 @@ void PeerListContent::prependRow(std::unique_ptr<PeerListRow> row) {
if (_rowsById.find(row->id()) == _rowsById.cend()) { if (_rowsById.find(row->id()) == _rowsById.cend()) {
addRowEntry(row.get()); addRowEntry(row.get());
if (!_hiddenRows.empty()) {
Assert(!row->hidden());
_filterResults.insert(_filterResults.begin(), row.get());
}
_rows.insert(_rows.begin(), std::move(row)); _rows.insert(_rows.begin(), std::move(row));
refreshIndices(); refreshIndices();
} }
@ -894,6 +913,10 @@ void PeerListContent::prependRowFromSearchResult(not_null<PeerListRow*> row) {
Assert(_searchRows[index].get() == row); Assert(_searchRows[index].get() == row);
row->setIsSearchResult(false); row->setIsSearchResult(false);
if (!_hiddenRows.empty()) {
Assert(!row->hidden());
_filterResults.insert(_filterResults.begin(), row);
}
_rows.insert(_rows.begin(), std::move(_searchRows[index])); _rows.insert(_rows.begin(), std::move(_searchRows[index]));
refreshIndices(); refreshIndices();
removeRowAtIndex(_searchRows, index); removeRowAtIndex(_searchRows, index);
@ -947,6 +970,7 @@ void PeerListContent::removeRow(not_null<PeerListRow*> row) {
_filterResults.erase( _filterResults.erase(
ranges::remove(_filterResults, row), ranges::remove(_filterResults, row),
end(_filterResults)); end(_filterResults));
_hiddenRows.remove(row);
removeRowAtIndex(eraseFrom, index); removeRowAtIndex(eraseFrom, index);
restoreSelection(); restoreSelection();
@ -984,7 +1008,9 @@ void PeerListContent::convertRowToSearchResult(not_null<PeerListRow*> row) {
removeFromSearchIndex(row); removeFromSearchIndex(row);
row->setIsSearchResult(true); row->setIsSearchResult(true);
row->setHidden(false);
row->setAbsoluteIndex(_searchRows.size()); row->setAbsoluteIndex(_searchRows.size());
_hiddenRows.remove(row);
_searchRows.push_back(std::move(_rows[index])); _searchRows.push_back(std::move(_rows[index]));
removeRowAtIndex(_rows, index); removeRowAtIndex(_rows, index);
} }
@ -1069,6 +1095,14 @@ int PeerListContent::labelHeight() const {
} }
void PeerListContent::refreshRows() { void PeerListContent::refreshRows() {
if (!_hiddenRows.empty()) {
_filterResults.clear();
for (const auto &row : _rows) {
if (!row->hidden()) {
_filterResults.push_back(row.get());
}
}
}
resizeToWidth(width()); resizeToWidth(width());
if (_visibleBottom > 0) { if (_visibleBottom > 0) {
checkScrollForPreload(); checkScrollForPreload();
@ -1082,7 +1116,7 @@ void PeerListContent::refreshRows() {
void PeerListContent::setSearchMode(PeerListSearchMode mode) { void PeerListContent::setSearchMode(PeerListSearchMode mode) {
if (_searchMode != mode) { if (_searchMode != mode) {
if (!addingToSearchIndex()) { if (!addingToSearchIndex()) {
for_const (auto &row, _rows) { for (const auto &row : _rows) {
addToSearchIndex(row.get()); addToSearchIndex(row.get());
} }
} }
@ -1284,13 +1318,22 @@ void PeerListContent::mousePressReleased(Qt::MouseButton button) {
void PeerListContent::showRowMenu( void PeerListContent::showRowMenu(
not_null<PeerListRow*> row, not_null<PeerListRow*> row,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed) { Fn<void(not_null<Ui::PopupMenu*>)> destroyed) {
showRowMenu(findRowIndex(row), QCursor::pos(), std::move(destroyed)); const auto index = findRowIndex(row);
showRowMenu(
index,
row,
QCursor::pos(),
highlightRow,
std::move(destroyed));
} }
bool PeerListContent::showRowMenu( bool PeerListContent::showRowMenu(
RowIndex index, RowIndex index,
PeerListRow *row,
QPoint globalPos, QPoint globalPos,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed) { Fn<void(not_null<Ui::PopupMenu*>)> destroyed) {
if (_contextMenu) { if (_contextMenu) {
_contextMenu->setDestroyedCallback(nullptr); _contextMenu->setDestroyedCallback(nullptr);
@ -1301,7 +1344,9 @@ bool PeerListContent::showRowMenu(
mousePressReleased(_pressButton); mousePressReleased(_pressButton);
} }
const auto row = getRow(index); if (highlightRow) {
row = getRow(index);
}
if (!row) { if (!row) {
return false; return false;
} }
@ -1312,11 +1357,15 @@ bool PeerListContent::showRowMenu(
return false; return false;
} }
setContexted({ index, false }); if (highlightRow) {
setContexted({ index, false });
}
raw->setDestroyedCallback(crl::guard( raw->setDestroyedCallback(crl::guard(
this, this,
[=] { [=] {
setContexted(Selected()); if (highlightRow) {
setContexted(Selected());
}
handleMouseMove(QCursor::pos()); handleMouseMove(QCursor::pos());
if (destroyed) { if (destroyed) {
destroyed(raw); destroyed(raw);
@ -1330,7 +1379,7 @@ void PeerListContent::contextMenuEvent(QContextMenuEvent *e) {
if (e->reason() == QContextMenuEvent::Mouse) { if (e->reason() == QContextMenuEvent::Mouse) {
handleMouseMove(e->globalPos()); handleMouseMove(e->globalPos());
} }
if (showRowMenu(_selected.index, e->globalPos())) { if (showRowMenu(_selected.index, nullptr, e->globalPos(), true)) {
e->accept(); e->accept();
} }
} }
@ -1607,6 +1656,8 @@ void PeerListContent::searchQueryChanged(QString query) {
if (_normalizedSearchQuery != normalizedQuery) { if (_normalizedSearchQuery != normalizedQuery) {
setSearchQuery(query, normalizedQuery); setSearchQuery(query, normalizedQuery);
if (_controller->searchInLocal() && !searchWordsList.isEmpty()) { if (_controller->searchInLocal() && !searchWordsList.isEmpty()) {
Assert(_hiddenRows.empty());
auto minimalList = (const std::vector<not_null<PeerListRow*>>*)nullptr; auto minimalList = (const std::vector<not_null<PeerListRow*>>*)nullptr;
for (const auto &searchWord : searchWordsList) { for (const auto &searchWord : searchWordsList) {
auto searchWordStart = searchWord[0].toLower(); auto searchWordStart = searchWord[0].toLower();
@ -1656,15 +1707,17 @@ void PeerListContent::searchQueryChanged(QString query) {
} }
std::unique_ptr<PeerListState> PeerListContent::saveState() const { std::unique_ptr<PeerListState> PeerListContent::saveState() const {
Expects(_hiddenRows.empty());
auto result = std::make_unique<PeerListState>(); auto result = std::make_unique<PeerListState>();
result->controllerState result->controllerState
= std::make_unique<PeerListController::SavedStateBase>(); = std::make_unique<PeerListController::SavedStateBase>();
result->list.reserve(_rows.size()); result->list.reserve(_rows.size());
for (auto &row : _rows) { for (const auto &row : _rows) {
result->list.push_back(row->peer()); result->list.push_back(row->peer());
} }
result->filterResults.reserve(_filterResults.size()); result->filterResults.reserve(_filterResults.size());
for (auto &row : _filterResults) { for (const auto &row : _filterResults) {
result->filterResults.push_back(row->peer()); result->filterResults.push_back(row->peer());
} }
result->searchQuery = _searchQuery; result->searchQuery = _searchQuery;
@ -1844,8 +1897,7 @@ void PeerListContent::updateRow(RowIndex index) {
if (index.value < 0) { if (index.value < 0) {
return; return;
} }
auto row = getRow(index); if (const auto row = getRow(index); row && row->disabled()) {
if (row->disabled()) {
if (index == _selected.index) { if (index == _selected.index) {
setSelected(Selected()); setSelected(Selected());
} }
@ -1940,3 +1992,10 @@ PeerListContent::~PeerListContent() {
_contextMenu->setDestroyedCallback(nullptr); _contextMenu->setDestroyedCallback(nullptr);
} }
} }
void PeerListContentDelegate::peerListShowRowMenu(
not_null<PeerListRow*> row,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu *>)> destroyed) {
_content->showRowMenu(row, highlightRow, std::move(destroyed));
}

View file

@ -161,7 +161,7 @@ public:
template <typename UpdateCallback> template <typename UpdateCallback>
void setChecked( void setChecked(
bool checked, bool checked,
const style::RoundImageCheckbox &st, const style::RoundImageCheckbox &st,
anim::type animated, anim::type animated,
UpdateCallback callback) { UpdateCallback callback) {
if (checked && !_checkbox) { if (checked && !_checkbox) {
@ -169,6 +169,12 @@ public:
} }
setCheckedInternal(checked, animated); setCheckedInternal(checked, animated);
} }
void setHidden(bool hidden) {
_hidden = hidden;
}
[[nodiscard]] bool hidden() const {
return _hidden;
}
void finishCheckedAnimation(); void finishCheckedAnimation();
void invalidatePixmapsCache(); void invalidatePixmapsCache();
@ -237,6 +243,7 @@ private:
base::flat_set<QChar> _nameFirstLetters; base::flat_set<QChar> _nameFirstLetters;
int _absoluteIndex = -1; int _absoluteIndex = -1;
State _disabledState = State::Active; State _disabledState = State::Active;
bool _hidden = false;
bool _initialized : 1; bool _initialized : 1;
bool _isSearchResult : 1; bool _isSearchResult : 1;
bool _isSavedMessagesChat : 1; bool _isSavedMessagesChat : 1;
@ -274,6 +281,7 @@ public:
virtual void peerListConvertRowToSearchResult(not_null<PeerListRow*> row) = 0; virtual void peerListConvertRowToSearchResult(not_null<PeerListRow*> row) = 0;
virtual bool peerListIsRowChecked(not_null<PeerListRow*> row) = 0; virtual bool peerListIsRowChecked(not_null<PeerListRow*> row) = 0;
virtual void peerListSetRowChecked(not_null<PeerListRow*> row, bool checked) = 0; virtual void peerListSetRowChecked(not_null<PeerListRow*> row, bool checked) = 0;
virtual void peerListSetRowHidden(not_null<PeerListRow*> row, bool hidden) = 0;
virtual void peerListSetForeignRowChecked( virtual void peerListSetForeignRowChecked(
not_null<PeerListRow*> row, not_null<PeerListRow*> row,
bool checked, bool checked,
@ -304,6 +312,7 @@ public:
virtual void peerListShowRowMenu( virtual void peerListShowRowMenu(
not_null<PeerListRow*> row, not_null<PeerListRow*> row,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr) = 0; Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr) = 0;
virtual int peerListSelectedRowsCount() = 0; virtual int peerListSelectedRowsCount() = 0;
virtual std::unique_ptr<PeerListState> peerListSaveState() const = 0; virtual std::unique_ptr<PeerListState> peerListSaveState() const = 0;
@ -577,6 +586,9 @@ public:
not_null<PeerListRow*> row, not_null<PeerListRow*> row,
bool checked, bool checked,
anim::type animated); anim::type animated);
void setRowHidden(
not_null<PeerListRow*> row,
bool hidden);
template <typename ReorderCallback> template <typename ReorderCallback>
void reorderRows(ReorderCallback &&callback) { void reorderRows(ReorderCallback &&callback) {
@ -585,6 +597,9 @@ public:
callback(searchEntity.second.begin(), searchEntity.second.end()); callback(searchEntity.second.begin(), searchEntity.second.end());
} }
refreshIndices(); refreshIndices();
if (!_hiddenRows.empty()) {
callback(_filterResults.begin(), _filterResults.end());
}
update(); update();
} }
@ -593,6 +608,7 @@ public:
void showRowMenu( void showRowMenu(
not_null<PeerListRow*> row, not_null<PeerListRow*> row,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed); Fn<void(not_null<Ui::PopupMenu*>)> destroyed);
auto scrollToRequests() const { auto scrollToRequests() const {
@ -680,7 +696,9 @@ private:
bool showRowMenu( bool showRowMenu(
RowIndex index, RowIndex index,
PeerListRow *row,
QPoint globalPos, QPoint globalPos,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr); Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr);
crl::time paintRow(Painter &p, crl::time now, RowIndex index); crl::time paintRow(Painter &p, crl::time now, RowIndex index);
@ -691,7 +709,7 @@ private:
void removeFromSearchIndex(not_null<PeerListRow*> row); void removeFromSearchIndex(not_null<PeerListRow*> row);
void setSearchQuery(const QString &query, const QString &normalizedQuery); void setSearchQuery(const QString &query, const QString &normalizedQuery);
bool showingSearch() const { bool showingSearch() const {
return !_searchQuery.isEmpty(); return !_hiddenRows.empty() || !_searchQuery.isEmpty();
} }
int shownRowsCount() const { int shownRowsCount() const {
return showingSearch() ? _filterResults.size() : _rows.size(); return showingSearch() ? _filterResults.size() : _rows.size();
@ -737,6 +755,7 @@ private:
QString _normalizedSearchQuery; QString _normalizedSearchQuery;
QString _mentionHighlight; QString _mentionHighlight;
std::vector<not_null<PeerListRow*>> _filterResults; std::vector<not_null<PeerListRow*>> _filterResults;
base::flat_set<not_null<PeerListRow*>> _hiddenRows;
int _aboveHeight = 0; int _aboveHeight = 0;
int _belowHeight = 0; int _belowHeight = 0;
@ -801,6 +820,11 @@ public:
bool checked) override { bool checked) override {
_content->changeCheckState(row, checked, anim::type::normal); _content->changeCheckState(row, checked, anim::type::normal);
} }
void peerListSetRowHidden(
not_null<PeerListRow*> row,
bool hidden) override {
_content->setRowHidden(row, hidden);
}
void peerListSetForeignRowChecked( void peerListSetForeignRowChecked(
not_null<PeerListRow*> row, not_null<PeerListRow*> row,
bool checked, bool checked,
@ -871,10 +895,9 @@ public:
_content->restoreState(std::move(state)); _content->restoreState(std::move(state));
} }
void peerListShowRowMenu( void peerListShowRowMenu(
not_null<PeerListRow*> row, not_null<PeerListRow*> row,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr) override { bool highlightRow,
_content->showRowMenu(row, std::move(destroyed)); Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr) override;
}
protected: protected:
not_null<PeerListContent*> content() const { not_null<PeerListContent*> content() const {

View file

@ -533,7 +533,7 @@ void LinksController::rowClicked(not_null<PeerListRow*> row) {
} }
void LinksController::rowActionClicked(not_null<PeerListRow*> row) { void LinksController::rowActionClicked(not_null<PeerListRow*> row) {
delegate()->peerListShowRowMenu(row, nullptr); delegate()->peerListShowRowMenu(row, true);
} }
base::unique_qptr<Ui::PopupMenu> LinksController::rowContextMenu( base::unique_qptr<Ui::PopupMenu> LinksController::rowContextMenu(

View file

@ -446,7 +446,7 @@ void Panel::refreshIncomingGeometry() {
to, to,
Qt::KeepAspectRatioByExpanding); Qt::KeepAspectRatioByExpanding);
// If we cut out no more than 0.33 of the original, let's use expanding. // If we cut out no more than 0.25 of the original, let's use expanding.
const auto use = ((big.width() * 3 <= to.width() * 4) const auto use = ((big.width() * 3 <= to.width() * 4)
&& (big.height() * 3 <= to.height() * 4)) && (big.height() * 3 <= to.height() * 4))
? big ? big

View file

@ -529,11 +529,15 @@ void GroupCall::toggleScreenSharing(std::optional<QString> uniqueId) {
} }
bool GroupCall::hasVideoWithFrames() const { bool GroupCall::hasVideoWithFrames() const {
return _hasVideoWithFrames.current(); return !_shownVideoTracks.empty();
} }
rpl::producer<bool> GroupCall::hasVideoWithFramesValue() const { rpl::producer<bool> GroupCall::hasVideoWithFramesValue() const {
return _hasVideoWithFrames.value(); return _videoStreamShownUpdates.events_starting_with(
VideoActiveToggle()
) | rpl::map([=] {
return hasVideoWithFrames();
}) | rpl::distinct_until_changed();
} }
void GroupCall::setScheduledDate(TimeId date) { void GroupCall::setScheduledDate(TimeId date) {
@ -586,8 +590,16 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
? regularEndpoint(data.now->cameraEndpoint()) ? regularEndpoint(data.now->cameraEndpoint())
: EmptyString(); : EmptyString();
if (wasCameraEndpoint != nowCameraEndpoint) { if (wasCameraEndpoint != nowCameraEndpoint) {
markEndpointActive({ peer, nowCameraEndpoint }, true); markEndpointActive({
markEndpointActive({ peer, wasCameraEndpoint }, false); VideoEndpointType::Camera,
peer,
nowCameraEndpoint
}, true);
markEndpointActive({
VideoEndpointType::Camera,
peer,
wasCameraEndpoint
}, false);
} }
const auto &wasScreenEndpoint = data.was const auto &wasScreenEndpoint = data.was
? regularEndpoint(data.was->screenEndpoint()) ? regularEndpoint(data.was->screenEndpoint())
@ -596,8 +608,16 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
? regularEndpoint(data.now->screenEndpoint()) ? regularEndpoint(data.now->screenEndpoint())
: EmptyString(); : EmptyString();
if (wasScreenEndpoint != nowScreenEndpoint) { if (wasScreenEndpoint != nowScreenEndpoint) {
markEndpointActive({ peer, nowScreenEndpoint }, true); markEndpointActive({
markEndpointActive({ peer, wasScreenEndpoint }, false); VideoEndpointType::Screen,
peer,
nowScreenEndpoint
}, true);
markEndpointActive({
VideoEndpointType::Screen,
peer,
wasScreenEndpoint
}, false);
} }
}, _lifetime); }, _lifetime);
@ -792,14 +812,22 @@ void GroupCall::setScreenEndpoint(std::string endpoint) {
return; return;
} }
if (!_screenEndpoint.empty()) { if (!_screenEndpoint.empty()) {
markEndpointActive({ _joinAs, _screenEndpoint }, false); markEndpointActive({
VideoEndpointType::Screen,
_joinAs,
_screenEndpoint
}, false);
} }
_screenEndpoint = std::move(endpoint); _screenEndpoint = std::move(endpoint);
if (_screenEndpoint.empty()) { if (_screenEndpoint.empty()) {
return; return;
} }
if (isSharingScreen()) { if (isSharingScreen()) {
markEndpointActive({ _joinAs, _screenEndpoint }, true); markEndpointActive({
VideoEndpointType::Screen,
_joinAs,
_screenEndpoint
}, true);
} }
} }
@ -808,14 +836,22 @@ void GroupCall::setCameraEndpoint(std::string endpoint) {
return; return;
} }
if (!_cameraEndpoint.empty()) { if (!_cameraEndpoint.empty()) {
markEndpointActive({ _joinAs, _cameraEndpoint }, false); markEndpointActive({
VideoEndpointType::Camera,
_joinAs,
_cameraEndpoint
}, false);
} }
_cameraEndpoint = std::move(endpoint); _cameraEndpoint = std::move(endpoint);
if (_cameraEndpoint.empty()) { if (_cameraEndpoint.empty()) {
return; return;
} }
if (isSharingCamera()) { if (isSharingCamera()) {
markEndpointActive({ _joinAs, _cameraEndpoint }, true); markEndpointActive({
VideoEndpointType::Camera,
_joinAs,
_cameraEndpoint
}, true);
} }
} }
@ -848,7 +884,7 @@ void GroupCall::markEndpointActive(VideoEndpoint endpoint, bool active) {
if (!changed) { if (!changed) {
return; return;
} }
auto hasVideoWithFrames = _hasVideoWithFrames.current(); auto shown = false;
if (active) { if (active) {
const auto i = _activeVideoTracks.emplace( const auto i = _activeVideoTracks.emplace(
endpoint, endpoint,
@ -862,11 +898,11 @@ void GroupCall::markEndpointActive(VideoEndpoint endpoint, bool active) {
track->renderNextFrame( track->renderNextFrame(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
if (!track->frameSize().isEmpty()) { if (!track->frameSize().isEmpty()) {
_hasVideoWithFrames = true; markTrackShown(endpoint, true);
} }
}, i->second.lifetime); }, i->second.lifetime);
if (!track->frameSize().isEmpty()) { if (!track->frameSize().isEmpty()) {
hasVideoWithFrames = true; shown = true;
} }
addVideoOutput(i->first.id, { track->sink() }); addVideoOutput(i->first.id, { track->sink() });
} else { } else {
@ -874,17 +910,17 @@ void GroupCall::markEndpointActive(VideoEndpoint endpoint, bool active) {
_videoEndpointPinned = VideoEndpoint(); _videoEndpointPinned = VideoEndpoint();
} }
_activeVideoTracks.erase(i); _activeVideoTracks.erase(i);
hasVideoWithFrames = false;
for (const auto &[endpoint, track] : _activeVideoTracks) {
if (!track.track->frameSize().isEmpty()) {
hasVideoWithFrames = true;
break;
}
}
} }
updateRequestedVideoChannelsDelayed(); updateRequestedVideoChannelsDelayed();
_videoStreamActiveUpdates.fire(std::move(endpoint)); _videoStreamActiveUpdates.fire({ endpoint, active });
_hasVideoWithFrames = hasVideoWithFrames; markTrackShown(endpoint, shown);
}
void GroupCall::markTrackShown(const VideoEndpoint &endpoint, bool shown) {
if ((shown && _shownVideoTracks.emplace(endpoint).second)
|| (!shown && _shownVideoTracks.remove(endpoint))) {
_videoStreamShownUpdates.fire_copy({ endpoint, shown });
}
} }
void GroupCall::rejoin() { void GroupCall::rejoin() {
@ -1746,7 +1782,11 @@ void GroupCall::ensureOutgoingVideo() {
_cameraCapture->setState(tgcalls::VideoState::Inactive); _cameraCapture->setState(tgcalls::VideoState::Inactive);
} }
_isSharingCamera = active; _isSharingCamera = active;
markEndpointActive({ _joinAs, _cameraEndpoint }, active); markEndpointActive({
VideoEndpointType::Camera,
_joinAs,
_cameraEndpoint
}, active);
sendSelfUpdate(SendUpdateType::VideoMuted); sendSelfUpdate(SendUpdateType::VideoMuted);
applyMeInCallLocally(); applyMeInCallLocally();
}, _lifetime); }, _lifetime);
@ -1785,7 +1825,11 @@ void GroupCall::ensureOutgoingVideo() {
_screenCapture->setState(tgcalls::VideoState::Inactive); _screenCapture->setState(tgcalls::VideoState::Inactive);
} }
_isSharingScreen = active; _isSharingScreen = active;
markEndpointActive({ _joinAs, _screenEndpoint }, active); markEndpointActive({
VideoEndpointType::Screen,
_joinAs,
_screenEndpoint
}, active);
_screenJoinState.nextActionPending = true; _screenJoinState.nextActionPending = true;
checkNextJoinAction(); checkNextJoinAction();
}, _lifetime); }, _lifetime);
@ -2172,22 +2216,23 @@ void GroupCall::fillActiveVideoEndpoints() {
markEndpointActive(std::move(endpoint), true); markEndpointActive(std::move(endpoint), true);
} }
}; };
using Type = VideoEndpointType;
for (const auto &participant : participants) { for (const auto &participant : participants) {
const auto camera = participant.cameraEndpoint(); const auto camera = participant.cameraEndpoint();
if (camera != _cameraEndpoint if (camera != _cameraEndpoint
&& camera != _screenEndpoint && camera != _screenEndpoint
&& participant.peer != _joinAs) { && participant.peer != _joinAs) {
feedOne({ participant.peer, camera }); feedOne({ Type::Camera, participant.peer, camera });
} }
const auto screen = participant.screenEndpoint(); const auto screen = participant.screenEndpoint();
if (screen != _cameraEndpoint if (screen != _cameraEndpoint
&& screen != _screenEndpoint && screen != _screenEndpoint
&& participant.peer != _joinAs) { && participant.peer != _joinAs) {
feedOne({ participant.peer, screen }); feedOne({ Type::Screen, participant.peer, screen });
} }
} }
feedOne({ _joinAs, cameraSharingEndpoint() }); feedOne({ Type::Camera, _joinAs, cameraSharingEndpoint() });
feedOne({ _joinAs, screenSharingEndpoint() }); feedOne({ Type::Screen, _joinAs, screenSharingEndpoint() });
if (pinned && !pinnedFound) { if (pinned && !pinnedFound) {
_videoEndpointPinned = VideoEndpoint(); _videoEndpointPinned = VideoEndpoint();
} }

View file

@ -76,7 +76,13 @@ struct LevelUpdate {
bool me = false; bool me = false;
}; };
enum class VideoEndpointType {
Camera,
Screen,
};
struct VideoEndpoint { struct VideoEndpoint {
VideoEndpointType type = VideoEndpointType::Camera;
PeerData *peer = nullptr; PeerData *peer = nullptr;
std::string id; std::string id;
@ -130,6 +136,11 @@ struct VideoPinToggle {
bool pinned = false; bool pinned = false;
}; };
struct VideoActiveToggle {
VideoEndpoint endpoint;
bool active = false;
};
struct VideoQualityRequest { struct VideoQualityRequest {
VideoEndpoint endpoint; VideoEndpoint endpoint;
Group::VideoQuality quality = Group::VideoQuality(); Group::VideoQuality quality = Group::VideoQuality();
@ -283,9 +294,13 @@ public:
return _levelUpdates.events(); return _levelUpdates.events();
} }
[[nodiscard]] auto videoStreamActiveUpdates() const [[nodiscard]] auto videoStreamActiveUpdates() const
-> rpl::producer<VideoEndpoint> { -> rpl::producer<VideoActiveToggle> {
return _videoStreamActiveUpdates.events(); return _videoStreamActiveUpdates.events();
} }
[[nodiscard]] auto videoStreamShownUpdates() const
-> rpl::producer<VideoActiveToggle> {
return _videoStreamShownUpdates.events();
}
void pinVideoEndpoint(VideoEndpoint endpoint); void pinVideoEndpoint(VideoEndpoint endpoint);
void requestVideoQuality( void requestVideoQuality(
const VideoEndpoint &endpoint, const VideoEndpoint &endpoint,
@ -317,6 +332,10 @@ public:
-> const base::flat_map<VideoEndpoint, VideoTrack> & { -> const base::flat_map<VideoEndpoint, VideoTrack> & {
return _activeVideoTracks; return _activeVideoTracks;
} }
[[nodiscard]] auto shownVideoTracks() const
-> const base::flat_set<VideoEndpoint> & {
return _shownVideoTracks;
}
[[nodiscard]] rpl::producer<Group::RejoinEvent> rejoinEvents() const { [[nodiscard]] rpl::producer<Group::RejoinEvent> rejoinEvents() const {
return _rejoinEvents.events(); return _rejoinEvents.events();
} }
@ -491,6 +510,7 @@ private:
void addVideoOutput(const std::string &endpoint, SinkPointer sink); void addVideoOutput(const std::string &endpoint, SinkPointer sink);
void markEndpointActive(VideoEndpoint endpoint, bool active); void markEndpointActive(VideoEndpoint endpoint, bool active);
void markTrackShown(const VideoEndpoint &endpoint, bool shown);
[[nodiscard]] MTPInputGroupCall inputCall() const; [[nodiscard]] MTPInputGroupCall inputCall() const;
@ -560,10 +580,11 @@ private:
bool _requireARGB32 = true; bool _requireARGB32 = true;
rpl::event_stream<LevelUpdate> _levelUpdates; rpl::event_stream<LevelUpdate> _levelUpdates;
rpl::event_stream<VideoEndpoint> _videoStreamActiveUpdates; rpl::event_stream<VideoActiveToggle> _videoStreamActiveUpdates;
rpl::event_stream<VideoActiveToggle> _videoStreamShownUpdates;
base::flat_map<VideoEndpoint, VideoTrack> _activeVideoTracks; base::flat_map<VideoEndpoint, VideoTrack> _activeVideoTracks;
base::flat_set<VideoEndpoint> _shownVideoTracks;
rpl::variable<VideoEndpoint> _videoEndpointPinned; rpl::variable<VideoEndpoint> _videoEndpointPinned;
rpl::variable<bool> _hasVideoWithFrames = false;
base::flat_map<uint32, Data::LastSpokeTimes> _lastSpoke; base::flat_map<uint32, Data::LastSpokeTimes> _lastSpoke;
rpl::event_stream<Group::RejoinEvent> _rejoinEvents; rpl::event_stream<Group::RejoinEvent> _rejoinEvents;
rpl::event_stream<> _allowedToSpeakNotifications; rpl::event_stream<> _allowedToSpeakNotifications;

View file

@ -171,7 +171,7 @@ private:
// not_null<Row*> row, // not_null<Row*> row,
// const std::string &endpoint); // const std::string &endpoint);
bool toggleRowVideo(not_null<PeerListRow*> row); bool toggleRowVideo(not_null<PeerListRow*> row);
void showRowMenu(not_null<PeerListRow*> row); void showRowMenu(not_null<PeerListRow*> row, bool highlightRow);
void toggleVideoEndpointActive( void toggleVideoEndpointActive(
const VideoEndpoint &endpoint, const VideoEndpoint &endpoint,
@ -180,6 +180,11 @@ private:
void appendInvitedUsers(); void appendInvitedUsers();
void scheduleRaisedHandStatusRemove(); void scheduleRaisedHandStatusRemove();
void hideRowsWithVideoExcept(const VideoEndpoint &pinned);
void showAllHiddenRows();
void hideRowWithVideo(const VideoEndpoint &endpoint);
void showRowWithVideo(const VideoEndpoint &endpoint);
const not_null<GroupCall*> _call; const not_null<GroupCall*> _call;
not_null<PeerData*> _peer; not_null<PeerData*> _peer;
std::string _largeEndpoint; std::string _largeEndpoint;
@ -412,6 +417,27 @@ void Members::Controller::setupListChangeViewers() {
// } // }
//}, _lifetime); //}, _lifetime);
_call->videoEndpointPinnedValue(
) | rpl::start_with_next([=](const VideoEndpoint &pinned) {
if (pinned) {
hideRowsWithVideoExcept(pinned);
} else {
showAllHiddenRows();
}
}, _lifetime);
_call->videoStreamShownUpdates(
) | rpl::filter([=](const VideoActiveToggle &update) {
const auto &pinned = _call->videoEndpointPinned();
return pinned && (update.endpoint != pinned);
}) | rpl::start_with_next([=](const VideoActiveToggle &update) {
if (update.active) {
hideRowWithVideo(update.endpoint);
} else {
showRowWithVideo(update.endpoint);
}
}, _lifetime);
_call->rejoinEvents( _call->rejoinEvents(
) | rpl::start_with_next([=](const Group::RejoinEvent &event) { ) | rpl::start_with_next([=](const Group::RejoinEvent &event) {
const auto guard = gsl::finally([&] { const auto guard = gsl::finally([&] {
@ -428,6 +454,59 @@ void Members::Controller::setupListChangeViewers() {
}, _lifetime); }, _lifetime);
} }
void Members::Controller::hideRowsWithVideoExcept(
const VideoEndpoint &pinned) {
auto hidden = false;
for (const auto &endpoint : _call->shownVideoTracks()) {
if (endpoint != pinned) {
if (const auto row = findRow(endpoint.peer)) {
delegate()->peerListSetRowHidden(row, true);
hidden = true;
}
}
}
if (hidden) {
delegate()->peerListRefreshRows();
}
}
void Members::Controller::showAllHiddenRows() {
auto shown = false;
for (const auto &endpoint : _call->shownVideoTracks()) {
if (const auto row = findRow(endpoint.peer)) {
delegate()->peerListSetRowHidden(row, false);
shown = true;
}
}
if (shown) {
delegate()->peerListRefreshRows();
}
}
void Members::Controller::hideRowWithVideo(const VideoEndpoint &endpoint) {
if (const auto row = findRow(endpoint.peer)) {
delegate()->peerListSetRowHidden(row, true);
delegate()->peerListRefreshRows();
}
}
void Members::Controller::showRowWithVideo(const VideoEndpoint &endpoint) {
const auto peer = endpoint.peer;
const auto &pinned = _call->videoEndpointPinned();
if (pinned) {
for (const auto &endpoint : _call->shownVideoTracks()) {
if (endpoint != pinned && endpoint.peer == peer) {
// Still hidden with another video.
return;
}
}
}
if (const auto row = findRow(endpoint.peer)) {
delegate()->peerListSetRowHidden(row, false);
delegate()->peerListRefreshRows();
}
}
void Members::Controller::subscribeToChanges(not_null<Data::GroupCall*> real) { void Members::Controller::subscribeToChanges(not_null<Data::GroupCall*> real) {
_fullCount = real->fullCountValue(); _fullCount = real->fullCountValue();
@ -463,9 +542,8 @@ void Members::Controller::subscribeToChanges(not_null<Data::GroupCall*> real) {
toggleVideoEndpointActive(endpoint, true); toggleVideoEndpointActive(endpoint, true);
} }
_call->videoStreamActiveUpdates( _call->videoStreamActiveUpdates(
) | rpl::start_with_next([=](const VideoEndpoint &endpoint) { ) | rpl::start_with_next([=](const VideoActiveToggle &update) {
const auto active = _call->activeVideoTracks().contains(endpoint); toggleVideoEndpointActive(update.endpoint, update.active);
toggleVideoEndpointActive(endpoint, active);
}, _lifetime); }, _lifetime);
if (_prepared) { if (_prepared) {
@ -822,9 +900,8 @@ Main::Session &Members::Controller::session() const {
void Members::Controller::prepare() { void Members::Controller::prepare() {
delegate()->peerListSetSearchMode(PeerListSearchMode::Disabled); delegate()->peerListSetSearchMode(PeerListSearchMode::Disabled);
//delegate()->peerListSetTitle(std::move(title)); setDescription(nullptr);
setDescriptionText(tr::lng_contacts_loading(tr::now)); setSearchNoResults(nullptr);
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
if (const auto real = _call->lookupReal()) { if (const auto real = _call->lookupReal()) {
prepareRows(real); prepareRows(real);
@ -1155,7 +1232,7 @@ bool Members::Controller::rowIsNarrow() {
} }
void Members::Controller::rowShowContextMenu(not_null<PeerListRow*> row) { void Members::Controller::rowShowContextMenu(not_null<PeerListRow*> row) {
showRowMenu(row); showRowMenu(row, false);
} }
//void Members::Controller::rowPaintNarrowBackground( //void Members::Controller::rowPaintNarrowBackground(
@ -1253,12 +1330,14 @@ auto Members::Controller::kickParticipantRequests() const
void Members::Controller::rowClicked(not_null<PeerListRow*> row) { void Members::Controller::rowClicked(not_null<PeerListRow*> row) {
if (!toggleRowVideo(row)) { if (!toggleRowVideo(row)) {
showRowMenu(row); showRowMenu(row, true);
} }
} }
void Members::Controller::showRowMenu(not_null<PeerListRow*> row) { void Members::Controller::showRowMenu(
delegate()->peerListShowRowMenu(row, [=](not_null<Ui::PopupMenu*> menu) { not_null<PeerListRow*> row,
bool highlightRow) {
const auto cleanup = [=](not_null<Ui::PopupMenu*> menu) {
if (!_menu || _menu.get() != menu) { if (!_menu || _menu.get() != menu) {
return; return;
} }
@ -1269,7 +1348,8 @@ void Members::Controller::showRowMenu(not_null<PeerListRow*> row) {
} }
} }
_menu = std::move(saved); _menu = std::move(saved);
}); };
delegate()->peerListShowRowMenu(row, highlightRow, cleanup);
} }
bool Members::Controller::toggleRowVideo(not_null<PeerListRow*> row) { bool Members::Controller::toggleRowVideo(not_null<PeerListRow*> row) {
@ -1317,7 +1397,7 @@ bool Members::Controller::toggleRowVideo(not_null<PeerListRow*> row) {
void Members::Controller::rowActionClicked( void Members::Controller::rowActionClicked(
not_null<PeerListRow*> row) { not_null<PeerListRow*> row) {
showRowMenu(row); showRowMenu(row, true);
} }
base::unique_qptr<Ui::PopupMenu> Members::Controller::rowContextMenu( base::unique_qptr<Ui::PopupMenu> Members::Controller::rowContextMenu(
@ -1414,6 +1494,7 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
result->addAction( result->addAction(
tr::lng_group_call_context_pin_camera(tr::now), tr::lng_group_call_context_pin_camera(tr::now),
[=] { _call->pinVideoEndpoint(VideoEndpoint{ [=] { _call->pinVideoEndpoint(VideoEndpoint{
VideoEndpointType::Camera,
participantPeer, participantPeer,
camera }); }); camera }); });
} }
@ -1427,6 +1508,7 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
result->addAction( result->addAction(
tr::lng_group_call_context_pin_screen(tr::now), tr::lng_group_call_context_pin_screen(tr::now),
[=] { _call->pinVideoEndpoint(VideoEndpoint{ [=] { _call->pinVideoEndpoint(VideoEndpoint{
VideoEndpointType::Screen,
participantPeer, participantPeer,
screen }); }); screen }); });
} }
@ -1828,7 +1910,7 @@ QRect Members::getInnerGeometry() const {
0, 0,
-_scroll->scrollTop(), -_scroll->scrollTop(),
width(), width(),
_list->y() + _list->height() + add); _list->y() + _list->height() + _bottomSkip->height() + add);
} }
rpl::producer<int> Members::fullCountValue() const { rpl::producer<int> Members::fullCountValue() const {
@ -1837,18 +1919,38 @@ rpl::producer<int> Members::fullCountValue() const {
void Members::setupList() { void Members::setupList() {
_listController->setStyleOverrides(&st::groupCallMembersList); _listController->setStyleOverrides(&st::groupCallMembersList);
_topSkip = _layout->add( const auto addSkip = [&] {
object_ptr<Ui::FixedHeightWidget>( const auto result = _layout->add(
_layout.get(), object_ptr<Ui::FixedHeightWidget>(
st::groupCallMembersTopSkip)); _layout.get(),
_topSkip->paintRequest( st::groupCallMembersTopSkip));
) | rpl::start_with_next([=](QRect clip) { result->paintRequest(
QPainter(_topSkip).fillRect(clip, st::groupCallMembersBg); ) | rpl::start_with_next([=](QRect clip) {
}, _topSkip->lifetime()); QPainter(result).fillRect(clip, st::groupCallMembersBg);
}, result->lifetime());
return result;
};
_topSkip = addSkip();
_list = _layout->add( _list = _layout->add(
object_ptr<ListWidget>( object_ptr<ListWidget>(
_layout.get(), _layout.get(),
_listController.get())); _listController.get()));
_bottomSkip = addSkip();
using namespace rpl::mappers;
rpl::combine(
_list->heightValue() | rpl::map(_1 > 0),
_addMemberButton.value() | rpl::map(_1 != nullptr)
) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](bool hasList, bool hasAddMembers) {
_topSkip->resize(
_topSkip->width(),
hasList ? st::groupCallMembersTopSkip : 0);
_bottomSkip->resize(
_bottomSkip->width(),
(hasList && !hasAddMembers) ? st::groupCallMembersTopSkip : 0);
}, _list->lifetime());
const auto skip = _layout->add(object_ptr<Ui::RpWidget>(_layout.get())); const auto skip = _layout->add(object_ptr<Ui::RpWidget>(_layout.get()));
_mode.value( _mode.value(
) | rpl::start_with_next([=](PanelMode mode) { ) | rpl::start_with_next([=](PanelMode mode) {
@ -1997,6 +2099,7 @@ void Members::setupFakeRoundCorners() {
const auto bottom = top const auto bottom = top
+ _topSkip->height() + _topSkip->height()
+ list.height() + list.height()
+ _bottomSkip->height()
+ addMembers + addMembers
- bottomleft->height(); - bottomleft->height();
topleft->move(left, top); topleft->move(left, top);

View file

@ -102,6 +102,7 @@ private:
rpl::event_stream<> _enlargeVideoClicks; rpl::event_stream<> _enlargeVideoClicks;
rpl::variable<Ui::RpWidget*> _addMemberButton = nullptr; rpl::variable<Ui::RpWidget*> _addMemberButton = nullptr;
RpWidget *_topSkip = nullptr; RpWidget *_topSkip = nullptr;
RpWidget *_bottomSkip = nullptr;
ListWidget *_list = nullptr; ListWidget *_list = nullptr;
rpl::event_stream<> _addMemberRequests; rpl::event_stream<> _addMemberRequests;

View file

@ -399,7 +399,7 @@ bool MembersRow::paintVideo(
// .outer = QSize(sizew, sizeh) * cIntRetinaFactor(), // .outer = QSize(sizew, sizeh) * cIntRetinaFactor(),
//}; //};
//const auto frame = _videoTrackShown->frame(request); //const auto frame = _videoTrackShown->frame(request);
//auto copy = frame; // #TODO calls optimize. //auto copy = frame; // TODO calls optimize.
//copy.detach(); //copy.detach();
//if (mode == PanelMode::Default) { //if (mode == PanelMode::Default) {
// Images::prepareCircle(copy); // Images::prepareCircle(copy);

View file

@ -254,7 +254,7 @@ private:
//std::unique_ptr<Webrtc::VideoTrack> _videoTrack; //std::unique_ptr<Webrtc::VideoTrack> _videoTrack;
//Webrtc::VideoTrack *_videoTrackShown = nullptr; //Webrtc::VideoTrack *_videoTrackShown = nullptr;
//std::string _videoTrackEndpoint; //std::string _videoTrackEndpoint;
//rpl::lifetime _videoTrackLifetime; // #TODO calls move to unique_ptr. //rpl::lifetime _videoTrackLifetime; // TODO calls move to unique_ptr.
Ui::Animations::Simple _speakingAnimation; // For gray-red/green icon. Ui::Animations::Simple _speakingAnimation; // For gray-red/green icon.
Ui::Animations::Simple _mutedAnimation; // For gray/red icon. Ui::Animations::Simple _mutedAnimation; // For gray/red icon.
Ui::Animations::Simple _activeAnimation; // For icon cross animation. Ui::Animations::Simple _activeAnimation; // For icon cross animation.

View file

@ -977,8 +977,14 @@ void Panel::setupMembers() {
_startsWhen.destroy(); _startsWhen.destroy();
_members.create(widget(), _call, mode()); _members.create(widget(), _call, mode());
setupVideo(_viewport.get()); setupVideo(_viewport.get());
setupVideo(_members->viewport()); setupVideo(_members->viewport());
_viewport->mouseInsideValue(
) | rpl::start_with_next([=](bool inside) {
toggleWideControls(inside);
}, _viewport->lifetime());
_members->show(); _members->show();
refreshControlsBackground(); refreshControlsBackground();
@ -1135,9 +1141,10 @@ void Panel::setupVideo(not_null<Viewport*> viewport) {
setupTile(endpoint, track); setupTile(endpoint, track);
} }
_call->videoStreamActiveUpdates( _call->videoStreamActiveUpdates(
) | rpl::start_with_next([=](const VideoEndpoint &endpoint) { ) | rpl::start_with_next([=](const VideoActiveToggle &update) {
if (_call->activeVideoTracks().contains(endpoint)) { if (update.active) {
// Add async (=> the participant row is definitely in Members). // Add async (=> the participant row is definitely in Members).
const auto endpoint = update.endpoint;
crl::on_main(viewport->widget(), [=] { crl::on_main(viewport->widget(), [=] {
const auto &tracks = _call->activeVideoTracks(); const auto &tracks = _call->activeVideoTracks();
const auto i = tracks.find(endpoint); const auto i = tracks.find(endpoint);
@ -1147,7 +1154,7 @@ void Panel::setupVideo(not_null<Viewport*> viewport) {
}); });
} else { } else {
// Remove sync. // Remove sync.
viewport->remove(endpoint); viewport->remove(update.endpoint);
} }
}, viewport->lifetime()); }, viewport->lifetime());
@ -1168,11 +1175,6 @@ void Panel::setupVideo(not_null<Viewport*> viewport) {
) | rpl::start_with_next([=](const VideoQualityRequest &request) { ) | rpl::start_with_next([=](const VideoQualityRequest &request) {
_call->requestVideoQuality(request.endpoint, request.quality); _call->requestVideoQuality(request.endpoint, request.quality);
}, viewport->lifetime()); }, viewport->lifetime());
viewport->mouseInsideValue(
) | rpl::start_with_next([=](bool inside) {
toggleWideControls(inside);
}, viewport->lifetime());
} }
void Panel::toggleWideControls(bool shown) { void Panel::toggleWideControls(bool shown) {

View file

@ -26,8 +26,11 @@ constexpr auto kScaleForBlurTextureIndex = 3;
constexpr auto kFirstBlurPassTextureIndex = 4; constexpr auto kFirstBlurPassTextureIndex = 4;
constexpr auto kBlurTextureSizeFactor = 1.7; constexpr auto kBlurTextureSizeFactor = 1.7;
constexpr auto kBlurOpacity = 0.7; constexpr auto kBlurOpacity = 0.7;
constexpr auto kMinCameraVisiblePart = 0.75;
ShaderPart FragmentBlurTexture(bool vertical, char prefix = 'v') { [[nodiscard]] ShaderPart FragmentBlurTexture(
bool vertical,
char prefix = 'v') {
const auto offsets = (vertical ? QString("0, 1") : QString("1, 0")); const auto offsets = (vertical ? QString("0, 1") : QString("1, 0"));
const auto name = prefix + QString("_texcoord"); const auto name = prefix + QString("_texcoord");
return { return {
@ -94,6 +97,16 @@ vec4 background() {
}; };
} }
[[nodiscard]] bool UseExpandForCamera(QSize original, QSize viewport) {
const auto big = original.scaled(
viewport,
Qt::KeepAspectRatioByExpanding);
// If we cut out no more than 0.25 of the original, let's use expanding.
return (big.width() * kMinCameraVisiblePart <= viewport.width())
&& (big.height() * kMinCameraVisiblePart <= viewport.height());
}
[[nodiscard]] QSize NonEmpty(QSize size) { [[nodiscard]] QSize NonEmpty(QSize size) {
return QSize(std::max(size.width(), 1), std::max(size.height(), 1)); return QSize(std::max(size.width(), 1), std::max(size.height(), 1));
} }
@ -440,12 +453,14 @@ void Viewport::RendererGL::paintTile(
const auto unscaled = Media::View::FlipSizeByRotation( const auto unscaled = Media::View::FlipSizeByRotation(
data.yuv420->size, data.yuv420->size,
data.rotation); data.rotation);
const auto tileSize = geometry.size();
const auto swap = (((data.rotation / 90) % 2) == 1); const auto swap = (((data.rotation / 90) % 2) == 1);
const auto expand = !_owner->wide()/* && !tile->screencast()*/; const auto expand = !tile->screencast()
auto texCoords = CountTexCoords(unscaled, geometry.size(), expand, swap); && (!_owner->wide() || UseExpandForCamera(unscaled, tileSize));
auto texCoords = CountTexCoords(unscaled, tileSize, expand, swap);
auto blurTexCoords = expand auto blurTexCoords = expand
? texCoords ? texCoords
: CountTexCoords(unscaled, geometry.size(), true); : CountTexCoords(unscaled, tileSize, true);
const auto rect = transformRect(geometry); const auto rect = transformRect(geometry);
auto toBlurTexCoords = std::array<std::array<GLfloat, 2>, 4> { { auto toBlurTexCoords = std::array<std::array<GLfloat, 2>, 4> { {
{ { 0.f, 1.f } }, { { 0.f, 1.f } },

View file

@ -46,6 +46,10 @@ int Viewport::VideoTile::pinSlide() const {
_pinShownAnimation.value(_pinShown ? 1. : 0.)); _pinShownAnimation.value(_pinShown ? 1. : 0.));
} }
bool Viewport::VideoTile::screencast() const {
return (_endpoint.type == VideoEndpointType::Screen);
}
void Viewport::VideoTile::setGeometry(QRect geometry) { void Viewport::VideoTile::setGeometry(QRect geometry) {
_geometry = geometry; _geometry = geometry;
updatePinnedGeometry(); updatePinnedGeometry();

View file

@ -53,6 +53,7 @@ public:
return _trackSize.value(); return _trackSize.value();
} }
[[nodiscard]] bool screencast() const;
void setGeometry(QRect geometry); void setGeometry(QRect geometry);
void togglePinShown(bool shown); void togglePinShown(bool shown);
bool updateRequestedQuality(VideoQuality quality); bool updateRequestedQuality(VideoQuality quality);