diff --git a/Telegram/Resources/icons/chat/ai_letters.svg b/Telegram/Resources/icons/chat/ai_letters.svg
new file mode 100644
index 0000000000..47c8ce91d6
--- /dev/null
+++ b/Telegram/Resources/icons/chat/ai_letters.svg
@@ -0,0 +1,8 @@
+
+
diff --git a/Telegram/Resources/icons/chat/ai_star1.svg b/Telegram/Resources/icons/chat/ai_star1.svg
new file mode 100644
index 0000000000..4c62840ce6
--- /dev/null
+++ b/Telegram/Resources/icons/chat/ai_star1.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/Telegram/Resources/icons/chat/ai_star2.svg b/Telegram/Resources/icons/chat/ai_star2.svg
new file mode 100644
index 0000000000..45d06aefd7
--- /dev/null
+++ b/Telegram/Resources/icons/chat/ai_star2.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style
index b0eb4c9420..a9d49e65f0 100644
--- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style
+++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style
@@ -1421,27 +1421,15 @@ historySend: SendButton {
sendIconFg: historySendIconFg;
}
historyAiComposeButton: IconButton(historyAttach) {
- width: 34px;
- height: 34px;
- icon: historySendIcon;
- iconOver: historySendIconOver;
- iconPosition: point(10px, 10px);
+ width: 28px;
+ height: 28px;
+ rippleAreaSize: 28px;
rippleAreaPosition: point(0px, 0px);
- rippleAreaSize: 34px;
- ripple: defaultRippleAnimationBgOver;
}
-historyAiComposeButtonBg: transparent;
-historyAiComposeButtonBgOver: transparent;
-historyAiComposeButtonTextFg: historyComposeIconFg;
-historyAiComposeButtonTextFgOver: historyComposeIconFgOver;
-historyAiComposeButtonFont: font(15px semibold);
-historyAiComposeButtonTextShift: point(1px, 1px);
-historyAiComposeButtonSparkleBigPosition: point(10px, 12px);
-historyAiComposeButtonSparkleBigRadius: 3px;
-historyAiComposeButtonSparkleSmallPosition: point(16px, 8px);
-historyAiComposeButtonSparkleSmallRadius: 2px;
-historyAiComposeButtonSparkleStroke: 1px;
-historyAiComposeButtonTop: -4px;
+historyAiComposeButtonLetters: icon{{ "chat/ai_letters-20x20", historyComposeIconFg }};
+historyAiComposeButtonStar1: icon{{ "chat/ai_star1-20x20", historyComposeIconFg }};
+historyAiComposeButtonStar2: icon{{ "chat/ai_star2-20x20", historyComposeIconFg }};
+historyAiComposeButtonPosition: point(-8px, -4px);
historyAiComposeTooltipSkip: 8px;
historyRecordFrameIndex: 30;
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index 4fb8c65aae..57eb8b67db 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -6274,20 +6274,24 @@ bool HistoryWidget::hasEnoughLinesForAi() const {
}
void HistoryWidget::updateAiButtonVisibility() {
- const auto shown = hasEnoughLinesForAi()
- && _send->isVisible()
- && _field->isVisible();
+ const auto hidden = !hasEnoughLinesForAi()
+ || !_send->isVisible()
+ || !_field->isVisible();
+ if (_aiButton->isHidden() == hidden) {
+ return;
+ }
+ const auto shown = !hidden;
_aiButton->setVisible(shown);
+ if (shown) {
+ updateAiButtonGeometry();
+ }
if (_aiTooltip) {
- if (shown) {
- updateAiButtonGeometry();
- }
const auto showTooltip = shown
&& !Core::App().settings().readPref(kAiComposeTooltipHiddenPref);
if (showTooltip) {
updateAiTooltipGeometry();
}
- if ((showTooltip != _aiTooltipShown)
+ if ((_aiTooltipShown != showTooltip)
|| (showTooltip && _aiTooltip->isHidden())) {
_aiTooltipShown = showTooltip;
_aiTooltip->toggleAnimated(showTooltip);
@@ -6299,9 +6303,8 @@ void HistoryWidget::updateAiButtonGeometry() {
if (_aiButton->isHidden()) {
return;
}
- _aiButton->move(
- _send->x() + _send->width() - _aiButton->width(),
- _field->y() + st::historyAiComposeButtonTop);
+ const auto x = _send->x() + _send->width() - _aiButton->width();
+ _aiButton->move(QPoint(x, _field->y()) + st::historyAiComposeButtonPosition);
updateAiTooltipGeometry();
}
diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_ai_button.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_ai_button.cpp
index 5e764f206e..bc33c029fb 100644
--- a/Telegram/SourceFiles/history/view/controls/history_view_compose_ai_button.cpp
+++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_ai_button.cpp
@@ -14,18 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView::Controls {
namespace {
-void PaintSparkle(QPainter &p, QPoint center, int radius) {
- p.drawLine(
- center.x() - radius,
- center.y(),
- center.x() + radius,
- center.y());
- p.drawLine(
- center.x(),
- center.y() - radius,
- center.x(),
- center.y() + radius);
-}
+constexpr auto kAnimationDuration = crl::time(640);
} // namespace
@@ -36,6 +25,15 @@ ComposeAiButton::ComposeAiButton(
, _st(st) {
resize(_st.width, _st.height);
setCursor(style::cur_pointer);
+
+ shownValue(
+ ) | rpl::on_next([=](bool shown) {
+ if (shown) {
+ _animation.start([=] { update(); }, 0., 1., kAnimationDuration);
+ } else {
+ _animation.stop();
+ }
+ }, lifetime());
}
void ComposeAiButton::paintEvent(QPaintEvent *e) {
@@ -43,37 +41,39 @@ void ComposeAiButton::paintEvent(QPaintEvent *e) {
PainterHighQualityEnabler hq(p);
const auto over = isDown() || isOver() || forceRippled();
- const auto bg = over
- ? st::historyAiComposeButtonBgOver
- : st::historyAiComposeButtonBg;
- if (bg->c.alpha()) {
- p.setPen(Qt::NoPen);
- p.setBrush(bg);
- p.drawEllipse(rect());
- }
paintRipple(p, _st.rippleAreaPosition);
- const auto fg = over
- ? st::historyAiComposeButtonTextFgOver
- : st::historyAiComposeButtonTextFg;
- auto pen = QPen(fg);
- pen.setWidth(st::historyAiComposeButtonSparkleStroke);
- pen.setCapStyle(Qt::RoundCap);
- p.setPen(pen);
- PaintSparkle(
- p,
- st::historyAiComposeButtonSparkleBigPosition,
- st::historyAiComposeButtonSparkleBigRadius);
- PaintSparkle(
- p,
- st::historyAiComposeButtonSparkleSmallPosition,
- st::historyAiComposeButtonSparkleSmallRadius);
+ const auto progress = _animation.value(1.);
+ auto star1Opacity = 1.;
+ auto star2Opacity = 1.;
+ if (progress < 0.25) {
+ star1Opacity = 1. - (progress / 0.25);
+ } else if (progress < 0.5) {
+ star1Opacity = 0.;
+ star2Opacity = 1. - ((progress - 0.25) / 0.25);
+ } else if (progress < 0.75) {
+ star1Opacity = (progress - 0.5) / 0.25;
+ star2Opacity = 0.;
+ } else {
+ star2Opacity = (progress - 0.75) / 0.25;
+ }
- p.setFont(st::historyAiComposeButtonFont);
- p.drawText(
- rect().translated(st::historyAiComposeButtonTextShift),
- Qt::AlignCenter,
- u"Ai"_q);
+ const auto part = [&](const style::icon &icon) {
+ if (over) {
+ icon.paintInCenter(p, rect(), st::historyComposeIconFgOver->c);
+ } else {
+ icon.paintInCenter(p, rect());
+ }
+ };
+ part(st::historyAiComposeButtonLetters);
+ if (star1Opacity > 0.) {
+ p.setOpacity(star1Opacity);
+ part(st::historyAiComposeButtonStar1);
+ }
+ if (star2Opacity > 0.) {
+ p.setOpacity(star2Opacity);
+ part(st::historyAiComposeButtonStar2);
+ }
}
void ComposeAiButton::onStateChanged(State was, StateChangeSource source) {
diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_ai_button.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_ai_button.h
index 8fe0c299fb..7d326b5d46 100644
--- a/Telegram/SourceFiles/history/view/controls/history_view_compose_ai_button.h
+++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_ai_button.h
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
+#include "ui/effects/animations.h"
#include "ui/widgets/buttons.h"
namespace HistoryView::Controls {
@@ -24,6 +25,7 @@ protected:
private:
const style::IconButton &_st;
+ Ui::Animations::Simple _animation;
};
diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
index 2a4729a009..455bba1bf2 100644
--- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
+++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
@@ -3550,18 +3550,26 @@ void ComposeControls::updateControlsVisibility() {
}
void ComposeControls::updateAiButtonVisibility() {
- const auto shown = hasEnoughLinesForAi()
- && _wrap->isVisible()
- && !_recording.current()
- && _field->isVisible();
+ const auto hidden = !hasEnoughLinesForAi()
+ || !_wrap->isVisible()
+ || _recording.current()
+ || !_field->isVisible();
+ if (_aiButton->isHidden() == hidden) {
+ return;
+ }
+ const auto shown = !hidden;
_aiButton->setVisible(shown);
+ if (shown) {
+ updateAiButtonGeometry();
+ }
if (_aiTooltip) {
const auto showTooltip = shown
&& !Core::App().settings().readPref(kAiComposeTooltipHiddenPref);
if (showTooltip) {
updateAiTooltipGeometry();
}
- if (showTooltip != _aiTooltipShown) {
+ if ((_aiTooltipShown != showTooltip)
+ || (showTooltip && _aiTooltip->isHidden())) {
_aiTooltipShown = showTooltip;
_aiTooltip->toggleAnimated(showTooltip);
}
@@ -3572,9 +3580,8 @@ void ComposeControls::updateAiButtonGeometry() {
if (_aiButton->isHidden()) {
return;
}
- _aiButton->move(
- _send->x() + (_send->width() - _aiButton->width()) / 2,
- _field->y() + st::historyAiComposeButtonTop);
+ const auto x = _send->x() + _send->width() - _aiButton->width();
+ _aiButton->move(QPoint(x, _field->y()) + st::historyAiComposeButtonPosition);
updateAiTooltipGeometry();
}