mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Support AI Tools in media box.
This commit is contained in:
@@ -1751,6 +1751,8 @@ PRIVATE
|
||||
ui/chat/choose_theme_controller.h
|
||||
ui/chat/sponsored_message_bar.cpp
|
||||
ui/chat/sponsored_message_bar.h
|
||||
ui/controls/compose_ai_button_factory.cpp
|
||||
ui/controls/compose_ai_button_factory.h
|
||||
ui/controls/emoji_button_factory.cpp
|
||||
ui/controls/emoji_button_factory.h
|
||||
ui/controls/location_picker.cpp
|
||||
|
||||
@@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history.h"
|
||||
#include "history/view/controls/history_view_compose_ai_button.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "menu/menu_checked_action.h"
|
||||
#include "main/main_session.h"
|
||||
@@ -50,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/chat/attach/attach_item_single_media_preview.h"
|
||||
#include "ui/chat/attach/attach_single_file_preview.h"
|
||||
#include "ui/chat/attach/attach_single_media_preview.h"
|
||||
#include "ui/controls/compose_ai_button_factory.h"
|
||||
#include "ui/controls/emoji_button.h"
|
||||
#include "ui/effects/scroll_content_shadow.h"
|
||||
#include "ui/image/image.h"
|
||||
@@ -615,6 +617,13 @@ void EditCaptionBox::setupField() {
|
||||
}
|
||||
Unexpected("Action in MimeData hook.");
|
||||
});
|
||||
|
||||
_aiButton = Ui::SetupCaptionAiButton({
|
||||
.parent = this,
|
||||
.field = _field.get(),
|
||||
.session = &_controller->session(),
|
||||
.show = _controller->uiShow(),
|
||||
});
|
||||
}
|
||||
|
||||
void EditCaptionBox::setupFieldAutocomplete() {
|
||||
@@ -1165,6 +1174,11 @@ void EditCaptionBox::resizeEvent(QResizeEvent *e) {
|
||||
_field->y() + st::boxAttachEmojiTop);
|
||||
_emojiToggle->update();
|
||||
|
||||
if (_aiButton) {
|
||||
Ui::UpdateCaptionAiButtonGeometry(_aiButton, _field.get());
|
||||
_aiButton->raise();
|
||||
}
|
||||
|
||||
if (!_controls->isHidden()) {
|
||||
_controls->resizeToWidth(width());
|
||||
_controls->moveToLeft(
|
||||
|
||||
@@ -24,6 +24,10 @@ namespace Data {
|
||||
class PhotoMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace HistoryView::Controls {
|
||||
class ComposeAiButton;
|
||||
} // namespace HistoryView::Controls
|
||||
|
||||
namespace Ui {
|
||||
class AbstractSinglePreview;
|
||||
class InputField;
|
||||
@@ -128,6 +132,7 @@ private:
|
||||
const base::unique_qptr<Ui::ScrollArea> _scroll;
|
||||
const base::unique_qptr<Ui::InputField> _field;
|
||||
const base::unique_qptr<Ui::EmojiButton> _emojiToggle;
|
||||
HistoryView::Controls::ComposeAiButton *_aiButton = nullptr;
|
||||
|
||||
std::unique_ptr<ChatHelpers::FieldAutocomplete> _autocomplete;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "editor/photo_editor_layer_widget.h"
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/view/controls/history_view_characters_limit.h"
|
||||
#include "history/view/controls/history_view_compose_ai_button.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "core/mime_type.h"
|
||||
#include "core/ui_integration.h"
|
||||
@@ -47,6 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/grouped_layout.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/controls/compose_ai_button_factory.h"
|
||||
#include "ui/controls/emoji_button.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
@@ -192,6 +194,21 @@ void EditFileCaptionBox(
|
||||
&& Data::AllowEmojiWithoutPremium(captionToPeer, emoji);
|
||||
},
|
||||
PremiumFeature::EmojiStatus);
|
||||
if (controller) {
|
||||
const auto aiButton = Ui::SetupCaptionAiButton({
|
||||
.parent = field->parentWidget(),
|
||||
.field = field,
|
||||
.session = &controller->session(),
|
||||
.show = controller->uiShow(),
|
||||
});
|
||||
rpl::combine(
|
||||
box->sizeValue(),
|
||||
field->geometryValue()
|
||||
) | rpl::on_next([=](QSize, QRect) {
|
||||
Ui::UpdateCaptionAiButtonGeometry(aiButton, field);
|
||||
aiButton->raise();
|
||||
}, aiButton->lifetime());
|
||||
}
|
||||
}
|
||||
field->setTextWithTags(std::move(currentCaption));
|
||||
|
||||
@@ -1181,6 +1198,10 @@ void SendFilesBox::updateCaptionVisibility() {
|
||||
if (_emojiToggle) {
|
||||
_emojiToggle->setVisible(can);
|
||||
}
|
||||
if (_aiButton) {
|
||||
_aiButton->setVisible(can
|
||||
&& Ui::HasEnoughLinesForAi(&_show->session(), _caption.data()));
|
||||
}
|
||||
}
|
||||
|
||||
void SendFilesBox::preparePreview() {
|
||||
@@ -1812,6 +1833,13 @@ void SendFilesBox::setupCaption() {
|
||||
checkCharsLimitation();
|
||||
refreshMessagesCount();
|
||||
}, _caption->lifetime());
|
||||
|
||||
_aiButton = Ui::SetupCaptionAiButton({
|
||||
.parent = this,
|
||||
.field = _caption.data(),
|
||||
.session = &_show->session(),
|
||||
.show = _show,
|
||||
});
|
||||
}
|
||||
|
||||
void SendFilesBox::setupCaptionAutocomplete() {
|
||||
@@ -2157,6 +2185,10 @@ void SendFilesBox::updateControlsGeometry() {
|
||||
_caption->y() + st::boxAttachEmojiTop);
|
||||
_emojiToggle->update();
|
||||
}
|
||||
if (_aiButton) {
|
||||
Ui::UpdateCaptionAiButtonGeometry(_aiButton, _caption.data());
|
||||
_aiButton->raise();
|
||||
}
|
||||
}
|
||||
const auto pairs = std::array<std::pair<RpWidget*, int>, 4>{ {
|
||||
{ _hintLabel.data(), st::editMediaLabelMargins.top() },
|
||||
|
||||
@@ -59,6 +59,7 @@ struct Action;
|
||||
|
||||
namespace HistoryView::Controls {
|
||||
class CharactersLimitLabel;
|
||||
class ComposeAiButton;
|
||||
} // namespace HistoryView::Controls
|
||||
|
||||
enum class SendFilesAllow {
|
||||
@@ -304,6 +305,7 @@ private:
|
||||
std::unique_ptr<ChatHelpers::FieldAutocomplete> _autocomplete;
|
||||
TextWithTags _prefilledCaptionText;
|
||||
object_ptr<Ui::EmojiButton> _emojiToggle = { nullptr };
|
||||
HistoryView::Controls::ComposeAiButton *_aiButton = nullptr;
|
||||
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
|
||||
base::unique_qptr<QObject> _emojiFilter;
|
||||
using CharactersLimitLabel = HistoryView::Controls::CharactersLimitLabel;
|
||||
|
||||
@@ -1434,6 +1434,7 @@ historyAiComposeButtonStar1: icon{{ "chat/ai_star1-20x20", historyComposeIconFg
|
||||
historyAiComposeButtonStar2: icon{{ "chat/ai_star2-20x20", historyComposeIconFg }};
|
||||
historyAiComposeButtonPosition: point(-8px, -4px);
|
||||
historyAiComposeTooltipSkip: 8px;
|
||||
boxAiComposeButtonPosition: point(0px, -4px);
|
||||
historyRecordFrameIndex: 30;
|
||||
|
||||
defaultComposeFilesMenu: IconButton(defaultIconButton) {
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
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 "ui/controls/compose_ai_button_factory.h"
|
||||
|
||||
#include "boxes/compose_ai_box.h"
|
||||
#include "history/view/controls/history_view_compose_ai_button.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/text/text_entity.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
|
||||
#include "styles/style_chat_helpers.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
bool HasEnoughLinesForAi(
|
||||
not_null<Main::Session*> session,
|
||||
not_null<Ui::InputField*> field) {
|
||||
if (session->appConfig().aiComposeStyles().empty()) {
|
||||
return false;
|
||||
}
|
||||
const auto &style = field->st().style;
|
||||
const auto lineHeight = style.lineHeight
|
||||
? style.lineHeight
|
||||
: style.font->height;
|
||||
const auto margins = field->fullTextMargins();
|
||||
const auto contentHeight = field->height()
|
||||
- margins.top()
|
||||
- margins.bottom();
|
||||
return contentHeight >= (3 * lineHeight);
|
||||
}
|
||||
|
||||
void UpdateCaptionAiButtonGeometry(
|
||||
not_null<HistoryView::Controls::ComposeAiButton*> button,
|
||||
not_null<Ui::InputField*> field) {
|
||||
if (button->isHidden()) {
|
||||
return;
|
||||
}
|
||||
const auto &pos = st::boxAiComposeButtonPosition;
|
||||
const auto x = field->x()
|
||||
+ field->width()
|
||||
- button->width()
|
||||
+ pos.x();
|
||||
const auto y = field->y()
|
||||
+ field->height()
|
||||
- button->height()
|
||||
+ pos.y();
|
||||
button->moveToLeft(x, y);
|
||||
}
|
||||
|
||||
auto SetupCaptionAiButton(SetupCaptionAiButtonArgs &&args)
|
||||
-> not_null<HistoryView::Controls::ComposeAiButton*> {
|
||||
const auto button = Ui::CreateChild<
|
||||
HistoryView::Controls::ComposeAiButton
|
||||
>(args.parent.get(), st::historyAiComposeButton);
|
||||
const auto field = args.field;
|
||||
const auto session = args.session;
|
||||
const auto show = std::move(args.show);
|
||||
|
||||
button->hide();
|
||||
button->setAccessibleName(tr::lng_ai_compose_title(tr::now));
|
||||
|
||||
button->setClickedCallback(crl::guard(field, [=] {
|
||||
const auto textWithTags = field->getTextWithAppliedMarkdown();
|
||||
if (textWithTags.text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
auto text = TextWithEntities{
|
||||
textWithTags.text,
|
||||
TextUtilities::ConvertTextTagsToEntities(textWithTags.tags),
|
||||
};
|
||||
HistoryView::Controls::ShowComposeAiBox(show, {
|
||||
.session = session,
|
||||
.text = std::move(text),
|
||||
.apply = crl::guard(field, [=](TextWithEntities result) {
|
||||
field->setTextWithTags(
|
||||
{
|
||||
result.text,
|
||||
TextUtilities::ConvertEntitiesToTextTags(
|
||||
result.entities),
|
||||
},
|
||||
Ui::InputField::HistoryAction::NewEntry);
|
||||
}),
|
||||
});
|
||||
}));
|
||||
|
||||
const auto updateVisibility = [=] {
|
||||
const auto visible = !field->isHidden()
|
||||
&& HasEnoughLinesForAi(session, field);
|
||||
button->setVisible(visible);
|
||||
if (visible) {
|
||||
UpdateCaptionAiButtonGeometry(button, field);
|
||||
button->raise();
|
||||
}
|
||||
};
|
||||
|
||||
rpl::merge(
|
||||
field->heightChanges() | rpl::to_empty,
|
||||
field->changes() | rpl::to_empty,
|
||||
field->shownValue() | rpl::to_empty
|
||||
) | rpl::on_next([=] {
|
||||
updateVisibility();
|
||||
}, button->lifetime());
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
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
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class InputField;
|
||||
class Show;
|
||||
} // namespace Ui
|
||||
|
||||
namespace HistoryView::Controls {
|
||||
class ComposeAiButton;
|
||||
} // namespace HistoryView::Controls
|
||||
|
||||
namespace Ui {
|
||||
|
||||
[[nodiscard]] bool HasEnoughLinesForAi(
|
||||
not_null<Main::Session*> session,
|
||||
not_null<Ui::InputField*> field);
|
||||
|
||||
struct SetupCaptionAiButtonArgs {
|
||||
not_null<QWidget*> parent;
|
||||
not_null<Ui::InputField*> field;
|
||||
not_null<Main::Session*> session;
|
||||
std::shared_ptr<Ui::Show> show;
|
||||
};
|
||||
|
||||
[[nodiscard]] auto SetupCaptionAiButton(SetupCaptionAiButtonArgs &&args)
|
||||
-> not_null<HistoryView::Controls::ComposeAiButton*>;
|
||||
|
||||
void UpdateCaptionAiButtonGeometry(
|
||||
not_null<HistoryView::Controls::ComposeAiButton*> button,
|
||||
not_null<Ui::InputField*> field);
|
||||
|
||||
} // namespace Ui
|
||||
Reference in New Issue
Block a user