diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 883e99a414..9cf42f9f5e 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -1006,9 +1006,8 @@ contactsWithStories: PeerList(peerListBox) { statusPosition: point(70px, 27px); checkbox: RoundImageCheckbox(defaultPeerListCheckbox) { - selectExtendTwice: 1px; imageRadius: 21px; - imageSmallRadius: 19px; + imageSmallRadius: 18px; check: RoundCheckbox(defaultPeerListCheck) { size: 0px; } diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index 684a06848b..6cc1b5d05a 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -983,10 +983,11 @@ void PeerListRow::setCheckedInternal(bool checked, anim::type animated) { } void PeerListRow::setCustomizedCheckSegments( - std::vector segments) { + std::vector segments, + bool liveBadge) { Expects(_checkbox != nullptr); - _checkbox->setCustomizedSegments(std::move(segments)); + _checkbox->setCustomizedSegments(std::move(segments), liveBadge); } void PeerListRow::finishCheckedAnimation() { diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h index 068906fa26..34fe0b13cf 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.h +++ b/Telegram/SourceFiles/boxes/peer_list_box.h @@ -223,7 +223,8 @@ public: setCheckedInternal(checked, animated); } void setCustomizedCheckSegments( - std::vector segments); + std::vector segments, + bool liveBadge); void setHidden(bool hidden) { _hidden = hidden; } diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index e8395b98cd..e6d54fc826 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -626,7 +626,8 @@ void PeerListStories::applyForRow( _delegate->peerListSetRowChecked(row, counts.count > 0); if (counts.count > 0) { row->setCustomizedCheckSegments( - PeerListStoriesSegments(counts, _unreadBrush)); + PeerListStoriesSegments(counts, _unreadBrush), + counts.videoStream); } } diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 545c77d9b4..b12071d3ab 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -1707,9 +1707,9 @@ groupCallMessageBadge: RoundButton(defaultActiveButton) { textBg: attentionButtonFg; textBgOver: attentionButtonFg; width: -6px; - height: 12px; - radius: 6px; - textTop: 1px; + height: 11px; + radius: 5px; + textTop: 0px; style: TextStyle(semiboldTextStyle) { font: font(8px semibold); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 9f72931b6d..530923e5e1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -12,7 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/credits_graphics.h" #include "ui/effects/outline_segments.h" #include "ui/effects/ripple_animation.h" +#include "ui/effects/round_checkbox.h" #include "ui/image/image_prepare.h" +#include "ui/text/custom_emoji_text_badge.h" #include "ui/text/format_values.h" #include "ui/text/text_options.h" #include "ui/text/text_utilities.h" @@ -30,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "lang/lang_keys.h" #include "base/unixtime.h" +#include "styles/style_calls.h" #include "styles/style_dialogs.h" namespace Dialogs { @@ -481,6 +484,10 @@ void Row::PaintCornerBadgeFrame( } else { Ui::PaintOutlineSegments(q, outline, segments); } + + if (data->storiesHasVideoStream) { + Ui::PaintLiveBadge(q, 0, 0, photoSize); + } } if (subscribed) { diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index e2a0158e23..b638e5abbc 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/event_filter.h" #include "base/qt_signal_producer.h" #include "lang/lang_keys.h" +#include "ui/effects/round_checkbox.h" #include "ui/effects/outline_segments.h" #include "ui/text/text_utilities.h" #include "ui/widgets/menu/menu_add_action_callback_factory.h" @@ -642,6 +643,19 @@ void List::paint( itemFull->element.thumbnail->image(size)); } } + + if (const auto full = single.itemFull) { + if (full->element.hasVideoStream && expandRatio > 0.) { + p.setOpacity(expandRatio); + const auto skip = std::ceil(line + lineRead); + Ui::PaintLiveBadge( + p, + std::ceil(userpic.x() - skip), + std::ceil(userpic.y() - skip), + std::ceil(userpic.width() + 2 * skip), + st::windowBg->c); + } + } p.setOpacity(1.); }); } diff --git a/Telegram/SourceFiles/ui/effects/round_checkbox.cpp b/Telegram/SourceFiles/ui/effects/round_checkbox.cpp index f74ecd0d59..0ce16d4dbb 100644 --- a/Telegram/SourceFiles/ui/effects/round_checkbox.cpp +++ b/Telegram/SourceFiles/ui/effects/round_checkbox.cpp @@ -7,10 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "ui/effects/round_checkbox.h" +#include "lang/lang_keys.h" #include "ui/rp_widget.h" #include "ui/ui_utility.h" #include "ui/painter.h" #include "ui/effects/outline_segments.h" +#include "styles/style_calls.h" +#include "styles/style_dialogs.h" #include "styles/style_widgets.h" #include @@ -376,13 +379,50 @@ RoundImageCheckbox::RoundImageCheckbox(RoundImageCheckbox&&) = default; RoundImageCheckbox::~RoundImageCheckbox() = default; -void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) const { +void RoundImageCheckbox::paint( + Painter &p, + int x, + int y, + int outerWidth) const { + if (_liveBadge) { + const auto ratio = style::DevicePixelRatio(); + const auto added = _st.selectWidth; + const auto cacheSize = (added + _st.imageRadius) * 2; + const auto fullCacheSize = cacheSize * ratio; + if (_liveBadgeCache.width() != fullCacheSize) { + _liveBadgeCache = QImage( + QSize(fullCacheSize, fullCacheSize), + QImage::Format_ARGB32_Premultiplied); + _liveBadgeCache.setDevicePixelRatio(ratio); + } + _liveBadgeCache.fill(Qt::transparent); + auto q = Painter(&_liveBadgeCache); + paintFrame(q, added, added, cacheSize); + q.end(); + + p.drawImage(x - added, y - added, _liveBadgeCache); + } else { + paintFrame(p, x, y, outerWidth); + } +} + +void RoundImageCheckbox::paintFrame( + Painter &p, + int x, + int y, + int outerWidth) const { auto selectionLevel = _selection.value(checked() ? 1. : 0.); if (_selection.animating()) { - auto userpicRadius = qRound(kWideScale * (_st.imageRadius + (_st.imageSmallRadius - _st.imageRadius) * selectionLevel)); + auto userpicRadius = qRound(kWideScale + * (_st.imageRadius + (_st.imageSmallRadius - _st.imageRadius) + * selectionLevel)); auto userpicShift = kWideScale * _st.imageRadius - userpicRadius; - auto userpicLeft = x - (kWideScale - 1) * _st.imageRadius + userpicShift; - auto userpicTop = y - (kWideScale - 1) * _st.imageRadius + userpicShift; + auto userpicLeft = x + - ((kWideScale - 1) * _st.imageRadius) + + userpicShift; + auto userpicTop = y + - ((kWideScale - 1) * _st.imageRadius) + + userpicShift; auto to = QRect(userpicLeft, userpicTop, userpicRadius * 2, userpicRadius * 2); auto from = QRect(QPoint(0, 0), _wideCache.size()); @@ -426,6 +466,11 @@ void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) const { } else { PaintOutlineSegments(p, outline, _segments); } + + if (_liveBadge) { + PaintLiveBadge(p, x, y, _st.imageRadius * 2); + } + p.setOpacity(1.); } if (_st.check.size > 0) { @@ -493,15 +538,59 @@ void RoundImageCheckbox::setColorOverride(std::optional fg) { if (fg) { setCustomizedSegments({ { .brush = *fg, .width = float64(_st.selectWidth) } - }); + }, false); } else { - setCustomizedSegments({}); + setCustomizedSegments({}, false); } } void RoundImageCheckbox::setCustomizedSegments( - std::vector segments) { + std::vector segments, + bool liveBadge) { _segments = std::move(segments); + _liveBadge = liveBadge; +} + +void PaintLiveBadge( + QPainter &p, + int x, + int y, + int photoSize, + std::optional outline) { + const auto &st = st::groupCallMessageBadge; + const auto text = tr::lng_video_stream_live(tr::now); + auto string = Ui::Text::String(st.style, text); + const auto size = QSize(string.maxWidth(), string.minHeight()); + + const auto full = QSize( + (st.width < 0) ? (size.width() - st.width) : st.width, + st.height); + const auto left = x + (photoSize - full.width()) / 2; + const auto top = y + photoSize - full.height(); + + const auto stroke = st::dialogsStories.lineTwice / 2.; + auto pen = QPen(outline.value_or(QColor(Qt::transparent))); + pen.setWidthF(stroke); + + const auto half = stroke / 2.; + if (!outline) { + p.setCompositionMode(QPainter::CompositionMode_Source); + } + auto hq = PainterHighQualityEnabler(p); + p.setPen(pen); + p.setBrush(st.textBg); + + const auto r = st.radius + half; + const auto rect = QRectF(left, top, full.width(), full.height()); + const auto sub = QMarginsF(half, half, half, half); + p.drawRoundedRect(rect.marginsAdded(sub), r, r); + + if (!outline) { + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + } + const auto textLeft = (full.width() - size.width()) / 2; + p.setPen(st.textFg); + string.draw(p, { .position = { left + textLeft, top + st.textTop } }); } } // namespace Ui diff --git a/Telegram/SourceFiles/ui/effects/round_checkbox.h b/Telegram/SourceFiles/ui/effects/round_checkbox.h index fa22110596..f265918015 100644 --- a/Telegram/SourceFiles/ui/effects/round_checkbox.h +++ b/Telegram/SourceFiles/ui/effects/round_checkbox.h @@ -54,7 +54,12 @@ private: class RoundImageCheckbox { public: - using PaintRoundImage = Fn; + using PaintRoundImage = Fn; RoundImageCheckbox( const style::RoundImageCheckbox &st, Fn updateCallback, @@ -67,7 +72,9 @@ public: float64 checkedAnimationRatio() const; void setColorOverride(std::optional fg); - void setCustomizedSegments(std::vector segments); + void setCustomizedSegments( + std::vector segments, + bool liveBadge); bool checked() const { return _check.checked(); @@ -82,6 +89,7 @@ public: private: void prepareWideCache(); + void paintFrame(Painter &p, int x, int y, int outerWidth) const; const style::RoundImageCheckbox &_st; Fn _updateCallback; @@ -96,6 +104,16 @@ private: //std::optional _fgOverride; std::vector _segments; + mutable QImage _liveBadgeCache; + bool _liveBadge = false; + }; +void PaintLiveBadge( + QPainter &p, + int x, + int y, + int photoSize, + std::optional outline = std::nullopt); + } // namespace Ui