Add 'x' button to AI Tools info toast.

This commit is contained in:
John Preston
2026-04-03 00:47:24 +07:00
parent a6d5300057
commit beeb4663c4
11 changed files with 183 additions and 153 deletions
+2
View File
@@ -826,6 +826,8 @@ PRIVATE
history/view/controls/compose_controls_common.h
history/view/controls/history_view_compose_ai_button.cpp
history/view/controls/history_view_compose_ai_button.h
history/view/controls/history_view_compose_ai_tooltip.cpp
history/view/controls/history_view_compose_ai_tooltip.h
history/view/controls/history_view_compose_controls.cpp
history/view/controls/history_view_compose_controls.h
history/view/controls/history_view_compose_media_edit_manager.cpp
@@ -1444,6 +1444,14 @@ historyAiComposeButtonStar1: icon{{ "chat/ai_star1-20x20", historyComposeIconFg
historyAiComposeButtonStar2: icon{{ "chat/ai_star2-20x20", historyComposeIconFg }};
historyAiComposeButtonPosition: point(-8px, -4px);
historyAiComposeTooltipSkip: 8px;
importantTooltipHide: IconButton(defaultIconButton) {
width: 34px;
height: 20px;
iconPosition: point(-1px, -1px);
icon: icon {{ "calls/video_tooltip", importantTooltipFg }};
iconOver: icon {{ "calls/video_tooltip", importantTooltipFg }};
ripple: emptyRippleAnimation;
}
boxAiComposeButtonPosition: point(0px, -4px);
historyRecordFrameIndex: 30;
@@ -838,15 +838,6 @@ dialogsStoriesTooltip: ImportantTooltip(defaultImportantTooltip) {
}
dialogsStoriesTooltipLabel: defaultImportantTooltipLabel;
dialogsStoriesTooltipMaxWidth: 200px;
dialogsStoriesTooltipHide: IconButton(defaultIconButton) {
width: 34px;
height: 20px;
iconPosition: point(-1px, -1px);
icon: icon {{ "calls/video_tooltip", importantTooltipFg }};
iconOver: icon {{ "calls/video_tooltip", importantTooltipFg }};
ripple: emptyRippleAnimation;
}
searchedBarHeight: 28px;
searchedBarFont: normalFont;
searchedBarPosition: point(14px, 5px);
@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/dynamic_image.h"
#include "ui/painter.h"
#include "ui/ui_utility.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_dialogs.h"
#include <QtWidgets/QApplication>
@@ -47,33 +48,6 @@ constexpr auto kMaxTooltipNames = 3;
return full.photoLeft * 2 + full.photo - 2 * skip;
}
[[nodiscard]] object_ptr<Ui::RpWidget> MakeTooltipContent(
not_null<QWidget*> parent,
rpl::producer<TextWithEntities> text,
Fn<void()> hide) {
const auto size = st::dialogsStoriesTooltipHide.width;
const auto skip = st::defaultImportantTooltip.padding.right();
auto result = object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>(
parent,
Ui::MakeNiceTooltipLabel(
parent,
std::move(text),
st::dialogsStoriesTooltipMaxWidth,
st::dialogsStoriesTooltipLabel),
(st::defaultImportantTooltip.padding
+ QMargins(0, 0, skip + size, 0)));
const auto button = Ui::CreateChild<Ui::IconButton>(
result.data(),
st::dialogsStoriesTooltipHide);
result->sizeValue(
) | rpl::on_next([=](QSize size) {
button->resize(button->width(), size.height());
button->moveToRight(0, 0, size.width());
}, button->lifetime());
button->setClickedCallback(std::move(hide));
return result;
}
} // namespace
struct List::Layout {
@@ -1006,9 +980,13 @@ void List::setShowTooltip(
};
_tooltip = std::make_unique<Ui::ImportantTooltip>(
tooltipParent,
MakeTooltipContent(
Ui::MakeTooltipWithClose(
tooltipParent,
_tooltipText.value() | rpl::filter(notEmpty),
st::dialogsStoriesTooltipMaxWidth,
st::dialogsStoriesTooltipLabel,
st::importantTooltipHide,
st::defaultImportantTooltip.padding,
_tooltipHide),
st::dialogsStoriesTooltip);
const auto tooltip = _tooltip.get();
+12 -54
View File
@@ -104,6 +104,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/admin_log/history_admin_log_section.h"
#include "history/view/controls/history_view_characters_limit.h"
#include "history/view/controls/history_view_compose_ai_button.h"
#include "history/view/controls/history_view_compose_ai_tooltip.h"
#include "history/view/controls/history_view_compose_search.h"
#include "history/view/controls/history_view_forward_panel.h"
#include "history/view/controls/history_view_draft_options.h"
@@ -167,7 +168,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/checkbox.h"
#include "ui/widgets/elastic_scroll.h"
#include "ui/widgets/popup_menu.h"
#include "ui/widgets/tooltip.h"
#include "ui/item_text_options.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
@@ -214,7 +214,6 @@ constexpr auto kSaveDraftTimeout = crl::time(1000);
constexpr auto kSaveDraftAnywayTimeout = 5 * crl::time(1000);
constexpr auto kSaveCloudDraftIdleTimeout = 14 * crl::time(1000);
constexpr auto kRefreshSlowmodeLabelTimeout = crl::time(200);
constexpr auto kAiComposeTooltipHiddenPref = "ai_compose_tooltip_hidden"_cs;
constexpr auto kCommonModifiers = 0
| Qt::ShiftModifier
| Qt::MetaModifier
@@ -1294,35 +1293,17 @@ void HistoryWidget::initAiButton() {
_aiButton->hide();
_aiButton->setAccessibleName(tr::lng_ai_compose_title(tr::now));
_aiButton->setClickedCallback([=] {
if (!Core::App().settings().readPref<bool>(kAiComposeTooltipHiddenPref)) {
Core::App().settings().writePref<bool>(kAiComposeTooltipHiddenPref, true);
}
if (_aiTooltip) {
_aiTooltipShown = false;
_aiTooltip->toggleAnimated(false);
if (_aiTooltipManager) {
_aiTooltipManager->hideAndRemember();
}
updateAiButtonVisibility();
showAiComposeBox();
});
_aiTooltip.reset(Ui::CreateChild<Ui::ImportantTooltip>(
_aiTooltipManager = std::make_unique<HistoryView::Controls::AiTooltipManager>(
this,
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>(
this,
Ui::MakeNiceTooltipLabel(
this,
tr::lng_ai_compose_tooltip(tr::rich),
st::historyMessagesTTLLabel.minWidth,
st::ttlMediaImportantTooltipLabel),
st::defaultImportantTooltip.padding),
st::historyRecordTooltip));
_aiTooltip->toggleFast(false);
_aiButton->geometryValue(
) | rpl::on_next([=](const QRect &geometry) {
if (!geometry.isEmpty()) {
updateAiTooltipGeometry();
}
}, _aiTooltip->lifetime());
_aiButton,
[=] { return width(); });
}
void HistoryWidget::initTabbedSelector() {
@@ -1888,8 +1869,8 @@ void HistoryWidget::orderWidgets() {
if (_attachBotsMenu) {
_attachBotsMenu->raise();
}
if (_aiTooltip) {
_aiTooltip->raise();
if (_aiTooltipManager) {
_aiTooltipManager->raise();
}
_attachDragAreas.document->raise();
_attachDragAreas.photo->raise();
@@ -6295,17 +6276,8 @@ void HistoryWidget::updateAiButtonVisibility() {
if (shown) {
updateAiButtonGeometry();
}
if (_aiTooltip) {
const auto showTooltip = shown
&& !Core::App().settings().readPref<bool>(kAiComposeTooltipHiddenPref);
if (showTooltip) {
updateAiTooltipGeometry();
}
if ((_aiTooltipShown != showTooltip)
|| (showTooltip && _aiTooltip->isHidden())) {
_aiTooltipShown = showTooltip;
_aiTooltip->toggleAnimated(showTooltip);
}
if (_aiTooltipManager) {
_aiTooltipManager->updateVisibility(shown);
}
}
@@ -6315,23 +6287,9 @@ void HistoryWidget::updateAiButtonGeometry() {
}
const auto x = _send->x() + _send->width() - _aiButton->width();
_aiButton->move(QPoint(x, _field->y()) + st::historyAiComposeButtonPosition);
updateAiTooltipGeometry();
}
void HistoryWidget::updateAiTooltipGeometry() {
if (!_aiTooltip || _aiButton->isHidden()) {
return;
if (_aiTooltipManager) {
_aiTooltipManager->updateGeometry();
}
const auto geometry = _aiButton->geometry();
const auto countPosition = [=](QSize size) {
const auto left = geometry.x()
+ geometry.width()
- size.width();
return QPoint(
std::clamp(left, 0, width() - size.width()),
geometry.y() - size.height() - st::historyAiComposeTooltipSkip);
};
_aiTooltip->pointAt(geometry, RectPart::Top, countPosition);
}
void HistoryWidget::moveFieldControls() {
@@ -63,7 +63,6 @@ namespace Ui {
class InnerDropdown;
class DropdownMenu;
class PlainShadow;
class ImportantTooltip;
class IconButton;
class EmojiButton;
class RpWidget;
@@ -129,6 +128,7 @@ class WebpageProcessor;
class CharactersLimitLabel;
class PhotoEditSpoilerManager;
class ComposeAiButton;
class AiTooltipManager;
struct VoiceToSend;
} // namespace HistoryView::Controls
@@ -528,7 +528,6 @@ private:
void initAiButton();
void updateAiButtonVisibility();
void updateAiButtonGeometry();
void updateAiTooltipGeometry();
void showAiComposeBox();
[[nodiscard]] bool canSendAiComposeDirect() const;
@@ -867,9 +866,8 @@ private:
std::unique_ptr<HistoryView::SubsectionTabs> _subsectionTabs;
rpl::lifetime _subsectionTabsLifetime;
rpl::lifetime _subsectionCheckLifetime;
base::unique_qptr<Ui::ImportantTooltip> _aiTooltip;
std::unique_ptr<HistoryView::Controls::AiTooltipManager> _aiTooltipManager;
std::shared_ptr<Ui::ChatStyle> _fieldChatStyle;
bool _aiTooltipShown = false;
bool _cmdStartShown = false;
object_ptr<Ui::InputField> _field;
base::unique_qptr<Ui::RpWidget> _fieldDisabled;
@@ -0,0 +1,97 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/controls/history_view_compose_ai_tooltip.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "history/view/controls/history_view_compose_ai_button.h"
#include "lang/lang_keys.h"
#include "ui/widgets/tooltip.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_widgets.h"
namespace HistoryView::Controls {
namespace {
constexpr auto kAiComposeTooltipHiddenPref = "ai_compose_tooltip_hidden"_cs;
} // namespace
AiTooltipManager::AiTooltipManager(
not_null<QWidget*> parent,
not_null<ComposeAiButton*> button,
Fn<int()> widthProvider)
: _button(button)
, _widthProvider(std::move(widthProvider)) {
_tooltip.reset(Ui::CreateChild<Ui::ImportantTooltip>(
parent,
Ui::MakeTooltipWithClose(
parent,
tr::lng_ai_compose_tooltip(tr::rich),
st::historyMessagesTTLLabel.minWidth,
st::ttlMediaImportantTooltipLabel,
st::importantTooltipHide,
st::defaultImportantTooltip.padding,
[=] { hideAndRemember(); }),
st::historyRecordTooltip));
_tooltip->toggleFast(false);
_button->geometryValue(
) | rpl::on_next([=](const QRect &geometry) {
if (!geometry.isEmpty()) {
updateGeometry();
}
}, _tooltip->lifetime());
}
void AiTooltipManager::hideAndRemember() {
if (!Core::App().settings().readPref<bool>(
kAiComposeTooltipHiddenPref)) {
Core::App().settings().writePref<bool>(
kAiComposeTooltipHiddenPref,
true);
}
_shown = false;
_tooltip->toggleAnimated(false);
}
void AiTooltipManager::updateVisibility(bool buttonShown) {
const auto showTooltip = buttonShown
&& !Core::App().settings().readPref<bool>(
kAiComposeTooltipHiddenPref);
if (showTooltip) {
updateGeometry();
}
if ((_shown != showTooltip)
|| (showTooltip && _tooltip->isHidden())) {
_shown = showTooltip;
_tooltip->toggleAnimated(showTooltip);
}
}
void AiTooltipManager::updateGeometry() {
if (_button->isHidden()) {
return;
}
const auto geometry = _button->geometry();
const auto maxWidth = _widthProvider();
const auto countPosition = [=](QSize size) {
const auto left = geometry.x()
+ geometry.width()
- size.width();
return QPoint(
std::clamp(left, 0, maxWidth - size.width()),
geometry.y() - size.height() - st::historyAiComposeTooltipSkip);
};
_tooltip->pointAt(geometry, RectPart::Top, countPosition);
}
void AiTooltipManager::raise() {
_tooltip->raise();
}
} // namespace HistoryView::Controls
@@ -0,0 +1,41 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/unique_qptr.h"
namespace Ui {
class ImportantTooltip;
class RpWidget;
} // namespace Ui
namespace HistoryView::Controls {
class ComposeAiButton;
class AiTooltipManager final {
public:
AiTooltipManager(
not_null<QWidget*> parent,
not_null<ComposeAiButton*> button,
Fn<int()> widthProvider);
void hideAndRemember();
void updateVisibility(bool buttonShown);
void updateGeometry();
void raise();
private:
const not_null<ComposeAiButton*> _button;
const Fn<int()> _widthProvider;
base::unique_qptr<Ui::ImportantTooltip> _tooltip;
bool _shown = false;
};
} // namespace HistoryView::Controls
@@ -62,6 +62,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h"
#include "history/view/controls/history_view_characters_limit.h"
#include "history/view/controls/history_view_compose_ai_button.h"
#include "history/view/controls/history_view_compose_ai_tooltip.h"
#include "history/view/controls/history_view_compose_media_edit_manager.h"
#include "history/view/controls/history_view_forward_panel.h"
#include "history/view/controls/history_view_draft_options.h"
@@ -125,7 +126,6 @@ constexpr auto kMaxStarSendEffects = 4;
constexpr auto kMaxStarEffects = 4;
constexpr auto kStarEffectDuration = 2 * crl::time(1000);
constexpr auto kStarEffectRotationMax = 12;
constexpr auto kAiComposeTooltipHiddenPref = "ai_compose_tooltip_hidden"_cs;
constexpr auto kStarEffectScaleMin = 0.3;
constexpr auto kStarEffectScaleMax = 0.7;
@@ -1905,8 +1905,8 @@ void ComposeControls::showFinished() {
}
updateWrappingVisibility();
_aiButton->raise();
if (_aiTooltip) {
_aiTooltip->raise();
if (_aiTooltipManager) {
_aiTooltipManager->raise();
}
_voiceRecordBar->orderControls();
}
@@ -3298,35 +3298,17 @@ void ComposeControls::initAiButton() {
_aiButton->hide();
_aiButton->setAccessibleName(tr::lng_ai_compose_title(tr::now));
_aiButton->setClickedCallback([=] {
if (!Core::App().settings().readPref<bool>(kAiComposeTooltipHiddenPref)) {
Core::App().settings().writePref<bool>(kAiComposeTooltipHiddenPref, true);
}
if (_aiTooltip) {
_aiTooltipShown = false;
_aiTooltip->toggleAnimated(false);
if (_aiTooltipManager) {
_aiTooltipManager->hideAndRemember();
}
updateAiButtonVisibility();
showAiComposeBox();
});
_aiTooltip.reset(Ui::CreateChild<Ui::ImportantTooltip>(
_aiTooltipManager = std::make_unique<Controls::AiTooltipManager>(
_wrap.get(),
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>(
_wrap.get(),
Ui::MakeNiceTooltipLabel(
_wrap.get(),
tr::lng_ai_compose_tooltip(tr::rich),
st::historyMessagesTTLLabel.minWidth,
st::ttlMediaImportantTooltipLabel),
st::defaultImportantTooltip.padding),
st::historyRecordTooltip));
_aiTooltip->toggleFast(false);
_aiButton->geometryValue(
) | rpl::on_next([=](const QRect &geometry) {
if (!geometry.isEmpty()) {
updateAiTooltipGeometry();
}
}, _aiTooltip->lifetime());
_aiButton,
[=] { return _wrap->width(); });
}
void ComposeControls::updateWrappingVisibility() {
@@ -3586,17 +3568,8 @@ void ComposeControls::updateAiButtonVisibility() {
if (shown) {
updateAiButtonGeometry();
}
if (_aiTooltip) {
const auto showTooltip = shown
&& !Core::App().settings().readPref<bool>(kAiComposeTooltipHiddenPref);
if (showTooltip) {
updateAiTooltipGeometry();
}
if ((_aiTooltipShown != showTooltip)
|| (showTooltip && _aiTooltip->isHidden())) {
_aiTooltipShown = showTooltip;
_aiTooltip->toggleAnimated(showTooltip);
}
if (_aiTooltipManager) {
_aiTooltipManager->updateVisibility(shown);
}
}
@@ -3606,23 +3579,9 @@ void ComposeControls::updateAiButtonGeometry() {
}
const auto x = _send->x() + _send->width() - _aiButton->width();
_aiButton->move(QPoint(x, _field->y()) + st::historyAiComposeButtonPosition);
updateAiTooltipGeometry();
}
void ComposeControls::updateAiTooltipGeometry() {
if (!_aiTooltip || _aiButton->isHidden()) {
return;
if (_aiTooltipManager) {
_aiTooltipManager->updateGeometry();
}
const auto geometry = _aiButton->geometry();
const auto countPosition = [=](QSize size) {
const auto left = geometry.x()
+ geometry.width()
- size.width();
return QPoint(
std::clamp(left, 0, _wrap->width() - size.width()),
geometry.y() - size.height() - st::historyAiComposeTooltipSkip);
};
_aiTooltip->pointAt(geometry, RectPart::Top, countPosition);
}
bool ComposeControls::updateLikeShown() {
@@ -68,7 +68,6 @@ class EmojiButton;
class SendAsButton;
class SilentToggle;
class DropdownMenu;
class ImportantTooltip;
struct PreparedList;
struct SendStarButtonState;
class ReactionFlyAnimation;
@@ -103,6 +102,7 @@ class TTLButton;
class WebpageProcessor;
class CharactersLimitLabel;
class ComposeAiButton;
class AiTooltipManager;
} // namespace HistoryView::Controls
namespace HistoryView {
@@ -328,7 +328,6 @@ private:
void updateControlsGeometry(QSize size);
void updateAiButtonVisibility();
void updateAiButtonGeometry();
void updateAiTooltipGeometry();
void setupSendMenu(
not_null<Ui::RpWidget*> button,
Fn<void(Api::SendOptions)> send);
@@ -476,8 +475,7 @@ private:
friend class FieldHeader;
const std::unique_ptr<FieldHeader> _header;
const std::unique_ptr<Controls::VoiceRecordBar> _voiceRecordBar;
base::unique_qptr<Ui::ImportantTooltip> _aiTooltip;
bool _aiTooltipShown = false;
std::unique_ptr<Controls::AiTooltipManager> _aiTooltipManager;
std::shared_ptr<Ui::ChatStyle> _chatStyle;
const Fn<SendMenu::Details()> _sendMenuDetails;