diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index b8765cd634..ac17eb8a56 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -676,8 +676,6 @@ PRIVATE history/view/controls/history_view_ttl_button.h history/view/controls/history_view_voice_record_bar.cpp history/view/controls/history_view_voice_record_bar.h - history/view/controls/history_view_voice_record_button.cpp - history/view/controls/history_view_voice_record_button.h history/view/controls/history_view_webpage_processor.cpp history/view/controls/history_view_webpage_processor.h history/view/media/history_view_call.cpp diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index 14af862530..135b895ed4 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -1071,6 +1071,13 @@ historyMessagesTTLLabel: FlatLabel(defaultFlatLabel) { textFg: windowSubTextFg; } +historyCharsLimitationLabel: FlatLabel(defaultFlatLabel) { + // The same as a width of the historySendSize. + minWidth: 44px; + align: align(center); + textFg: attentionButtonFg; +} + historyRecordVoiceFg: historyComposeIconFg; historyRecordVoiceFgOver: historyComposeIconFgOver; historyRecordVoiceFgInactive: attentionButtonFg; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 5fa7a5a193..c713d464ae 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -71,6 +71,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_file_origin.h" #include "data/data_histories.h" #include "data/data_group_call.h" +#include "data/data_peer_values.h" // Data::AmPremiumValue. +#include "data/data_premium_limits.h" // Data::PremiumLimits. #include "data/stickers/data_stickers.h" #include "data/stickers/data_custom_emoji.h" #include "history/history.h" @@ -80,6 +82,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_inner_widget.h" #include "history/history_item_components.h" #include "history/history_unread_things.h" +#include "history/view/controls/history_view_characters_limit.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" @@ -1622,6 +1625,8 @@ void HistoryWidget::fieldChanged() { } }); + checkCharsLimitation(); + updateSendButtonType(); if (!HasSendText(_field)) { _fieldIsEmpty = true; @@ -3836,6 +3841,18 @@ void HistoryWidget::windowIsVisibleChanged() { }); } +TextWithEntities HistoryWidget::prepareTextForEditMsg() const { + const auto textWithTags = _field->getTextWithAppliedMarkdown(); + const auto prepareFlags = Ui::ItemTextOptions( + _history, + session().user()).flags; + auto left = TextWithEntities { + textWithTags.text, + TextUtilities::ConvertTextTagsToEntities(textWithTags.tags) }; + TextUtilities::PrepareForSending(left, prepareFlags); + return left; +} + void HistoryWidget::saveEditMsg() { Expects(_history != nullptr); @@ -3849,15 +3866,8 @@ void HistoryWidget::saveEditMsg() { return; } const auto webPageDraft = _preview->draft(); - const auto textWithTags = _field->getTextWithAppliedMarkdown(); - const auto prepareFlags = Ui::ItemTextOptions( - _history, - session().user()).flags; + auto left = prepareTextForEditMsg(); auto sending = TextWithEntities(); - auto left = TextWithEntities { - textWithTags.text, - TextUtilities::ConvertTextTagsToEntities(textWithTags.tags) }; - TextUtilities::PrepareForSending(left, prepareFlags); const auto media = item->media(); if (!TextUtilities::CutPart(sending, left, MaxMessageSize) @@ -7291,6 +7301,36 @@ void HistoryWidget::showPremiumToast(not_null document) { _stickerToast->showFor(document); } +void HistoryWidget::checkCharsLimitation() { + if (!_history || !_editMsgId) { + if (_charsLimitation) { + _charsLimitation = nullptr; + } + return; + } + const auto limits = Data::PremiumLimits(&session()); + const auto left = prepareTextForEditMsg(); + const auto remove = left.text.size() - limits.captionLengthCurrent(); + if (remove > 0) { + if (!_charsLimitation) { + _charsLimitation = base::make_unique_q( + this, + _send.get()); + _charsLimitation->show(); + Data::AmPremiumValue( + &session() + ) | rpl::start_with_next([=] { + checkCharsLimitation(); + }, _charsLimitation->lifetime()); + } + _charsLimitation->setLeft(remove); + } else { + if (_charsLimitation) { + _charsLimitation = nullptr; + } + } +} + void HistoryWidget::setFieldText( const TextWithTags &textWithTags, TextUpdateEvents events, @@ -7303,6 +7343,8 @@ void HistoryWidget::setFieldText( _textUpdateEvents = TextUpdateEvent::SaveDraft | TextUpdateEvent::SendTyping; + checkCharsLimitation(); + if (_preview) { _preview->checkNow(false); } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 3fa34ac2be..e4ec63ea2a 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -101,6 +101,7 @@ class VoiceRecordBar; class ForwardPanel; class TTLButton; class WebpageProcessor; +class CharactersLimitLabel; } // namespace HistoryView::Controls class BotKeyboard; @@ -543,6 +544,7 @@ private: [[nodiscard]] bool insideJumpToEndInsteadOfToUnread() const; void createUnreadBarAndResize(); + [[nodiscard]] TextWithEntities prepareTextForEditMsg() const; void saveEditMsg(); void setupPreview(); @@ -643,6 +645,8 @@ private: void switchToSearch(QString query); + void checkCharsLimitation(); + MTP::Sender _api; FullReplyTo _replyTo; Ui::Text::String _replyToName; @@ -763,6 +767,8 @@ private: object_ptr _field; base::unique_qptr _fieldDisabled; base::unique_qptr _sendRestriction; + using CharactersLimitLabel = HistoryView::Controls::CharactersLimitLabel; + base::unique_qptr _charsLimitation; QString _sendRestrictionKey; Ui::Animations::Simple _inPhotoEditOver; bool _inDetails = false; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_characters_limit.cpp b/Telegram/SourceFiles/history/view/controls/history_view_characters_limit.cpp new file mode 100644 index 0000000000..8fa5621c68 --- /dev/null +++ b/Telegram/SourceFiles/history/view/controls/history_view_characters_limit.cpp @@ -0,0 +1,35 @@ +/* +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_characters_limit.h" + +#include "styles/style_chat_helpers.h" + +namespace HistoryView::Controls { + +CharactersLimitLabel::CharactersLimitLabel( + not_null parent, + not_null widgetBelow) +: Ui::FlatLabel(parent, st::historyCharsLimitationLabel) { + rpl::combine( + Ui::RpWidget::heightValue(), + widgetBelow->positionValue() + ) | rpl::start_with_next([=](int height, const QPoint &p) { + move(p.x(), p.y() - height); + }, lifetime()); +} + +void CharactersLimitLabel::setLeft(int value) { + if (value <= 0) { + return; + } + constexpr auto kMinus = QChar(0x2212); + constexpr auto kLimit = int(999); + Ui::FlatLabel::setText(kMinus + QString::number(std::min(value, kLimit))); +} + +} // namespace HistoryView::Controls diff --git a/Telegram/SourceFiles/history/view/controls/history_view_characters_limit.h b/Telegram/SourceFiles/history/view/controls/history_view_characters_limit.h new file mode 100644 index 0000000000..b16b6bfa18 --- /dev/null +++ b/Telegram/SourceFiles/history/view/controls/history_view_characters_limit.h @@ -0,0 +1,24 @@ +/* +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 "ui/widgets/labels.h" + +namespace HistoryView::Controls { + +class CharactersLimitLabel final : public Ui::FlatLabel { +public: + CharactersLimitLabel( + not_null parent, + not_null widgetBelow); + + void setLeft(int value); + +}; + +} // namespace HistoryView::Controls 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 ada3c72954..9122d06743 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_forum_topic.h" #include "data/data_peer_values.h" #include "data/data_photo_media.h" +#include "data/data_premium_limits.h" // Data::PremiumLimits. #include "data/stickers/data_stickers.h" #include "data/stickers/data_custom_emoji.h" #include "data/data_web_page.h" @@ -47,6 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/power_saving.h" #include "history/history.h" #include "history/history_item.h" +#include "history/view/controls/history_view_characters_limit.h" #include "history/view/controls/history_view_forward_panel.h" #include "history/view/controls/history_view_draft_options.h" #include "history/view/controls/history_view_voice_record_bar.h" @@ -63,6 +65,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/audio/media_audio_capture.h" #include "media/audio/media_audio.h" #include "settings/settings_premium.h" +#include "ui/item_text_options.h" #include "ui/text/text_options.h" #include "ui/text/text_utilities.h" #include "ui/ui_utility.h" @@ -1205,6 +1208,8 @@ void ComposeControls::setFieldText( _textUpdateEvents = TextUpdateEvent::SaveDraft | TextUpdateEvent::SendTyping; + checkCharsLimitation(); + if (_preview) { _preview->checkNow(false); } @@ -1788,6 +1793,8 @@ void ComposeControls::fieldChanged() { } }); + checkCharsLimitation(); + _saveCloudDraftTimer.cancel(); if (!(_textUpdateEvents & TextUpdateEvent::SaveDraft)) { return; @@ -2021,6 +2028,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) { _preview->setDisabled(false); } } + checkCharsLimitation(); } void ComposeControls::cancelForward() { @@ -3284,4 +3292,50 @@ Fn ComposeControls::restoreTextCallback( }); } +TextWithEntities ComposeControls::prepareTextForEditMsg() const { + if (!_history) { + return {}; + } + const auto textWithTags = getTextWithAppliedMarkdown(); + const auto prepareFlags = Ui::ItemTextOptions( + _history, + session().user()).flags; + auto left = TextWithEntities { + textWithTags.text, + TextUtilities::ConvertTextTagsToEntities(textWithTags.tags) }; + TextUtilities::PrepareForSending(left, prepareFlags); + return left; +} + +void ComposeControls::checkCharsLimitation() { + if (!_history || !isEditingMessage()) { + if (_charsLimitation) { + _charsLimitation = nullptr; + } + return; + } + const auto limits = Data::PremiumLimits(&session()); + const auto left = prepareTextForEditMsg(); + const auto remove = left.text.size() - limits.captionLengthCurrent(); + if (remove > 0) { + if (!_charsLimitation) { + using namespace Controls; + _charsLimitation = base::make_unique_q( + _wrap.get(), + _send.get()); + _charsLimitation->show(); + Data::AmPremiumValue( + &session() + ) | rpl::start_with_next([=] { + checkCharsLimitation(); + }, _charsLimitation->lifetime()); + } + _charsLimitation->setLeft(remove); + } else { + if (_charsLimitation) { + _charsLimitation = nullptr; + } + } +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h index 795e25760a..4911bfde9c 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -83,6 +83,7 @@ namespace HistoryView::Controls { class VoiceRecordBar; class TTLButton; class WebpageProcessor; +class CharactersLimitLabel; } // namespace HistoryView::Controls namespace HistoryView { @@ -228,6 +229,8 @@ public: [[nodiscard]] rpl::producer fieldMenuShownValue() const; [[nodiscard]] not_null likeAnimationTarget() const; + [[nodiscard]] TextWithEntities prepareTextForEditMsg() const; + void applyCloudDraft(); void applyDraft( FieldHistoryAction fieldHistoryAction = FieldHistoryAction::Clear); @@ -334,6 +337,8 @@ private: void registerDraftSource(); void changeFocusedControl(); + void checkCharsLimitation(); + const style::ComposeControls &_st; const ChatHelpers::ComposeFeatures _features; const not_null _parent; @@ -373,6 +378,7 @@ private: std::unique_ptr _sendAs; std::unique_ptr _silent; std::unique_ptr _ttlInfo; + base::unique_qptr _charsLimitation; std::unique_ptr _inlineResults; std::unique_ptr _tabbedPanel; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index a244437ffc..25e1749240 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -1229,16 +1229,9 @@ void RepliesWidget::edit( if (*saveEditMsgRequestId) { return; } - const auto textWithTags = _composeControls->getTextWithAppliedMarkdown(); const auto webpage = _composeControls->webPageDraft(); - const auto prepareFlags = Ui::ItemTextOptions( - _history, - session().user()).flags; auto sending = TextWithEntities(); - auto left = TextWithEntities { - textWithTags.text, - TextUtilities::ConvertTextTagsToEntities(textWithTags.tags) }; - TextUtilities::PrepareForSending(left, prepareFlags); + auto left = _composeControls->prepareTextForEditMsg(); if (!TextUtilities::CutPart(sending, left, MaxMessageSize) && (!item diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index ca81ba290c..8c83ef478f 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -649,16 +649,9 @@ void ScheduledWidget::edit( if (*saveEditMsgRequestId) { return; } - const auto textWithTags = _composeControls->getTextWithAppliedMarkdown(); const auto webpage = _composeControls->webPageDraft(); - const auto prepareFlags = Ui::ItemTextOptions( - _history, - session().user()).flags; auto sending = TextWithEntities(); - auto left = TextWithEntities { - textWithTags.text, - TextUtilities::ConvertTextTagsToEntities(textWithTags.tags) }; - TextUtilities::PrepareForSending(left, prepareFlags); + auto left = _composeControls->prepareTextForEditMsg(); if (!TextUtilities::CutPart(sending, left, MaxMessageSize) && (!item diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index 53db41bc69..817f3c9aba 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -100,6 +100,10 @@ PRIVATE history/history_view_top_toast.cpp history/history_view_top_toast.h + history/view/controls/history_view_characters_limit.cpp + history/view/controls/history_view_characters_limit.h + history/view/controls/history_view_voice_record_button.cpp + history/view/controls/history_view_voice_record_button.h info/profile/info_profile_icon.cpp info/profile/info_profile_icon.h