diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index ccd4d0536c..487a33007b 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/call_delayed.h" #include "boxes/premium_limits_box.h" #include "boxes/premium_preview_box.h" +#include "boxes/send_gif_with_caption_box.h" #include "boxes/send_credits_box.h" #include "ui/effects/scroll_content_shadow.h" #include "ui/widgets/fields/number_input.h" @@ -57,6 +58,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/stickers/data_stickers.h" #include "data/stickers/data_custom_emoji.h" #include "window/window_session_controller.h" +#include "window/window_controller.h" #include "core/application.h" #include "core/core_settings.h" #include "styles/style_boxes.h" @@ -164,6 +166,58 @@ void RenameFileBox( }); } +void EditFileCaptionBox( + not_null box, + const style::ComposeControls &st, + PeerData *captionToPeer, + TextWithTags currentCaption, + Fn apply) { + box->setTitle(tr::lng_context_upload_edit_caption()); + const auto wrap = box->addRow( + object_ptr(box), + st::boxRowPadding); + const auto field = Ui::CreateChild( + wrap, + st.files.caption, + Ui::InputField::Mode::MultiLine, + tr::lng_photo_caption()); + field->setMaxLength(kMaxMessageLength); + field->setSubmitSettings(Core::App().settings().sendSubmitWay()); + Ui::ResizeFitChild(wrap, field); + if (const auto window = Core::App().findWindow(box)) { + const auto controller = window->sessionController(); + Ui::SetupCaptionFieldInBox( + box, + controller, + field, + captionToPeer, + [=](not_null emoji) { + return captionToPeer + && Data::AllowEmojiWithoutPremium(captionToPeer, emoji); + }, + PremiumFeature::EmojiStatus); + } + field->setTextWithTags(std::move(currentCaption)); + + box->setFocusCallback([=] { + field->setFocusFast(); + }); + const auto save = [=] { + const auto text = field->getTextWithAppliedMarkdown(); + if (!apply(text)) { + return; + } + box->closeBox(); + }; + field->submits() | rpl::on_next([=] { + save(); + }, box->lifetime()); + box->addButton(tr::lng_settings_save(), save); + box->addButton(tr::lng_cancel(), [=] { + box->closeBox(); + }); +} + void EditPriceBox( not_null box, not_null session, @@ -1449,23 +1503,80 @@ void SendFilesBox::pushBlock(int from, int till) { if (from >= till || from >= _list.files.size()) { return base::EventFilterResult::Continue; } - const auto fileIndex = from; + auto fileIndex = from; + if (const auto album = dynamic_cast(widget)) { + const auto indexInBlock = album->indexFromPoint(mouse->pos()); + if (indexInBlock < 0) { + return base::EventFilterResult::Continue; + } + fileIndex += indexInBlock; + } + if (fileIndex >= till || fileIndex >= _list.files.size()) { + return base::EventFilterResult::Continue; + } state->menu = base::make_unique_q( widget, _st.tabbed.menu); - state->menu->addAction(tr::lng_rename_file(tr::now), [=] { - auto &file = _list.files[fileIndex]; - _show->show(Box(RenameFileBox, file.displayName, [=]( - QString newName) { - const auto displayName = std::move(newName); - _list.files[fileIndex].displayName = displayName; - if (!setDisplayNameInSingleFilePreview( - fileIndex, - displayName)) { - refreshAllAfterChanges(from); - } - })); - }, &st::menuIconEdit); + const auto &file = _list.files[fileIndex]; + const auto canEditFileData + = !_sendWay.current().sendImagesAsPhotos() + || (file.type != Ui::PreparedFile::Type::Photo + && file.type != Ui::PreparedFile::Type::Video); + if (canEditFileData) { + state->menu->addAction(tr::lng_rename_file(tr::now), [=] { + auto &file = _list.files[fileIndex]; + _show->show(Box(RenameFileBox, file.displayName, [=]( + QString newName) { + const auto displayName = std::move(newName); + _list.files[fileIndex].displayName = displayName; + if (!setDisplayNameInSingleFilePreview( + fileIndex, + displayName)) { + refreshAllAfterChanges(from); + } + })); + }, &st::menuIconEdit); + state->menu->addAction( + tr::lng_context_upload_edit_caption(tr::now), + [=] { + auto &file = _list.files[fileIndex]; + _show->show(Box( + EditFileCaptionBox, + _st, + _captionToPeer, + file.caption, + [=](TextWithTags text) { + if (!validateSingleCaptionLength(text.text)) { + return false; + } + auto updated = text; + const auto syncMainCaption = (fileIndex == 0) + && _caption + && !_caption->isHidden() + && mainCaptionWillBeAttached(); + if (fileIndex == 0) { + _mainCaptionAttachedToFirstFile = false; + _firstFileCaptionBackup = text; + } + _list.files[fileIndex].caption + = std::move(text); + if (syncMainCaption) { + _caption->setTextWithTags(updated); + } + if (!setCaptionInSingleFilePreview( + fileIndex, + updated)) { + refreshAllAfterChanges(from); + } + return true; + })); + }, + &st::menuIconCaptionShow); + } + if (state->menu->empty()) { + state->menu = nullptr; + return base::EventFilterResult::Continue; + } state->menu->popup(mouse->globalPos()); return base::EventFilterResult::Cancel; } diff --git a/Telegram/SourceFiles/boxes/send_gif_with_caption_box.cpp b/Telegram/SourceFiles/boxes/send_gif_with_caption_box.cpp index 33635b45ba..3c4a6ca823 100644 --- a/Telegram/SourceFiles/boxes/send_gif_with_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/send_gif_with_caption_box.cpp @@ -53,6 +53,89 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_menu_icons.h" namespace Ui { + +void SetupCaptionFieldInBox( + not_null box, + not_null controller, + not_null field, + PeerData *panelPeer, + Fn)> allowWithoutPremium, + PremiumFeature premiumFeature) { + using Limit = HistoryView::Controls::CharactersLimitLabel; + struct State final { + base::unique_qptr emojiPanel; + base::unique_qptr charsLimitation; + }; + const auto state = box->lifetime().make_state(); + const auto container = box->getDelegate()->outerContainer(); + using Selector = ChatHelpers::TabbedSelector; + state->emojiPanel = base::make_unique_q( + container, + controller, + object_ptr( + nullptr, + controller->uiShow(), + Window::GifPauseReason::Layer, + Selector::Mode::EmojiOnly)); + const auto emojiPanel = state->emojiPanel.get(); + emojiPanel->setDesiredHeightValues( + 1., + st::emojiPanMinHeight / 2, + st::emojiPanMinHeight); + emojiPanel->hide(); + emojiPanel->selector()->setCurrentPeer( + panelPeer ? panelPeer : controller->session().user()); + emojiPanel->selector()->emojiChosen( + ) | rpl::on_next([=](ChatHelpers::EmojiChosen data) { + Ui::InsertEmojiAtCursor(field->textCursor(), data.emoji); + }, field->lifetime()); + emojiPanel->selector()->customEmojiChosen( + ) | rpl::on_next([=](ChatHelpers::FileChosen data) { + const auto info = data.document->sticker(); + if (info + && info->setType == Data::StickersType::Emoji + && !allowWithoutPremium(data.document) + && !controller->session().premium()) { + ShowPremiumPreviewBox(controller, premiumFeature); + } else { + Data::InsertCustomEmoji(field, data.document); + } + }, field->lifetime()); + + const auto emojiButton = Ui::AddEmojiToggleToField( + field, + box, + controller, + emojiPanel, + st::sendGifWithCaptionEmojiPosition); + emojiButton->show(); + + const auto session = &controller->session(); + const auto checkCharsLimitation = [=](auto repeat) -> void { + const auto remove = Ui::ComputeFieldCharacterCount(field) + - Data::PremiumLimits(session).captionLengthCurrent(); + if (remove > 0) { + if (!state->charsLimitation) { + state->charsLimitation = base::make_unique_q( + field, + emojiButton, + style::al_top); + state->charsLimitation->show(); + Data::AmPremiumValue(session) | rpl::on_next([=] { + repeat(repeat); + }, state->charsLimitation->lifetime()); + } + state->charsLimitation->setLeft(remove); + state->charsLimitation->show(); + } else { + state->charsLimitation = nullptr; + } + }; + field->changes() | rpl::on_next([=] { + checkCharsLimitation(checkCharsLimitation); + }, field->lifetime()); +} + namespace { struct State final { @@ -205,8 +288,6 @@ struct State final { [[nodiscard]] not_null AddInputField( not_null box, not_null controller) { - using Limit = HistoryView::Controls::CharactersLimitLabel; - const auto bottomContainer = box->setPinnedToBottomContent( object_ptr(box)); const auto wrap = bottomContainer->add( @@ -218,83 +299,15 @@ struct State final { Ui::InputField::Mode::MultiLine, tr::lng_photo_caption()); Ui::ResizeFitChild(wrap, input); - - struct State final { - base::unique_qptr emojiPanel; - base::unique_qptr charsLimitation; - }; - const auto state = box->lifetime().make_state(); - - { - const auto container = box->getDelegate()->outerContainer(); - using Selector = ChatHelpers::TabbedSelector; - state->emojiPanel = base::make_unique_q( - container, - controller, - object_ptr( - nullptr, - controller->uiShow(), - Window::GifPauseReason::Layer, - Selector::Mode::EmojiOnly)); - const auto emojiPanel = state->emojiPanel.get(); - emojiPanel->setDesiredHeightValues( - 1., - st::emojiPanMinHeight / 2, - st::emojiPanMinHeight); - emojiPanel->hide(); - emojiPanel->selector()->setCurrentPeer(controller->session().user()); - emojiPanel->selector()->emojiChosen( - ) | rpl::on_next([=](ChatHelpers::EmojiChosen data) { - Ui::InsertEmojiAtCursor(input->textCursor(), data.emoji); - }, input->lifetime()); - emojiPanel->selector()->customEmojiChosen( - ) | rpl::on_next([=](ChatHelpers::FileChosen data) { - const auto info = data.document->sticker(); - if (info - && info->setType == Data::StickersType::Emoji - && !controller->session().premium()) { - ShowPremiumPreviewBox( - controller, - PremiumFeature::AnimatedEmoji); - } else { - Data::InsertCustomEmoji(input, data.document); - } - }, input->lifetime()); - } - - const auto emojiButton = Ui::AddEmojiToggleToField( - input, + SetupCaptionFieldInBox( box, controller, - state->emojiPanel.get(), - st::sendGifWithCaptionEmojiPosition); - emojiButton->show(); - - const auto session = &controller->session(); - const auto checkCharsLimitation = [=](auto repeat) -> void { - const auto remove = Ui::ComputeFieldCharacterCount(input) - - Data::PremiumLimits(session).captionLengthCurrent(); - if (remove > 0) { - if (!state->charsLimitation) { - state->charsLimitation = base::make_unique_q( - input, - emojiButton, - style::al_top); - state->charsLimitation->show(); - Data::AmPremiumValue(session) | rpl::on_next([=] { - repeat(repeat); - }, state->charsLimitation->lifetime()); - } - state->charsLimitation->setLeft(remove); - state->charsLimitation->show(); - } else { - state->charsLimitation = nullptr; - } - }; - - input->changes() | rpl::on_next([=] { - checkCharsLimitation(checkCharsLimitation); - }, input->lifetime()); + input, + controller->session().user(), + [](not_null) { + return false; + }, + PremiumFeature::AnimatedEmoji); return input; } diff --git a/Telegram/SourceFiles/boxes/send_gif_with_caption_box.h b/Telegram/SourceFiles/boxes/send_gif_with_caption_box.h index 1730c86714..db3c68ac14 100644 --- a/Telegram/SourceFiles/boxes/send_gif_with_caption_box.h +++ b/Telegram/SourceFiles/boxes/send_gif_with_caption_box.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class PeerData; class DocumentData; +enum class PremiumFeature; namespace Api { struct SendOptions; @@ -22,9 +23,22 @@ namespace HistoryView { class Element; } // namespace HistoryView +namespace Window { +class SessionController; +} // namespace Window + namespace Ui { class GenericBox; +class InputField; + +void SetupCaptionFieldInBox( + not_null box, + not_null controller, + not_null field, + PeerData *panelPeer, + Fn)> allowWithoutPremium, + PremiumFeature premiumFeature); void EditCaptionBox( not_null box,