Support about text above reactions strip.

This commit is contained in:
John Preston 2024-01-27 17:11:49 +04:00
parent f324c53440
commit 46579ac84d
6 changed files with 148 additions and 28 deletions

View file

@ -122,6 +122,8 @@ EmojiPan {
removeSet: IconButton;
boxLabel: FlatLabel;
icons: ComposeIcons;
about: FlatLabel;
aboutPadding: margins;
autocompleteBottomSkip: pixels;
}
@ -617,6 +619,14 @@ defaultComposeIcons: ComposeIcons {
{ "chat/reactions_expand_panel", windowSubTextFg },
};
}
defaultEmojiPanAbout: FlatLabel(defaultFlatLabel) {
minWidth: 10px;
align: align(top);
textFg: windowSubTextFg;
style: TextStyle(defaultTextStyle) {
font: font(11px);
}
}
defaultEmojiPan: EmojiPan {
margin: margins(7px, 0px, 7px, 0px);
padding: margins(7px, 0px, 4px, 7px);
@ -658,6 +668,8 @@ defaultEmojiPan: EmojiPan {
removeSet: stickerPanRemoveSet;
boxLabel: boxLabel;
icons: defaultComposeIcons;
about: defaultEmojiPanAbout;
aboutPadding: margins(12px, 2px, 12px, 2px);
autocompleteBottomSkip: 0px;
}
statusEmojiPan: EmojiPan(defaultEmojiPan) {

View file

@ -635,7 +635,7 @@ void StickersListFooter::paint(
if (context.expanding) {
const auto both = clip.intersected(
context.clip.marginsRemoved(
{ context.radius, 0, context.radius, 0 }));
{ 0/*context.radius*/, 0, context.radius, 0 }));
if (both.isEmpty()) {
return;
}

View file

@ -2636,7 +2636,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
desiredPosition,
reactItem,
[=](ChosenReaction reaction) { reactionChosen(reaction); },
TextWithEntities(),
(reactItem->reactionsAreTags()
? TextWithEntities{ u"Organize your Saved Messages with tags. Learn More..."_q }
: TextWithEntities()),
_controller->cachedReactionIconFactory().createMethod())
: AttachSelectorResult::Skipped;
if (attached == AttachSelectorResult::Failed) {

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/reactions/history_view_reactions_selector.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/popup_menu.h"
#include "ui/widgets/shadow.h"
@ -195,6 +196,7 @@ Selector::Selector(
const style::EmojiPan &st,
std::shared_ptr<ChatHelpers::Show> show,
const Data::PossibleItemReactionsRef &reactions,
TextWithEntities about,
IconFactory iconFactory,
Fn<void(bool fast)> close,
bool child)
@ -207,6 +209,7 @@ Selector::Selector(
? ChatHelpers::EmojiListMode::FullReactions
: ChatHelpers::EmojiListMode::RecentReactions),
{},
std::move(about),
iconFactory,
close,
child) {
@ -227,6 +230,7 @@ Selector::Selector(
{ .customAllowed = true },
mode,
std::move(recent),
{},
nullptr,
close,
child) {
@ -239,6 +243,7 @@ Selector::Selector(
const Data::PossibleItemReactionsRef &reactions,
ChatHelpers::EmojiListMode mode,
std::vector<DocumentId> recent,
TextWithEntities about,
IconFactory iconFactory,
Fn<void(bool fast)> close,
bool child)
@ -261,6 +266,12 @@ Selector::Selector(
crl::guard(this, [=] { update(_inner); }),
std::move(iconFactory))
: nullptr)
, _about(about.empty()
? nullptr
: std::make_unique<Ui::FlatLabel>(
this,
rpl::single(about),
_st.about))
, _size(st::reactStripSize)
, _skipx(countSkipLeft())
, _skipy((st::reactStripHeight - st::reactStripSize) / 2) {
@ -269,6 +280,8 @@ Selector::Selector(
_useTransparency = child || Ui::Platform::TranslucentWindowsSupported();
}
Selector::~Selector() = default;
bool Selector::useTransparency() const {
return _useTransparency;
}
@ -332,6 +345,27 @@ int Selector::extendTopForCategories() const {
return _reactions.customAllowed ? _st.footer : 0;
}
int Selector::extendTopForCategoriesAndAbout(int width) const {
if (_about) {
const auto padding = _st.aboutPadding;
const auto available = width - padding.left() - padding.right();
const auto countAboutHeight = [&](int width) {
_about->resizeToWidth(width);
return _about->height();
};
const auto desired = Ui::FindNiceTooltipWidth(
std::min(available, _st.about.minWidth * 2),
available,
countAboutHeight);
_about->resizeToWidth(desired);
_aboutExtend = padding.top() + _about->height() + padding.bottom();
} else {
_aboutExtend = 0;
}
return std::max(extendTopForCategories(), _aboutExtend);
}
int Selector::minimalHeight() const {
return _skipy
+ std::min(_recentRows * _size, st::emojiPanMinHeight)
@ -351,19 +385,33 @@ void Selector::initGeometry(int innerTop) {
const auto width = _useTransparency
? (innerWidth + margins.left() + margins.right())
: parent.width();
const auto height = innerHeight + margins.top() + margins.bottom();
const auto left = style::RightToLeft() ? 0 : (parent.width() - width);
const auto forAbout = width - margins.left() - margins.right();
_collapsedTopSkip = _useTransparency
? (extendTopForCategories() + _specialExpandTopSkip)
? (extendTopForCategoriesAndAbout(forAbout) + _specialExpandTopSkip)
: 0;
_topAddOnExpand = extendTopForCategories()
- _aboutExtend
+ _specialExpandTopSkip;
const auto height = margins.top()
+ _aboutExtend
+ innerHeight
+ margins.bottom();
const auto left = style::RightToLeft() ? 0 : (parent.width() - width);
const auto top = innerTop - margins.top() - _collapsedTopSkip;
const auto add = _st.icons.stripBubble.height() - margins.bottom();
_outer = QRect(0, _collapsedTopSkip, width, height);
_outer = QRect(0, _collapsedTopSkip - _aboutExtend, width, height);
_outerWithBubble = _outer.marginsAdded({ 0, 0, 0, add });
setGeometry(_outerWithBubble.marginsAdded(
{ 0, _collapsedTopSkip, 0, 0 }
{ 0, _outer.y(), 0, 0}
).translated(left, top));
_inner = _outer.marginsRemoved(margins);
_inner = _outer.marginsRemoved(
margins + QMargins{ 0, _aboutExtend, 0, 0 });
if (_about) {
_about->move(
_inner.x() + (_inner.width() - _about->width()) / 2,
_outer.y() + margins.top() + _st.aboutPadding.top());
_aboutCache = Ui::GrabWidgetToImage(_about.get());
}
if (!_strip) {
expand();
@ -390,6 +438,14 @@ void Selector::updateShowState(
&& !appearing
&& !_paintBuffer.isNull()) {
paintBackgroundToBuffer();
if (_about && _about->isHidden()) {
_about->show();
}
} else if (_useTransparency
&& !_appearing
&& appearing
&& _about) {
_about->hide();
}
_appearing = appearing;
_toggling = toggling;
@ -416,7 +472,6 @@ void Selector::paintAppearing(QPainter &p) {
Expects(_strip != nullptr);
p.setOpacity(_appearOpacity);
const auto factor = style::DevicePixelRatio();
if (_paintBuffer.size() != _outerWithBubble.size() * factor) {
_paintBuffer = _cachedRound.PrepareImage(_outerWithBubble.size());
@ -428,7 +483,7 @@ void Selector::paintAppearing(QPainter &p) {
const auto fullWidth = _inner.x() + appearedWidth + margins.right();
const auto size = QSize(fullWidth, _outer.height());
q.translate(_inner.topLeft() - QPoint(0, _collapsedTopSkip));
q.translate(_inner.topLeft() - QPoint(0, _outer.y()));
_strip->paint(
q,
{ _skipx, _skipy },
@ -439,7 +494,7 @@ void Selector::paintAppearing(QPainter &p) {
_cachedRound.setBackgroundColor(_st.bg->c);
_cachedRound.setShadowColor(st::shadowFg->c);
q.translate(QPoint(0, _collapsedTopSkip) - _inner.topLeft());
q.translate(QPoint(0, _outer.y()) - _inner.topLeft());
const auto radius = st::reactStripHeight / 2;
_cachedRound.overlayExpandedBorder(
q,
@ -460,6 +515,15 @@ void Selector::paintAppearing(QPainter &p) {
_outer.topLeft(),
_paintBuffer,
QRect(QPoint(), QSize(fullWidth, height()) * factor));
const auto aboutRight = _inner.x() + appearedWidth;
if (_about && _about->isHidden() && aboutRight > _about->x()) {
const auto aboutWidth = aboutRight - _about->x();
p.drawImage(
_about->geometry().topLeft(),
_aboutCache,
QRect(QPoint(), QSize(aboutWidth, _about->height()) * factor));
}
}
void Selector::paintBackgroundToBuffer() {
@ -478,8 +542,11 @@ void Selector::paintBackgroundToBuffer() {
auto p = QPainter(&_paintBuffer);
const auto radius = _inner.height() / 2.;
const auto frame = _cachedRound.validateFrame(0, 1., radius);
const auto outer = _outer.translated(0, -_collapsedTopSkip);
_cachedRound.FillWithImage(p, outer, frame);
const auto outer = _outer.translated(0, -_outer.y());
const auto fill = _cachedRound.FillWithImage(p, outer, frame);
if (!fill.isEmpty()) {
p.fillRect(fill, _st.bg);
}
paintBubble(p, _inner.width());
}
@ -507,6 +574,13 @@ void Selector::paintExpanding(Painter &p, float64 progress) {
const auto rects = updateExpandingRects(progress);
paintExpandingBg(p, rects);
progress /= kFullDuration;
if (_about && !_aboutCache.isNull()) {
p.setClipping(false);
p.setOpacity((1. - progress) * (1. - progress));
const auto y = _about->y() - _outer.y() + rects.outer.y();
p.drawImage(_about->x(), y, _aboutCache);
p.setOpacity(1.);
}
if (_footer) {
_footer->paintExpanding(
p,
@ -537,25 +611,36 @@ Selector::ExpandingRects Selector::updateExpandingRects(float64 progress) {
: radiusStart;
const auto margins = marginsForShadow();
const auto expanding = anim::easeOutCirc(1., progress);
const auto expandUp = anim::interpolate(0, _collapsedTopSkip, expanding);
const auto expandUp = anim::interpolate(0, _topAddOnExpand, expanding);
const auto expandDown = anim::interpolate(
0,
(height() - _outer.y() - _outer.height()),
expanding);
const auto outer = _outer.marginsAdded({ 0, expandUp, 0, expandDown });
const auto categories = anim::interpolate(
0,
extendTopForCategories(),
expanding);
const auto inner = outer.marginsRemoved(margins);
_shadowTop = inner.y() + categories;
const auto inner = outer.marginsRemoved(margins
+ QMargins{
0,
anim::interpolate(_aboutExtend, 0, expanding),
0,
0 });
const auto list = outer.marginsRemoved(margins
+ QMargins{
0,
anim::interpolate(
_aboutExtend,
extendTopForCategories(),
expanding),
0,
0 });
_shadowTop = list.y();
const auto categories = list.y() - inner.y();
_shadowSkip = (_useTransparency && categories < radius)
? int(base::SafeRound(
radius - sqrt(categories * (2 * radius - categories))))
: 0;
return {
.categories = QRect(inner.x(), inner.y(), inner.width(), categories),
.list = inner.marginsRemoved({ 0, categories, 0, 0 }),
.list = list,
.radius = radius,
.expanding = expanding,
.finalBottom = height() - margins.bottom(),
@ -651,7 +736,7 @@ void Selector::paintBubble(QPainter &p, int innerWidth) {
bubble.paint(
p,
_inner.x() + innerWidth - bubbleRight - bubble.width(),
_inner.y() + _inner.height() - _collapsedTopSkip,
_inner.y() + _inner.height() - _outer.y(),
width());
}
@ -804,6 +889,9 @@ void Selector::expand() {
base::call_delayed(kExpandDelay, this, [this] {
const auto full = kExpandDuration + kScaleDuration;
if (_about) {
_about->hide();
}
_expanded = true;
_paintBuffer = _cachedRound.PrepareImage(size());
_expanding.start([=] { update(); }, 0., full, full);
@ -932,12 +1020,12 @@ bool AdjustMenuGeometryForSelector(
const auto maxWidth = menu->st().menu.widthMax + added;
const auto width = selector->countWidth(desiredWidth, maxWidth);
const auto margins = selector->marginsForShadow();
const auto categoriesTop = selector->useTransparency()
? selector->extendTopForCategories()
const auto categoriesAboutTop = selector->useTransparency()
? selector->extendTopForCategoriesAndAbout(width)
: 0;
menu->setForceWidth(width - added);
const auto height = menu->height();
const auto fullTop = margins.top() + categoriesTop + extend.top();
const auto fullTop = margins.top() + categoriesAboutTop + extend.top();
const auto minimalHeight = margins.top()
+ selector->minimalHeight()
+ margins.bottom();
@ -1063,7 +1151,7 @@ AttachSelectorResult AttachSelectorToMenu(
QPoint desiredPosition,
not_null<HistoryItem*> item,
Fn<void(ChosenReaction)> chosen,
TextWithEntities description,
TextWithEntities about,
IconFactory iconFactory) {
const auto result = AttachSelectorToMenu(
menu,
@ -1071,6 +1159,7 @@ AttachSelectorResult AttachSelectorToMenu(
st::reactPanelEmojiPan,
controller->uiShow(),
Data::LookupPossibleReactions(item),
std::move(about),
std::move(iconFactory));
if (!result) {
return result.error();
@ -1103,6 +1192,7 @@ auto AttachSelectorToMenu(
const style::EmojiPan &st,
std::shared_ptr<ChatHelpers::Show> show,
const Data::PossibleItemReactionsRef &reactions,
TextWithEntities about,
IconFactory iconFactory)
-> base::expected<not_null<Selector*>, AttachSelectorResult> {
if (reactions.recent.empty()) {
@ -1114,6 +1204,7 @@ auto AttachSelectorToMenu(
st,
std::move(show),
std::move(reactions),
std::move(about),
std::move(iconFactory),
[=](bool fast) { menu->hideMenu(fast); },
false); // child

View file

@ -36,6 +36,7 @@ namespace Ui {
class PopupMenu;
class ScrollArea;
class PlainShadow;
class FlatLabel;
} // namespace Ui
namespace HistoryView::Reactions {
@ -80,6 +81,7 @@ public:
const style::EmojiPan &st,
std::shared_ptr<ChatHelpers::Show> show,
const Data::PossibleItemReactionsRef &reactions,
TextWithEntities about,
IconFactory iconFactory,
Fn<void(bool fast)> close,
bool child = false);
@ -91,12 +93,14 @@ public:
std::vector<DocumentId> recent,
Fn<void(bool fast)> close,
bool child = false);
~Selector();
[[nodiscard]] bool useTransparency() const;
int countWidth(int desiredWidth, int maxWidth);
[[nodiscard]] QMargins marginsForShadow() const;
[[nodiscard]] int extendTopForCategories() const;
[[nodiscard]] int extendTopForCategoriesAndAbout(int width) const;
[[nodiscard]] int minimalHeight() const;
[[nodiscard]] int countAppearedWidth(float64 progress) const;
void setSpecialExpandTopSkip(int skip);
@ -137,6 +141,7 @@ private:
const Data::PossibleItemReactionsRef &reactions,
ChatHelpers::EmojiListMode mode,
std::vector<DocumentId> recent,
TextWithEntities about,
IconFactory iconFactory,
Fn<void(bool fast)> close,
bool child);
@ -179,6 +184,8 @@ private:
Fn<void()> _jumpedToPremium;
Ui::RoundAreaWithShadow _cachedRound;
std::unique_ptr<Strip> _strip;
std::unique_ptr<Ui::FlatLabel> _about;
mutable int _aboutExtend = 0;
rpl::event_stream<ChosenReaction> _chosen;
rpl::event_stream<> _willExpand;
@ -200,9 +207,11 @@ private:
QRect _outer;
QRect _outerWithBubble;
QImage _expandIconCache;
QImage _aboutCache;
QMargins _padding;
int _specialExpandTopSkip = 0;
int _collapsedTopSkip = 0;
int _topAddOnExpand = 0;
const int _size = 0;
int _recentRows = 0;
int _columns = 0;
@ -243,7 +252,7 @@ AttachSelectorResult AttachSelectorToMenu(
QPoint desiredPosition,
not_null<HistoryItem*> item,
Fn<void(ChosenReaction)> chosen,
TextWithEntities description,
TextWithEntities about,
IconFactory iconFactory);
[[nodiscard]] auto AttachSelectorToMenu(
@ -252,6 +261,7 @@ AttachSelectorResult AttachSelectorToMenu(
const style::EmojiPan &st,
std::shared_ptr<ChatHelpers::Show> show,
const Data::PossibleItemReactionsRef &reactions,
TextWithEntities about,
IconFactory iconFactory
) -> base::expected<not_null<Selector*>, AttachSelectorResult>;

View file

@ -675,6 +675,9 @@ void Reactions::Panel::create() {
st::storiesReactionsPan,
_controller->uiShow(),
std::move(reactions),
TextWithEntities{ (mode == Mode::Message
? u"Send reaction as a private message"_q
: QString()) },
_controller->cachedReactionIconFactory().createMethod(),
[=](bool fast) { hide(mode); });
@ -689,7 +692,8 @@ void Reactions::Panel::create() {
const auto maxWidth = desiredWidth * 2;
const auto width = _selector->countWidth(desiredWidth, maxWidth);
const auto margins = _selector->marginsForShadow();
const auto categoriesTop = _selector->extendTopForCategories();
const auto categoriesTop = _selector->extendTopForCategoriesAndAbout(
width);
const auto full = margins.left() + width + margins.right();
_shownValue = 0.;
@ -874,6 +878,7 @@ auto Reactions::attachToMenu(
st::storiesReactionsPan,
show,
LookupPossibleReactions(&show->session()),
TextWithEntities(),
_controller->cachedReactionIconFactory().createMethod());
if (!result) {
return result.error();