diff --git a/Telegram/Resources/icons/menu/spoiler.png b/Telegram/Resources/icons/menu/spoiler.png new file mode 100644 index 000000000..a8c47bdca Binary files /dev/null and b/Telegram/Resources/icons/menu/spoiler.png differ diff --git a/Telegram/Resources/icons/menu/spoiler@2x.png b/Telegram/Resources/icons/menu/spoiler@2x.png new file mode 100644 index 000000000..97f644192 Binary files /dev/null and b/Telegram/Resources/icons/menu/spoiler@2x.png differ diff --git a/Telegram/Resources/icons/menu/spoiler@3x.png b/Telegram/Resources/icons/menu/spoiler@3x.png new file mode 100644 index 000000000..0963b5076 Binary files /dev/null and b/Telegram/Resources/icons/menu/spoiler@3x.png differ diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 6e8a7e5ae..3efc57af7 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2344,17 +2344,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_send_image_empty" = "Could not send an empty file: {name}"; "lng_send_images_selected#one" = "{count} image selected"; "lng_send_images_selected#other" = "{count} images selected"; -"lng_send_photos#one" = "Send {count} photo"; -"lng_send_photos#other" = "Send {count} photos"; -"lng_send_separate_photos" = "Send as separate photos"; -"lng_send_separate_photos_videos" = "Send as separate media"; "lng_send_files_selected#one" = "{count} file selected"; "lng_send_files_selected#other" = "{count} files selected"; -"lng_send_files#one" = "Send {count} file"; -"lng_send_files#other" = "Send {count} files"; "lng_send_grouped" = "Group items"; +"lng_send_compressed_one" = "Compress the image"; "lng_send_compressed" = "Compress images"; "lng_send_media_invalid_files" = "Sorry, no valid files found."; +"lng_send_image" = "Send an image"; +"lng_send_file" = "Send a file"; +"lng_send_video" = "Send a video file"; "lng_forward_choose" = "Choose recipient..."; "lng_forward_cant" = "Sorry, no way to forward here :("; diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp index f712506cc..37f4780ca 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp @@ -319,7 +319,7 @@ void EditCaptionBox::setupControls() { this, object_ptr( this, - tr::lng_send_compressed(tr::now), + tr::lng_send_compressed_one(tr::now), true, st::defaultBoxCheckbox), st::editMediaCheckboxMargins) diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index e47fe9083..3805176c0 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" #include "ui/widgets/scroll_area.h" +#include "ui/widgets/popup_menu.h" #include "ui/wrap/vertical_layout.h" #include "ui/chat/attach/attach_prepare.h" #include "ui/chat/attach/attach_send_files_way.h" @@ -62,6 +63,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_layers.h" #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" +#include "styles/style_info.h" +#include "styles/style_menu_icons.h" #include @@ -227,6 +230,17 @@ void SendFilesBox::Block::setSendWay(Ui::SendFilesWay way) { album->setSendWay(way); } +void SendFilesBox::Block::toggleSpoilers(bool enabled) { + if (_isAlbum) { + const auto album = static_cast(_preview.get()); + album->toggleSpoilers(enabled); + } else if (_isSingleMedia) { + const auto media = static_cast( + _preview.get()); + media->setSpoiler(enabled); + } +} + void SendFilesBox::Block::applyChanges() { if (!_isAlbum) { if (_isSingleMedia) { @@ -297,7 +311,7 @@ SendFilesBox::SendFilesBox( void SendFilesBox::initPreview() { using namespace rpl::mappers; - refreshControls(); + refreshControls(true); updateBoxSize(); @@ -345,19 +359,6 @@ void SendFilesBox::enqueueNextPrepare() { } void SendFilesBox::prepare() { - _send = addButton( - (_sendType == Api::SendType::Normal - ? tr::lng_send_button() - : tr::lng_create_group_next()), - [=] { send({}); }); - if (_sendType == Api::SendType::Normal) { - SendMenu::SetupMenuAndShortcuts( - _send, - [=] { return _sendMenuType; }, - [=] { sendSilent(); }, - [=] { sendScheduled(); }); - } - addButton(tr::lng_cancel(), [=] { closeBox(); }); initSendWay(); setupCaption(); setupSendWayControls(); @@ -371,11 +372,6 @@ void SendFilesBox::prepare() { } }, lifetime()); - _addFile = addLeftButton( - tr::lng_stickers_featured_add(), - base::fn_delayed(st::historyAttach.ripple.hideDuration, this, [=] { - openDialogToAddFileToAlbum(); - })); setupDragArea(); } @@ -457,6 +453,103 @@ void SendFilesBox::openDialogToAddFileToAlbum() { crl::guard(this, callback)); } +void SendFilesBox::refreshButtons() { + clearButtons(); + + _send = addButton( + (_sendType == Api::SendType::Normal + ? tr::lng_send_button() + : tr::lng_create_group_next()), + [=] { send({}); }); + if (_sendType == Api::SendType::Normal) { + SendMenu::SetupMenuAndShortcuts( + _send, + [=] { return _sendMenuType; }, + [=] { sendSilent(); }, + [=] { sendScheduled(); }); + } + addButton(tr::lng_cancel(), [=] { closeBox(); }); + _addFile = addLeftButton( + tr::lng_stickers_featured_add(), + base::fn_delayed(st::historyAttach.ripple.hideDuration, this, [=] { + openDialogToAddFileToAlbum(); + })); + + addMenuButton(); +} + +bool SendFilesBox::hasSendMenu() const { + return (_sendMenuType != SendMenu::Type::Disabled); +} + +bool SendFilesBox::hasSpoilerMenu() const { + const auto allAreVideo = !ranges::any_of(_list.files, [](const auto &f) { + using Type = Ui::PreparedFile::Type; + return (f.type != Type::Video); + }); + const auto allAreMedia = !ranges::any_of(_list.files, [](const auto &f) { + using Type = Ui::PreparedFile::Type; + return (f.type != Type::Photo) && (f.type != Type::Video); + }); + return allAreVideo + || (allAreMedia && _sendWay.current().sendImagesAsPhotos()); +} + +void SendFilesBox::applyBlockChanges() { + for (auto &block : _blocks) { + block.applyChanges(); + } +} + +bool SendFilesBox::allWithSpoilers() { + applyBlockChanges(); + return ranges::all_of(_list.files, &Ui::PreparedFile::spoiler); +} + +void SendFilesBox::toggleSpoilers(bool enabled) { + for (auto &file : _list.files) { + file.spoiler = enabled; + } + for (auto &block : _blocks) { + block.toggleSpoilers(enabled); + } +} + +void SendFilesBox::addMenuButton() { + if (!hasSendMenu() && !hasSpoilerMenu()) { + return; + } + + const auto top = addTopButton(st::infoTopBarMenu); + top->setClickedCallback([=] { + _menu = base::make_unique_q( + top, + st::popupMenuExpandedSeparator); + if (hasSpoilerMenu()) { + const auto spoilered = allWithSpoilers(); + _menu->addAction( + (spoilered + ? tr::lng_context_disable_spoiler(tr::now) + : tr::lng_context_spoiler_effect(tr::now)), + [=] { toggleSpoilers(!spoilered); }, + (spoilered ? &st::menuIconDisable : &st::menuIconSpoiler)); + if (hasSendMenu()) { + _menu->addSeparator(); + } + } + if (hasSendMenu()) { + SendMenu::FillSendMenu( + _menu.get(), + _sendMenuType, + [=] { sendSilent(); }, + [=] { sendScheduled(); }); + } + _menu->popup(QCursor::pos()); + return true; + }); + +} + void SendFilesBox::initSendWay() { _sendWay = [&] { auto result = Core::App().settings().sendFilesWay(); @@ -480,6 +573,9 @@ void SendFilesBox::initSendWay() { for (auto &block : _blocks) { block.setSendWay(value); } + if (!hasSendMenu()) { + refreshButtons(); + } setInnerFocus(); }, lifetime()); } @@ -650,9 +746,12 @@ void SendFilesBox::pushBlock(int from, int till) { }, widget->lifetime()); } -void SendFilesBox::refreshControls() { +void SendFilesBox::refreshControls(bool initial) { + if (initial || !hasSendMenu()) { + refreshButtons(); + } refreshTitleText(); - updateSendWayControlsVisibility(); + updateSendWayControls(); updateCaptionPlaceholder(); } @@ -711,11 +810,14 @@ void SendFilesBox::setupSendWayControls() { st::editMediaHintLabel); } -void SendFilesBox::updateSendWayControlsVisibility() { +void SendFilesBox::updateSendWayControls() { const auto onlyOne = (_sendLimit == SendLimit::One); _groupFiles->setVisible(_list.hasGroupOption(onlyOne)); _sendImagesAsPhotos->setVisible( _list.hasSendImagesAsPhotosOption(onlyOne)); + _sendImagesAsPhotos->setText((_list.files.size() > 1) + ? tr::lng_send_compressed(tr::now) + : tr::lng_send_compressed_one(tr::now)); _hintLabel->setVisible( _controller->session().settings().photoEditorHintShown() @@ -933,20 +1035,27 @@ void SendFilesBox::addFile(Ui::PreparedFile &&file) { } void SendFilesBox::refreshTitleText() { + using Type = Ui::PreparedFile::Type; const auto count = int(_list.files.size()); if (count > 1) { const auto imagesCount = ranges::count( _list.files, - Ui::PreparedFile::Type::Photo, + Type::Photo, &Ui::PreparedFile::type); _titleText = (imagesCount == count) ? tr::lng_send_images_selected(tr::now, lt_count, count) : tr::lng_send_files_selected(tr::now, lt_count, count); - _titleHeight = st::boxTitleHeight; } else { - _titleText = QString(); - _titleHeight = count ? st::boxPhotoPadding.top() : 0; + const auto type = _list.files.empty() + ? Type::None + : _list.files.front().type; + _titleText = (type == Type::Photo) + ? tr::lng_send_image(tr::now) + : (type == Type::Video) + ? tr::lng_send_video(tr::now) + : tr::lng_send_file(tr::now); } + _titleHeight = st::boxTitleHeight; } void SendFilesBox::updateBoxSize() { @@ -1102,9 +1211,7 @@ void SendFilesBox::send( for (auto &item : _list.files) { item.spoiler = false; } - for (auto &block : _blocks) { - block.applyChanges(); - } + applyBlockChanges(); Storage::ApplyModifications(_list); diff --git a/Telegram/SourceFiles/boxes/send_files_box.h b/Telegram/SourceFiles/boxes/send_files_box.h index 480b946a3..63e05fe47 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.h +++ b/Telegram/SourceFiles/boxes/send_files_box.h @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/abstract_box.h" #include "ui/chat/attach/attach_prepare.h" #include "ui/chat/attach/attach_send_files_way.h" +#include "ui/widgets/popup_menu.h" #include "storage/localimageloader.h" #include "storage/storage_media_prepare.h" @@ -36,6 +37,7 @@ class EmojiButton; class AlbumPreview; class VerticalLayout; class FlatLabel; +class PopupMenu; } // namespace Ui namespace Window { @@ -106,6 +108,7 @@ private: [[nodiscard]] rpl::producer itemModifyRequest() const; void setSendWay(Ui::SendFilesWay way); + void toggleSpoilers(bool enabled); void applyChanges(); private: @@ -117,16 +120,24 @@ private: bool _isSingleMedia = false; }; + void initSendWay(); void initPreview(); + [[nodiscard]] bool hasSendMenu() const; + [[nodiscard]] bool hasSpoilerMenu() const; + [[nodiscard]] bool allWithSpoilers(); + void addMenuButton(); + void applyBlockChanges(); + void toggleSpoilers(bool enabled); bool validateLength(const QString &text) const; - void refreshControls(); + void refreshButtons(); + void refreshControls(bool initial = false); void setupSendWayControls(); void setupCaption(); void setupEmojiPanel(); - void updateSendWayControlsVisibility(); + void updateSendWayControls(); void updateEmojiPanelGeometry(); void emojiFilterForGeometry(not_null event); @@ -200,6 +211,8 @@ private: Fn _whenReadySend; bool _preparing = false; + base::unique_qptr _menu; + QPointer _send; QPointer _addFile; diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp index 64cc29718..c905035c1 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp @@ -264,11 +264,12 @@ void AbstractSingleMediaPreview::showContextMenu(QPoint position) { this, st::popupMenuWithIcons); - _menu->addAction(hasSpoiler() + const auto spoilered = hasSpoiler(); + _menu->addAction(spoilered ? tr::lng_context_disable_spoiler(tr::now) : tr::lng_context_spoiler_effect(tr::now), [=] { - setSpoiler(!hasSpoiler()); - }, &st::menuIconCopy); + setSpoiler(!spoilered); + }, spoilered ? &st::menuIconDisable : &st::menuIconSpoiler); if (_menu->empty()) { _menu = nullptr; diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp index 8acd66726..00f7eba62 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp @@ -81,6 +81,12 @@ bool AlbumPreview::canHaveSpoiler(int index) const { return _sendWay.sendImagesAsPhotos(); } +void AlbumPreview::toggleSpoilers(bool enabled) { + for (auto &thumb : _thumbs) { + thumb->setSpoiler(enabled); + } +} + std::vector AlbumPreview::takeOrder() { //Expects(_thumbs.size() == _order.size()); //Expects(_itemsShownDimensions.size() == _order.size()); @@ -582,11 +588,12 @@ void AlbumPreview::showContextMenu( this, st::popupMenuWithIcons); - _menu->addAction(thumb->hasSpoiler() + const auto spoilered = thumb->hasSpoiler(); + _menu->addAction(spoilered ? tr::lng_context_disable_spoiler(tr::now) : tr::lng_context_spoiler_effect(tr::now), [=] { - thumb->setSpoiler(!thumb->hasSpoiler()); - }, &st::menuIconCopy); + thumb->setSpoiler(!spoilered); + }, spoilered ? &st::menuIconDisable : &st::menuIconSpoiler); if (_menu->empty()) { _menu = nullptr; diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.h b/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.h index 4732ad33c..ccb64970e 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.h +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.h @@ -30,6 +30,7 @@ public: [[nodiscard]] base::flat_set collectSpoileredIndices(); [[nodiscard]] bool canHaveSpoiler(int index) const; + void toggleSpoilers(bool enabled); [[nodiscard]] std::vector takeOrder(); [[nodiscard]] rpl::producer thumbDeleted() const { diff --git a/Telegram/SourceFiles/ui/menu_icons.style b/Telegram/SourceFiles/ui/menu_icons.style index 6d26f8011..373f59886 100644 --- a/Telegram/SourceFiles/ui/menu_icons.style +++ b/Telegram/SourceFiles/ui/menu_icons.style @@ -94,6 +94,8 @@ menuIconStartStreamWith: icon {{ "menu/start_stream_with", menuIconColor }}; menuIconVideoChat: icon {{ "menu/video_chat", menuIconColor }}; menuIconTranslate: icon {{ "menu/translate", menuIconColor }}; menuIconReportAntiSpam: icon {{ "menu/false_positive", menuIconColor }}; +menuIconSpoiler: icon {{ "menu/spoiler", menuIconColor }}; +menuIconDisable: icon {{ "menu/disable", menuIconColor }}; menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }}; menuIconTTLAnyTextPosition: point(11px, 22px);