Added ability to edit media with spoiled one without resending.

This commit is contained in:
23rd 2024-05-07 17:47:52 +03:00
parent 923e3ee808
commit 334fd4e951
15 changed files with 285 additions and 22 deletions

View File

@ -688,6 +688,8 @@ PRIVATE
history/view/controls/compose_controls_common.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
history/view/controls/history_view_compose_media_edit_manager.h
history/view/controls/history_view_compose_search.cpp
history/view/controls/history_view_compose_search.h
history/view/controls/history_view_draft_options.cpp

View File

@ -252,12 +252,47 @@ mtpRequestId EditTextMessage(
Data::WebPageDraft webpage,
SendOptions options,
Fn<void(mtpRequestId requestId)> done,
Fn<void(const QString &, mtpRequestId requestId)> fail) {
Fn<void(const QString &error, mtpRequestId requestId)> fail,
std::optional<bool> spoilerMediaOverride) {
const auto callback = [=](Fn<void()> applyUpdates, mtpRequestId id) {
applyUpdates();
done(id);
};
return EditMessage(item, caption, webpage, options, callback, fail);
auto inputMedia = std::optional<MTPInputMedia>();
if (spoilerMediaOverride) {
const auto spoiler = *spoilerMediaOverride;
if (const auto media = item->media()) {
if (const auto photo = media->photo()) {
using Flag = MTPDinputMediaPhoto::Flag;
const auto flags = Flag()
| (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag())
| (spoiler ? Flag::f_spoiler : Flag());
inputMedia = MTP_inputMediaPhoto(
MTP_flags(flags),
photo->mtpInput(),
MTP_int(media->ttlSeconds()));
} else if (const auto document = media->document()) {
using Flag = MTPDinputMediaDocument::Flag;
const auto flags = Flag()
| (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag())
| (spoiler ? Flag::f_spoiler : Flag());
inputMedia = MTP_inputMediaDocument(
MTP_flags(flags),
document->mtpInput(),
MTP_int(media->ttlSeconds()),
MTPstring()); // query
}
}
}
return EditMessage(
item,
caption,
webpage,
options,
callback,
fail,
inputMedia);
}
} // namespace Api

View File

@ -55,6 +55,7 @@ mtpRequestId EditTextMessage(
Data::WebPageDraft webpage,
SendOptions options,
Fn<void(mtpRequestId requestId)> done,
Fn<void(const QString &error, mtpRequestId requestId)> fail);
Fn<void(const QString &error, mtpRequestId requestId)> fail,
std::optional<bool> spoilerMediaOverride);
} // namespace Api

View File

@ -2656,6 +2656,7 @@ void HistoryWidget::setEditMsgId(MsgId msgId) {
unregisterDraftSources();
_editMsgId = msgId;
if (!msgId) {
_mediaEditSpoiler.setSpoilerOverride(std::nullopt);
_canReplaceMedia = false;
if (_preview) {
_preview->setDisabled(false);
@ -4043,7 +4044,8 @@ void HistoryWidget::saveEditMsg() {
webPageDraft,
options,
done,
fail);
fail,
_mediaEditSpoiler.spoilerOverride());
}
void HistoryWidget::hideChildWidgets() {
@ -6562,7 +6564,14 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
return;
}
const auto isReadyToForward = readyToForward();
if (_inPhotoEdit && _photoEditMedia) {
if (_editMsgId
&& (_inDetails || _inPhotoEdit)
&& (e->button() == Qt::RightButton)) {
_mediaEditSpoiler.showMenu(
_list,
session().data().message(_history->peer, _editMsgId),
[=](bool) { mouseMoveEvent(nullptr); });
} else if (_inPhotoEdit && _photoEditMedia) {
EditCaptionBox::StartPhotoEdit(
controller(),
_photoEditMedia,
@ -8235,8 +8244,14 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
? drawMsgText->media()
: nullptr;
const auto hasPreview = media && media->hasReplyPreview();
const auto preview = hasPreview ? media->replyPreview() : nullptr;
const auto spoilered = preview && media->hasSpoiler();
const auto preview = _mediaEditSpoiler.spoilerOverride()
? _mediaEditSpoiler.mediaPreview(drawMsgText)
: hasPreview
? media->replyPreview()
: nullptr;
const auto spoilered = _mediaEditSpoiler.spoilerOverride()
? (*_mediaEditSpoiler.spoilerOverride())
: (preview && media->hasSpoiler());
if (!spoilered) {
_replySpoiler = nullptr;
} else if (!_replySpoiler) {

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "history/view/controls/history_view_compose_media_edit_manager.h"
#include "history/view/history_view_corner_buttons.h"
#include "history/history_drag_area.h"
#include "history/history_view_highlight_manager.h"
@ -103,6 +104,7 @@ class ForwardPanel;
class TTLButton;
class WebpageProcessor;
class CharactersLimitLabel;
class PhotoEditSpoilerManager;
} // namespace HistoryView::Controls
class BotKeyboard;
@ -660,6 +662,7 @@ private:
MsgId _editMsgId = 0;
std::shared_ptr<Data::PhotoMedia> _photoEditMedia;
bool _canReplaceMedia = false;
HistoryView::MediaEditSpoilerManager _mediaEditSpoiler;
HistoryItem *_replyEditMsg = nullptr;
Ui::Text::String _replyEditMsgText;

View File

@ -21,6 +21,7 @@ struct MessageToEdit {
FullMsgId fullId;
Api::SendOptions options;
TextWithTags textWithTags;
std::optional<bool> spoilerMediaOverride;
};
struct VoiceToSend {
QByteArray bytes;

View File

@ -50,6 +50,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h"
#include "history/history_item.h"
#include "history/view/controls/history_view_characters_limit.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"
#include "history/view/controls/history_view_voice_record_bar.h"
@ -72,6 +73,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/ui_utility.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/widgets/popup_menu.h"
#include "ui/text/format_values.h"
#include "ui/controls/emoji_button.h"
#include "ui/controls/send_button.h"
@ -84,6 +86,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwindow.h"
#include "styles/style_chat.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_menu_icons.h"
namespace HistoryView {
namespace {
@ -210,6 +213,8 @@ private:
bool _repaintScheduled : 1 = false;
bool _inClickable : 1 = false;
HistoryView::MediaEditSpoilerManager _mediaEditSpoiler;
const not_null<Data::Session*> _data;
const not_null<Ui::IconButton*> _cancel;
@ -398,7 +403,12 @@ void FieldHeader::init() {
_editOptionsRequests.fire({});
}
} else if (!isLeftButton) {
if (const auto reply = replyingToMessage()) {
if (inPreviewRect && isEditingMessage()) {
_mediaEditSpoiler.showMenu(
this,
_data->message(_editMsgId.current()),
[=](bool) { update(); });
} else if (const auto reply = replyingToMessage()) {
_jumpToItemRequests.fire_copy(reply);
}
}
@ -572,10 +582,14 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) {
const auto media = _shownMessage->media();
_shownMessageHasPreview = media && media->hasReplyPreview();
const auto preview = _shownMessageHasPreview
const auto preview = _mediaEditSpoiler.spoilerOverride()
? _mediaEditSpoiler.mediaPreview(_shownMessage)
: _shownMessageHasPreview
? media->replyPreview()
: nullptr;
const auto spoilered = preview && media->hasSpoiler();
const auto spoilered = _mediaEditSpoiler.spoilerOverride()
? (*_mediaEditSpoiler.spoilerOverride())
: (preview && media->hasSpoiler());
if (!spoilered) {
_shownPreviewSpoiler = nullptr;
} else if (!_shownPreviewSpoiler) {
@ -720,6 +734,7 @@ void FieldHeader::editMessage(FullMsgId id, bool photoEditAllowed) {
_photoEditAllowed = photoEditAllowed;
_editMsgId = id;
if (!photoEditAllowed) {
_mediaEditSpoiler.setSpoilerOverride(std::nullopt);
_inPhotoEdit = false;
_inPhotoEditOver.stop();
}
@ -767,6 +782,7 @@ MessageToEdit FieldHeader::queryToEdit() {
.scheduled = item->isScheduled() ? item->date() : 0,
.shortcutId = item->shortcutId(),
},
.spoilerMediaOverride = _mediaEditSpoiler.spoilerOverride(),
};
}
@ -3440,4 +3456,49 @@ rpl::producer<bool> SendDisabledBySlowmode(not_null<PeerData*> peer) {
_1 && _2);
}
void ShowPhotoEditSpoilerMenu(
not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item,
const std::optional<bool> &override,
Fn<void(bool)> callback) {
const auto media = item->media();
const auto hasPreview = media && media->hasReplyPreview();
const auto preview = hasPreview ? media->replyPreview() : nullptr;
if (!preview) {
return;
}
const auto spoilered = override
? (*override)
: (preview && media->hasSpoiler());
const auto menu = Ui::CreateChild<Ui::PopupMenu>(
parent,
st::popupMenuWithIcons);
menu->addAction(
spoilered
? tr::lng_context_disable_spoiler(tr::now)
: tr::lng_context_spoiler_effect(tr::now),
[=] { callback(!spoilered); },
spoilered ? &st::menuIconSpoilerOff : &st::menuIconSpoiler);
menu->popup(QCursor::pos());
}
Image *MediaPreviewWithOverriddenSpoiler(
not_null<HistoryItem*> item,
bool spoiler) {
if (const auto media = item->media()) {
if (const auto photo = media->photo()) {
return photo->getReplyPreview(
item->fullId(),
item->history()->peer,
spoiler);
} else if (const auto document = media->document()) {
return document->getReplyPreview(
item->fullId(),
item->history()->peer,
spoiler);
}
}
return nullptr;
}
} // namespace HistoryView

View File

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class History;
class DocumentData;
class FieldAutocomplete;
class Image;
namespace style {
struct ComposeControls;
@ -451,4 +452,14 @@ private:
[[nodiscard]] rpl::producer<bool> SendDisabledBySlowmode(
not_null<PeerData*> peer);
void ShowPhotoEditSpoilerMenu(
not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item,
const std::optional<bool> &override,
Fn<void(bool)> callback);
[[nodiscard]] Image *MediaPreviewWithOverriddenSpoiler(
not_null<HistoryItem*> item,
bool spoiler);
} // namespace HistoryView

View File

@ -0,0 +1,83 @@
/*
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_media_edit_manager.h"
#include "data/data_document.h"
#include "data/data_file_origin.h"
#include "data/data_photo.h"
#include "history/history.h"
#include "history/history_item.h"
#include "lang/lang_keys.h"
#include "ui/widgets/popup_menu.h"
#include "styles/style_menu_icons.h"
namespace HistoryView {
MediaEditSpoilerManager::MediaEditSpoilerManager() = default;
void MediaEditSpoilerManager::showMenu(
not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item,
Fn<void(bool)> callback) {
const auto media = item->media();
const auto hasPreview = media && media->hasReplyPreview();
const auto preview = hasPreview ? media->replyPreview() : nullptr;
if (!preview) {
return;
}
const auto spoilered = _spoilerOverride
? (*_spoilerOverride)
: (preview && media->hasSpoiler());
const auto menu = Ui::CreateChild<Ui::PopupMenu>(
parent,
st::popupMenuWithIcons);
menu->addAction(
spoilered
? tr::lng_context_disable_spoiler(tr::now)
: tr::lng_context_spoiler_effect(tr::now),
[=] {
_spoilerOverride = (!spoilered);
if (callback) {
callback(!spoilered);
}
},
spoilered ? &st::menuIconSpoilerOff : &st::menuIconSpoiler);
menu->popup(QCursor::pos());
}
[[nodiscard]] Image *MediaEditSpoilerManager::mediaPreview(
not_null<HistoryItem*> item) {
if (!_spoilerOverride) {
return nullptr;
}
if (const auto media = item->media()) {
if (const auto photo = media->photo()) {
return photo->getReplyPreview(
item->fullId(),
item->history()->peer,
*_spoilerOverride);
} else if (const auto document = media->document()) {
return document->getReplyPreview(
item->fullId(),
item->history()->peer,
*_spoilerOverride);
}
}
return nullptr;
}
void MediaEditSpoilerManager::setSpoilerOverride(
std::optional<bool> spoilerOverride) {
_spoilerOverride = spoilerOverride;
}
std::optional<bool> MediaEditSpoilerManager::spoilerOverride() const {
return _spoilerOverride;
}
} // namespace HistoryView

View File

@ -0,0 +1,39 @@
/*
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 Ui {
class RpWidget;
} // namespace Ui
class Image;
class HistoryItem;
namespace HistoryView {
class MediaEditSpoilerManager final {
public:
MediaEditSpoilerManager();
void showMenu(
not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item,
Fn<void(bool)> callback);
[[nodiscard]] Image *mediaPreview(not_null<HistoryItem*> item);
void setSpoilerOverride(std::optional<bool> spoilerOverride);
std::optional<bool> spoilerOverride() const;
private:
std::optional<bool> _spoilerOverride;
};
} // namespace HistoryView

View File

@ -736,7 +736,8 @@ void RepliesWidget::setupComposeControls() {
_composeControls->editRequests(
) | rpl::start_with_next([=](auto data) {
if (const auto item = session().data().message(data.fullId)) {
edit(item, data.options, saveEditMsgRequestId);
const auto spoiler = data.spoilerMediaOverride;
edit(item, data.options, saveEditMsgRequestId, spoiler);
}
}, lifetime());
@ -1207,7 +1208,8 @@ void RepliesWidget::send(Api::SendOptions options) {
void RepliesWidget::edit(
not_null<HistoryItem*> item,
Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId) {
mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride) {
if (*saveEditMsgRequestId) {
return;
}
@ -1275,7 +1277,8 @@ void RepliesWidget::edit(
webpage,
options,
crl::guard(this, done),
crl::guard(this, fail));
crl::guard(this, fail),
spoilerMediaOverride);
_composeControls->hidePanelsAnimated();
doSetInnerFocus();

View File

@ -246,7 +246,8 @@ private:
void edit(
not_null<HistoryItem*> item,
Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId);
mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride);
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
[[nodiscard]] SendMenu::Type sendMenuType() const;
[[nodiscard]] FullReplyTo replyTo() const;

View File

@ -318,7 +318,8 @@ void ScheduledWidget::setupComposeControls() {
) | rpl::start_with_next([=](auto data) {
if (const auto item = session().data().message(data.fullId)) {
if (item->isScheduled()) {
edit(item, data.options, saveEditMsgRequestId);
const auto spoiler = data.spoilerMediaOverride;
edit(item, data.options, saveEditMsgRequestId, spoiler);
}
}
}, lifetime());
@ -726,7 +727,8 @@ void ScheduledWidget::sendVoice(
void ScheduledWidget::edit(
not_null<HistoryItem*> item,
Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId) {
mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride) {
if (*saveEditMsgRequestId) {
return;
}
@ -794,7 +796,8 @@ void ScheduledWidget::edit(
webpage,
options,
crl::guard(this, done),
crl::guard(this, fail));
crl::guard(this, fail),
spoilerMediaOverride);
_composeControls->hidePanelsAnimated();
_composeControls->focus();

View File

@ -213,7 +213,8 @@ private:
void edit(
not_null<HistoryItem*> item,
Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId);
mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride);
void highlightSingleNewMessage(const Data::MessagesSlice &slice);
void chooseAttach();
[[nodiscard]] SendMenu::Type sendMenuType() const;

View File

@ -238,7 +238,8 @@ private:
void edit(
not_null<HistoryItem*> item,
Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId);
mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride);
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
[[nodiscard]] SendMenu::Type sendMenuType() const;
[[nodiscard]] FullReplyTo replyTo() const;
@ -673,7 +674,8 @@ void ShortcutMessages::setupComposeControls() {
) | rpl::start_with_next([=](auto data) {
if (const auto item = _session->data().message(data.fullId)) {
if (item->isBusinessShortcut()) {
edit(item, data.options, saveEditMsgRequestId);
const auto spoiler = data.spoilerMediaOverride;
edit(item, data.options, saveEditMsgRequestId, spoiler);
}
}
}, lifetime());
@ -1213,7 +1215,8 @@ void ShortcutMessages::send(Api::SendOptions options) {
void ShortcutMessages::edit(
not_null<HistoryItem*> item,
Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId) {
mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride) {
if (*saveEditMsgRequestId) {
return;
}
@ -1281,7 +1284,8 @@ void ShortcutMessages::edit(
webpage,
options,
crl::guard(this, done),
crl::guard(this, fail));
crl::guard(this, fail),
spoilerMediaOverride);
_composeControls->hidePanelsAnimated();
doSetInnerFocus();