Implement text -> media message editing.

This commit is contained in:
John Preston 2024-10-10 18:20:10 +04:00
parent 0397006894
commit f89aeb6ad4
9 changed files with 55 additions and 21 deletions

View file

@ -238,7 +238,7 @@ EditCaptionBox::EditCaptionBox(
Fn<void()> saved) Fn<void()> saved)
: _controller(controller) : _controller(controller)
, _historyItem(item) , _historyItem(item)
, _isAllowedEditMedia(item->media() && item->media()->allowsEditMedia()) , _isAllowedEditMedia(item->allowsEditMedia())
, _albumType(ComputeAlbumType(item)) , _albumType(ComputeAlbumType(item))
, _controls(base::make_unique_q<Ui::VerticalLayout>(this)) , _controls(base::make_unique_q<Ui::VerticalLayout>(this))
, _scroll(base::make_unique_q<Ui::ScrollArea>(this, st::boxScroll)) , _scroll(base::make_unique_q<Ui::ScrollArea>(this, st::boxScroll))
@ -253,8 +253,8 @@ EditCaptionBox::EditCaptionBox(
, _initialText(std::move(text)) , _initialText(std::move(text))
, _initialList(std::move(list)) , _initialList(std::move(list))
, _saved(std::move(saved)) { , _saved(std::move(saved)) {
Expects(item->media() != nullptr); Expects(!_initialList.files.empty());
Expects(item->media()->allowsEditCaption()); Expects(!item->media() || item->media()->allowsEditCaption());
_mediaEditManager.start(item, spoilered, invertCaption); _mediaEditManager.start(item, spoilered, invertCaption);
@ -422,7 +422,8 @@ void EditCaptionBox::prepare() {
setInitialText(); setInitialText();
if (!setPreparedList(std::move(_initialList))) { if (!setPreparedList(std::move(_initialList))) {
rebuildPreview(); crl::on_main(this, [=] { closeBox(); });
return;
} }
setupEditEventHandler(); setupEditEventHandler();
SetupShadowsToScrollContent(this, _scroll, _contentHeight.events()); SetupShadowsToScrollContent(this, _scroll, _contentHeight.events());

View file

@ -1074,6 +1074,13 @@ historyReplaceMedia: IconButton(historyAttach) {
color: lightButtonBgOver; color: lightButtonBgOver;
} }
} }
historyAddMedia: IconButton(historyAttach) {
icon: icon {{ "chat/input_attach", windowBgActive }};
iconOver: icon {{ "chat/input_attach", windowBgActive }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: lightButtonBgOver;
}
}
historyAttachEmojiActive: icon {{ "chat/input_smile_face", windowBgActive }}; historyAttachEmojiActive: icon {{ "chat/input_smile_face", windowBgActive }};
historyEmojiCircle: size(20px, 20px); historyEmojiCircle: size(20px, 20px);

View file

@ -1470,12 +1470,10 @@ void HistoryItem::returnSavedMedia() {
} }
void HistoryItem::savePreviousMedia() { void HistoryItem::savePreviousMedia() {
Expects(_media != nullptr);
AddComponents(HistoryMessageSavedMediaData::Bit()); AddComponents(HistoryMessageSavedMediaData::Bit());
const auto data = Get<HistoryMessageSavedMediaData>(); const auto data = Get<HistoryMessageSavedMediaData>();
data->text = originalText(); data->text = originalText();
data->media = _media->clone(this); data->media = _media ? _media->clone(this) : nullptr;
} }
bool HistoryItem::isEditingMedia() const { bool HistoryItem::isEditingMedia() const {
@ -2231,6 +2229,10 @@ bool HistoryItem::allowsEdit(TimeId now) const {
&& !isEditingMedia(); && !isEditingMedia();
} }
bool HistoryItem::allowsEditMedia() const {
return !_media || _media->allowsEditMedia();
}
bool HistoryItem::canBeEdited() const { bool HistoryItem::canBeEdited() const {
if ((!isRegular() && !isScheduled() && !isBusinessShortcut()) if ((!isRegular() && !isScheduled() && !isBusinessShortcut())
|| Has<HistoryMessageVia>() || Has<HistoryMessageVia>()

View file

@ -431,6 +431,7 @@ public:
[[nodiscard]] bool allowsSendNow() const; [[nodiscard]] bool allowsSendNow() const;
[[nodiscard]] bool allowsForward() const; [[nodiscard]] bool allowsForward() const;
[[nodiscard]] bool allowsEdit(TimeId now) const; [[nodiscard]] bool allowsEdit(TimeId now) const;
[[nodiscard]] bool allowsEditMedia() const;
[[nodiscard]] bool canDelete() const; [[nodiscard]] bool canDelete() const;
[[nodiscard]] bool canDeleteForEveryone(TimeId now) const; [[nodiscard]] bool canDeleteForEveryone(TimeId now) const;
[[nodiscard]] bool suggestReport() const; [[nodiscard]] bool suggestReport() const;

View file

@ -2312,7 +2312,7 @@ void HistoryWidget::showHistory(
_processingReplyItem = _replyEditMsg = nullptr; _processingReplyItem = _replyEditMsg = nullptr;
_processingReplyTo = _replyTo = FullReplyTo(); _processingReplyTo = _replyTo = FullReplyTo();
_editMsgId = MsgId(); _editMsgId = MsgId();
_canReplaceMedia = false; _canReplaceMedia = _canAddMedia = false;
_photoEditMedia = nullptr; _photoEditMedia = nullptr;
updateReplaceMediaButton(); updateReplaceMediaButton();
_fieldBarCancel->hide(); _fieldBarCancel->hide();
@ -2700,7 +2700,7 @@ void HistoryWidget::setEditMsgId(MsgId msgId) {
_editMsgId = msgId; _editMsgId = msgId;
if (!msgId) { if (!msgId) {
_mediaEditManager.cancel(); _mediaEditManager.cancel();
_canReplaceMedia = false; _canReplaceMedia = _canAddMedia = false;
if (_preview) { if (_preview) {
_preview->setDisabled(false); _preview->setDisabled(false);
} }
@ -2756,14 +2756,16 @@ void HistoryWidget::clearAllLoadRequests() {
} }
bool HistoryWidget::updateReplaceMediaButton() { bool HistoryWidget::updateReplaceMediaButton() {
if (!_canReplaceMedia) { if (!_canReplaceMedia && !_canAddMedia) {
const auto result = (_replaceMedia != nullptr); const auto result = (_replaceMedia != nullptr);
_replaceMedia.destroy(); _replaceMedia.destroy();
return result; return result;
} else if (_replaceMedia) { } else if (_replaceMedia) {
return false; return false;
} }
_replaceMedia.create(this, st::historyReplaceMedia); _replaceMedia.create(
this,
_canReplaceMedia ? st::historyReplaceMedia : st::historyAddMedia);
const auto hideDuration = st::historyReplaceMedia.ripple.hideDuration; const auto hideDuration = st::historyReplaceMedia.ripple.hideDuration;
_replaceMedia->setClickedCallback([=] { _replaceMedia->setClickedCallback([=] {
base::call_delayed(hideDuration, this, [=] { base::call_delayed(hideDuration, this, [=] {
@ -5712,7 +5714,7 @@ bool HistoryWidget::confirmSendingFiles(
Ui::PreparedList &&list, Ui::PreparedList &&list,
const QString &insertTextOnCancel) { const QString &insertTextOnCancel) {
if (_editMsgId) { if (_editMsgId) {
if (_canReplaceMedia) { if (_canReplaceMedia || _canAddMedia) {
EditCaptionBox::StartMediaReplace( EditCaptionBox::StartMediaReplace(
controller(), controller(),
{ _history->peer->id, _editMsgId }, { _history->peer->id, _editMsgId },
@ -8002,7 +8004,7 @@ void HistoryWidget::cancelEdit() {
return; return;
} }
_canReplaceMedia = false; _canReplaceMedia = _canAddMedia = false;
_photoEditMedia = nullptr; _photoEditMedia = nullptr;
updateReplaceMediaButton(); updateReplaceMediaButton();
_replyEditMsg = nullptr; _replyEditMsg = nullptr;
@ -8357,7 +8359,16 @@ void HistoryWidget::updateReplyEditTexts(bool force) {
if (_editMsgId && _replyEditMsg) { if (_editMsgId && _replyEditMsg) {
_mediaEditManager.start(_replyEditMsg); _mediaEditManager.start(_replyEditMsg);
} }
_canReplaceMedia = editMedia && editMedia->allowsEditMedia(); _canReplaceMedia = _editMsgId && _replyEditMsg->allowsEditMedia();
if (editMedia) {
_canAddMedia = false;
} else {
_canAddMedia = base::take(_canReplaceMedia);
}
if (_canReplaceMedia || _canAddMedia) {
// Invalidate the button, maybe icon has changed.
_replaceMedia.destroy();
}
_photoEditMedia = (_canReplaceMedia _photoEditMedia = (_canReplaceMedia
&& editMedia->photo() && editMedia->photo()
&& !editMedia->photo()->isNull()) && !editMedia->photo()->isNull())

View file

@ -662,6 +662,7 @@ private:
MsgId _editMsgId = 0; MsgId _editMsgId = 0;
std::shared_ptr<Data::PhotoMedia> _photoEditMedia; std::shared_ptr<Data::PhotoMedia> _photoEditMedia;
bool _canReplaceMedia = false; bool _canReplaceMedia = false;
bool _canAddMedia = false;
HistoryView::MediaEditManager _mediaEditManager; HistoryView::MediaEditManager _mediaEditManager;
HistoryItem *_replyEditMsg = nullptr; HistoryItem *_replyEditMsg = nullptr;

View file

@ -1153,7 +1153,7 @@ void ComposeControls::setMimeDataHook(MimeDataHook hook) {
bool ComposeControls::confirmMediaEdit(Ui::PreparedList &list) { bool ComposeControls::confirmMediaEdit(Ui::PreparedList &list) {
if (!isEditingMessage() || !_regularWindow) { if (!isEditingMessage() || !_regularWindow) {
return false; return false;
} else if (_canReplaceMedia) { } else if (_canReplaceMedia || _canAddMedia) {
const auto queryToEdit = _header->queryToEdit(); const auto queryToEdit = _header->queryToEdit();
EditCaptionBox::StartMediaReplace( EditCaptionBox::StartMediaReplace(
_regularWindow, _regularWindow,
@ -1944,7 +1944,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
_preview->apply({ .removed = true }); _preview->apply({ .removed = true });
_preview->setDisabled(false); _preview->setDisabled(false);
} }
_canReplaceMedia = false; _canReplaceMedia = _canAddMedia = false;
_photoEditMedia = nullptr; _photoEditMedia = nullptr;
return; return;
} }
@ -1964,7 +1964,16 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
const auto resolve = [=] { const auto resolve = [=] {
if (const auto item = _history->owner().message(editingId)) { if (const auto item = _history->owner().message(editingId)) {
const auto media = item->media(); const auto media = item->media();
_canReplaceMedia = media && media->allowsEditMedia(); _canReplaceMedia = item->allowsEditMedia();
if (media) {
_canAddMedia = false;
} else {
_canAddMedia = base::take(_canReplaceMedia);
}
if (_canReplaceMedia || _canAddMedia) {
// Invalidate the button, maybe icon has changed.
_replaceMedia = nullptr;
}
_photoEditMedia = (_canReplaceMedia _photoEditMedia = (_canReplaceMedia
&& _regularWindow && _regularWindow
&& media->photo() && media->photo()
@ -1985,7 +1994,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
} }
return true; return true;
} }
_canReplaceMedia = false; _canReplaceMedia = _canAddMedia = false;
_photoEditMedia = nullptr; _photoEditMedia = nullptr;
_header->editMessage(editingId, false); _header->editMessage(editingId, false);
return false; return false;
@ -2006,7 +2015,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
} }
_header->replyToMessage({}); _header->replyToMessage({});
} else { } else {
_canReplaceMedia = false; _canReplaceMedia = _canAddMedia = false;
_photoEditMedia = nullptr; _photoEditMedia = nullptr;
_header->replyToMessage(draft->reply); _header->replyToMessage(draft->reply);
if (_header->replyingToMessage()) { if (_header->replyingToMessage()) {
@ -2931,7 +2940,7 @@ void ComposeControls::editMessage(not_null<HistoryItem*> item) {
} }
bool ComposeControls::updateReplaceMediaButton() { bool ComposeControls::updateReplaceMediaButton() {
if (!_canReplaceMedia || !_regularWindow) { if ((!_canReplaceMedia && !_canAddMedia) || !_regularWindow) {
const auto result = (_replaceMedia != nullptr); const auto result = (_replaceMedia != nullptr);
_replaceMedia = nullptr; _replaceMedia = nullptr;
return result; return result;
@ -2940,7 +2949,7 @@ bool ComposeControls::updateReplaceMediaButton() {
} }
_replaceMedia = std::make_unique<Ui::IconButton>( _replaceMedia = std::make_unique<Ui::IconButton>(
_wrap.get(), _wrap.get(),
st::historyReplaceMedia); _canReplaceMedia ? st::historyReplaceMedia : st::historyAddMedia);
const auto hideDuration = st::historyReplaceMedia.ripple.hideDuration; const auto hideDuration = st::historyReplaceMedia.ripple.hideDuration;
_replaceMedia->setClickedCallback([=] { _replaceMedia->setClickedCallback([=] {
base::call_delayed(hideDuration, _wrap.get(), [=] { base::call_delayed(hideDuration, _wrap.get(), [=] {

View file

@ -444,6 +444,7 @@ private:
FullMsgId _editingId; FullMsgId _editingId;
std::shared_ptr<Data::PhotoMedia> _photoEditMedia; std::shared_ptr<Data::PhotoMedia> _photoEditMedia;
bool _canReplaceMedia = false; bool _canReplaceMedia = false;
bool _canAddMedia = false;
std::unique_ptr<Controls::WebpageProcessor> _preview; std::unique_ptr<Controls::WebpageProcessor> _preview;

View file

@ -29,6 +29,7 @@ void MediaEditManager::start(
std::optional<bool> invertCaption) { std::optional<bool> invertCaption) {
const auto media = item->media(); const auto media = item->media();
if (!media) { if (!media) {
cancel();
return; return;
} }
_item = item; _item = item;