mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 07:07:08 +02:00
Allow editing spoiler/caption-above in EditCaptionBox.
This commit is contained in:
parent
8c0351be4e
commit
974bf99921
21 changed files with 247 additions and 156 deletions
Telegram/SourceFiles
|
@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_histories.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "history/view/controls/history_view_compose_media_edit_manager.h"
|
||||
#include "history/history.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -255,85 +256,85 @@ mtpRequestId EditTextMessage(
|
|||
SendOptions options,
|
||||
Fn<void(mtpRequestId requestId)> done,
|
||||
Fn<void(const QString &error, mtpRequestId requestId)> fail,
|
||||
std::optional<bool> spoilerMediaOverride) {
|
||||
if (spoilerMediaOverride) {
|
||||
const auto spoiler = *spoilerMediaOverride;
|
||||
if (const auto media = item->media()) {
|
||||
auto takeInputMedia = Fn<std::optional<MTPInputMedia>()>(nullptr);
|
||||
auto takeFileReference = Fn<QByteArray()>(nullptr);
|
||||
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());
|
||||
takeInputMedia = [=] {
|
||||
return MTP_inputMediaPhoto(
|
||||
MTP_flags(flags),
|
||||
photo->mtpInput(),
|
||||
MTP_int(media->ttlSeconds()));
|
||||
};
|
||||
takeFileReference = [=] { return photo->fileReference(); };
|
||||
} 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());
|
||||
takeInputMedia = [=] {
|
||||
return MTP_inputMediaDocument(
|
||||
MTP_flags(flags),
|
||||
document->mtpInput(),
|
||||
MTP_int(media->ttlSeconds()),
|
||||
MTPstring()); // query
|
||||
};
|
||||
takeFileReference = [=] { return document->fileReference(); };
|
||||
}
|
||||
|
||||
const auto usedFileReference = takeFileReference
|
||||
? takeFileReference()
|
||||
: QByteArray();
|
||||
const auto origin = item->fullId();
|
||||
const auto api = &item->history()->session().api();
|
||||
const auto performRequest = [=](
|
||||
const auto &repeatRequest,
|
||||
mtpRequestId originalRequestId) -> mtpRequestId {
|
||||
const auto handleReference = [=](
|
||||
const QString &error,
|
||||
mtpRequestId requestId) {
|
||||
if (error.startsWith(u"FILE_REFERENCE_"_q)) {
|
||||
api->refreshFileReference(origin, [=](const auto &) {
|
||||
if (takeFileReference &&
|
||||
(takeFileReference() != usedFileReference)) {
|
||||
repeatRequest(
|
||||
repeatRequest,
|
||||
originalRequestId
|
||||
? originalRequestId
|
||||
: requestId);
|
||||
} else {
|
||||
fail(error, requestId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fail(error, requestId);
|
||||
}
|
||||
};
|
||||
const auto callback = [=](
|
||||
Fn<void()> applyUpdates,
|
||||
mtpRequestId requestId) {
|
||||
applyUpdates();
|
||||
done(originalRequestId ? originalRequestId : requestId);
|
||||
};
|
||||
const auto requestId = EditMessage(
|
||||
item,
|
||||
caption,
|
||||
webpage,
|
||||
options,
|
||||
callback,
|
||||
handleReference,
|
||||
takeInputMedia ? takeInputMedia() : std::nullopt);
|
||||
return originalRequestId ? originalRequestId : requestId;
|
||||
bool spoilered) {
|
||||
const auto media = item->media();
|
||||
if (media
|
||||
&& HistoryView::MediaEditManager::CanBeSpoilered(item)
|
||||
&& spoilered != media->hasSpoiler()) {
|
||||
auto takeInputMedia = Fn<std::optional<MTPInputMedia>()>(nullptr);
|
||||
auto takeFileReference = Fn<QByteArray()>(nullptr);
|
||||
if (const auto photo = media->photo()) {
|
||||
using Flag = MTPDinputMediaPhoto::Flag;
|
||||
const auto flags = Flag()
|
||||
| (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag())
|
||||
| (spoilered ? Flag::f_spoiler : Flag());
|
||||
takeInputMedia = [=] {
|
||||
return MTP_inputMediaPhoto(
|
||||
MTP_flags(flags),
|
||||
photo->mtpInput(),
|
||||
MTP_int(media->ttlSeconds()));
|
||||
};
|
||||
return performRequest(performRequest, 0);
|
||||
takeFileReference = [=] { return photo->fileReference(); };
|
||||
} else if (const auto document = media->document()) {
|
||||
using Flag = MTPDinputMediaDocument::Flag;
|
||||
const auto flags = Flag()
|
||||
| (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag())
|
||||
| (spoilered ? Flag::f_spoiler : Flag());
|
||||
takeInputMedia = [=] {
|
||||
return MTP_inputMediaDocument(
|
||||
MTP_flags(flags),
|
||||
document->mtpInput(),
|
||||
MTP_int(media->ttlSeconds()),
|
||||
MTPstring()); // query
|
||||
};
|
||||
takeFileReference = [=] { return document->fileReference(); };
|
||||
}
|
||||
|
||||
const auto usedFileReference = takeFileReference
|
||||
? takeFileReference()
|
||||
: QByteArray();
|
||||
const auto origin = item->fullId();
|
||||
const auto api = &item->history()->session().api();
|
||||
const auto performRequest = [=](
|
||||
const auto &repeatRequest,
|
||||
mtpRequestId originalRequestId) -> mtpRequestId {
|
||||
const auto handleReference = [=](
|
||||
const QString &error,
|
||||
mtpRequestId requestId) {
|
||||
if (error.startsWith(u"FILE_REFERENCE_"_q)) {
|
||||
api->refreshFileReference(origin, [=](const auto &) {
|
||||
if (takeFileReference &&
|
||||
(takeFileReference() != usedFileReference)) {
|
||||
repeatRequest(
|
||||
repeatRequest,
|
||||
originalRequestId
|
||||
? originalRequestId
|
||||
: requestId);
|
||||
} else {
|
||||
fail(error, requestId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fail(error, requestId);
|
||||
}
|
||||
};
|
||||
const auto callback = [=](
|
||||
Fn<void()> applyUpdates,
|
||||
mtpRequestId requestId) {
|
||||
applyUpdates();
|
||||
done(originalRequestId ? originalRequestId : requestId);
|
||||
};
|
||||
const auto requestId = EditMessage(
|
||||
item,
|
||||
caption,
|
||||
webpage,
|
||||
options,
|
||||
callback,
|
||||
handleReference,
|
||||
takeInputMedia ? takeInputMedia() : std::nullopt);
|
||||
return originalRequestId ? originalRequestId : requestId;
|
||||
};
|
||||
return performRequest(performRequest, 0);
|
||||
}
|
||||
|
||||
const auto callback = [=](Fn<void()> applyUpdates, mtpRequestId id) {
|
||||
|
|
|
@ -56,6 +56,6 @@ mtpRequestId EditTextMessage(
|
|||
SendOptions options,
|
||||
Fn<void(mtpRequestId requestId)> done,
|
||||
Fn<void(const QString &error, mtpRequestId requestId)> fail,
|
||||
std::optional<bool> spoilerMediaOverride);
|
||||
bool spoilered);
|
||||
|
||||
} // namespace Api
|
||||
|
|
|
@ -514,6 +514,7 @@ void SendConfirmedFile(
|
|||
edition.ttl = 0;
|
||||
edition.mtpMedia = &media;
|
||||
edition.textWithEntities = caption;
|
||||
edition.invertMedia = file->to.options.invertCaption;
|
||||
edition.useSameViews = true;
|
||||
edition.useSameForwards = true;
|
||||
edition.useSameMarkup = true;
|
||||
|
|
|
@ -176,7 +176,7 @@ void ChooseReplacement(
|
|||
void EditPhotoImage(
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<Data::PhotoMedia> media,
|
||||
bool wasSpoiler,
|
||||
bool spoilered,
|
||||
Fn<void(Ui::PreparedList)> done) {
|
||||
const auto large = media
|
||||
? media->image(Data::PhotoSize::Large)
|
||||
|
@ -199,7 +199,7 @@ void EditPhotoImage(
|
|||
|
||||
using ImageInfo = Ui::PreparedFileInformation::Image;
|
||||
auto &file = list.files.front();
|
||||
file.spoiler = wasSpoiler;
|
||||
file.spoiler = spoilered;
|
||||
const auto image = std::get_if<ImageInfo>(&file.information->media);
|
||||
|
||||
image->modifications = mods;
|
||||
|
@ -231,13 +231,13 @@ EditCaptionBox::EditCaptionBox(
|
|||
not_null<Window::SessionController*> controller,
|
||||
not_null<HistoryItem*> item,
|
||||
TextWithTags &&text,
|
||||
bool spoilered,
|
||||
bool invertCaption,
|
||||
Ui::PreparedList &&list,
|
||||
Fn<void()> saved)
|
||||
: _controller(controller)
|
||||
, _historyItem(item)
|
||||
, _isAllowedEditMedia(item->media()
|
||||
? item->media()->allowsEditMedia()
|
||||
: false)
|
||||
, _isAllowedEditMedia(item->media() && item->media()->allowsEditMedia())
|
||||
, _albumType(ComputeAlbumType(item))
|
||||
, _controls(base::make_unique_q<Ui::VerticalLayout>(this))
|
||||
, _scroll(base::make_unique_q<Ui::ScrollArea>(this, st::boxScroll))
|
||||
|
@ -255,6 +255,8 @@ EditCaptionBox::EditCaptionBox(
|
|||
Expects(item->media() != nullptr);
|
||||
Expects(item->media()->allowsEditCaption());
|
||||
|
||||
_mediaEditManager.start(item, spoilered, invertCaption);
|
||||
|
||||
_controller->session().data().itemRemoved(
|
||||
_historyItem->fullId()
|
||||
) | rpl::start_with_next([=] {
|
||||
|
@ -268,6 +270,8 @@ void EditCaptionBox::StartMediaReplace(
|
|||
not_null<Window::SessionController*> controller,
|
||||
FullMsgId itemId,
|
||||
TextWithTags text,
|
||||
bool spoilered,
|
||||
bool invertCaption,
|
||||
Fn<void()> saved) {
|
||||
const auto session = &controller->session();
|
||||
const auto item = session->data().message(itemId);
|
||||
|
@ -279,6 +283,8 @@ void EditCaptionBox::StartMediaReplace(
|
|||
controller,
|
||||
item,
|
||||
std::move(text),
|
||||
spoilered,
|
||||
invertCaption,
|
||||
std::move(list),
|
||||
std::move(saved)));
|
||||
};
|
||||
|
@ -293,6 +299,8 @@ void EditCaptionBox::StartMediaReplace(
|
|||
FullMsgId itemId,
|
||||
Ui::PreparedList &&list,
|
||||
TextWithTags text,
|
||||
bool spoilered,
|
||||
bool invertCaption,
|
||||
Fn<void()> saved) {
|
||||
const auto session = &controller->session();
|
||||
const auto item = session->data().message(itemId);
|
||||
|
@ -326,6 +334,8 @@ void EditCaptionBox::StartMediaReplace(
|
|||
controller,
|
||||
item,
|
||||
std::move(text),
|
||||
spoilered,
|
||||
invertCaption,
|
||||
std::move(list),
|
||||
std::move(saved)));
|
||||
}
|
||||
|
@ -336,14 +346,15 @@ void EditCaptionBox::StartPhotoEdit(
|
|||
std::shared_ptr<Data::PhotoMedia> media,
|
||||
FullMsgId itemId,
|
||||
TextWithTags text,
|
||||
bool spoilered,
|
||||
bool invertCaption,
|
||||
Fn<void()> saved) {
|
||||
const auto session = &controller->session();
|
||||
const auto item = session->data().message(itemId);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const auto hasSpoiler = item->media() && item->media()->hasSpoiler();
|
||||
EditPhotoImage(controller, media, hasSpoiler, [=](
|
||||
EditPhotoImage(controller, media, spoilered, [=](
|
||||
Ui::PreparedList &&list) mutable {
|
||||
const auto item = session->data().message(itemId);
|
||||
if (!item) {
|
||||
|
@ -353,6 +364,8 @@ void EditCaptionBox::StartPhotoEdit(
|
|||
controller,
|
||||
item,
|
||||
std::move(text),
|
||||
spoilered,
|
||||
invertCaption,
|
||||
std::move(list),
|
||||
std::move(saved)));
|
||||
});
|
||||
|
@ -363,10 +376,29 @@ void EditCaptionBox::prepare() {
|
|||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
const auto details = crl::guard(this, [=] {
|
||||
return SendMenu::Details();
|
||||
auto result = SendMenu::Details();
|
||||
const auto allWithSpoilers = ranges::all_of(
|
||||
_preparedList.files,
|
||||
&Ui::PreparedFile::spoiler);
|
||||
result.spoiler = !_preparedList.hasSpoilerMenu(!_asFile)
|
||||
? SendMenu::SpoilerState::None
|
||||
: allWithSpoilers
|
||||
? SendMenu::SpoilerState::Enabled
|
||||
: SendMenu::SpoilerState::Possible;
|
||||
const auto canMoveCaption = _preparedList.canMoveCaption(
|
||||
false,
|
||||
!_asFile
|
||||
) && _field && HasSendText(_field);
|
||||
result.caption = !canMoveCaption
|
||||
? SendMenu::CaptionState::None
|
||||
: _mediaEditManager.invertCaption()
|
||||
? SendMenu::CaptionState::Above
|
||||
: SendMenu::CaptionState::Below;
|
||||
return result;
|
||||
});
|
||||
const auto callback = [=](SendMenu::Action action, const auto &) {
|
||||
|
||||
_mediaEditManager.apply(action);
|
||||
rebuildPreview();
|
||||
};
|
||||
SendMenu::SetupMenuAndShortcuts(
|
||||
button,
|
||||
|
@ -402,7 +434,6 @@ void EditCaptionBox::rebuildPreview() {
|
|||
|
||||
applyChanges();
|
||||
|
||||
_previewHasSpoiler = nullptr;
|
||||
if (_preparedList.files.empty()) {
|
||||
const auto media = _historyItem->media();
|
||||
const auto photo = media->photo();
|
||||
|
@ -436,7 +467,13 @@ void EditCaptionBox::rebuildPreview() {
|
|||
_isPhoto = (media && media->isPhoto());
|
||||
const auto withCheckbox = _isPhoto && CanBeCompressed(_albumType);
|
||||
if (media && (!withCheckbox || !_asFile)) {
|
||||
_previewHasSpoiler = [media] { return media->hasSpoiler(); };
|
||||
media->spoileredChanges(
|
||||
) | rpl::start_with_next([=](bool spoilered) {
|
||||
_mediaEditManager.apply({ .type = spoilered
|
||||
? SendMenu::ActionType::SpoilerOn
|
||||
: SendMenu::ActionType::SpoilerOff
|
||||
});
|
||||
}, media->lifetime());
|
||||
_content.reset(media);
|
||||
} else {
|
||||
_content.reset(Ui::CreateChild<Ui::SingleFilePreview>(
|
||||
|
@ -763,10 +800,7 @@ bool EditCaptionBox::setPreparedList(Ui::PreparedList &&list) {
|
|||
}
|
||||
|
||||
bool EditCaptionBox::hasSpoiler() const {
|
||||
return _preparedList.files.empty()
|
||||
? (_historyItem->media()
|
||||
&& _historyItem->media()->hasSpoiler())
|
||||
: _preparedList.files.front().spoiler;
|
||||
return _mediaEditManager.spoilered();
|
||||
}
|
||||
|
||||
void EditCaptionBox::captionResized() {
|
||||
|
@ -875,8 +909,8 @@ bool EditCaptionBox::validateLength(const QString &text) const {
|
|||
}
|
||||
|
||||
void EditCaptionBox::applyChanges() {
|
||||
if (!_preparedList.files.empty() && _previewHasSpoiler) {
|
||||
_preparedList.files.front().spoiler = _previewHasSpoiler();
|
||||
if (!_preparedList.files.empty()) {
|
||||
_preparedList.files.front().spoiler = _mediaEditManager.spoilered();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -905,7 +939,7 @@ void EditCaptionBox::save() {
|
|||
auto options = Api::SendOptions();
|
||||
options.scheduled = item->isScheduled() ? item->date() : 0;
|
||||
options.shortcutId = item->shortcutId();
|
||||
//options.invertCaption = _invertCaption;
|
||||
options.invertCaption = _mediaEditManager.invertCaption();
|
||||
|
||||
if (!_preparedList.files.empty()) {
|
||||
if ((_albumType != Ui::AlbumType::None)
|
||||
|
|
|
@ -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 "ui/layers/box_content.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
|
||||
|
@ -37,6 +38,8 @@ public:
|
|||
not_null<Window::SessionController*> controller,
|
||||
not_null<HistoryItem*> item,
|
||||
TextWithTags &&text,
|
||||
bool spoilered,
|
||||
bool invertCaption,
|
||||
Ui::PreparedList &&list,
|
||||
Fn<void()> saved);
|
||||
~EditCaptionBox();
|
||||
|
@ -45,18 +48,24 @@ public:
|
|||
not_null<Window::SessionController*> controller,
|
||||
FullMsgId itemId,
|
||||
TextWithTags text,
|
||||
bool spoilered,
|
||||
bool invertCaption,
|
||||
Fn<void()> saved);
|
||||
static void StartMediaReplace(
|
||||
not_null<Window::SessionController*> controller,
|
||||
FullMsgId itemId,
|
||||
Ui::PreparedList &&list,
|
||||
TextWithTags text,
|
||||
bool spoilered,
|
||||
bool invertCaption,
|
||||
Fn<void()> saved);
|
||||
static void StartPhotoEdit(
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<Data::PhotoMedia> media,
|
||||
FullMsgId itemId,
|
||||
TextWithTags text,
|
||||
bool spoilered,
|
||||
bool invertCaption,
|
||||
Fn<void()> saved);
|
||||
|
||||
protected:
|
||||
|
@ -107,7 +116,6 @@ private:
|
|||
const base::unique_qptr<Ui::EmojiButton> _emojiToggle;
|
||||
|
||||
base::unique_qptr<Ui::AbstractSinglePreview> _content;
|
||||
Fn<bool()> _previewHasSpoiler;
|
||||
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
|
||||
base::unique_qptr<QObject> _emojiFilter;
|
||||
|
||||
|
@ -118,6 +126,7 @@ private:
|
|||
std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||
|
||||
Ui::PreparedList _preparedList;
|
||||
HistoryView::MediaEditManager _mediaEditManager;
|
||||
|
||||
mtpRequestId _saveRequestId = 0;
|
||||
|
||||
|
|
|
@ -595,16 +595,7 @@ bool SendFilesBox::hasSendMenu(const SendMenu::Details &details) const {
|
|||
}
|
||||
|
||||
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());
|
||||
return _list.hasSpoilerMenu(_sendWay.current().sendImagesAsPhotos());
|
||||
}
|
||||
|
||||
void SendFilesBox::applyBlockChanges() {
|
||||
|
|
|
@ -328,7 +328,7 @@ HistoryWidget::HistoryWidget(
|
|||
|| action.type == ActionType::CaptionDown
|
||||
|| action.type == ActionType::SpoilerOn
|
||||
|| action.type == ActionType::SpoilerOff) {
|
||||
_mediaEditSpoiler.apply(action);
|
||||
_mediaEditManager.apply(action);
|
||||
} else if (action.type == ActionType::Send) {
|
||||
send(action.options);
|
||||
} else {
|
||||
|
@ -2677,7 +2677,7 @@ void HistoryWidget::setEditMsgId(MsgId msgId) {
|
|||
unregisterDraftSources();
|
||||
_editMsgId = msgId;
|
||||
if (!msgId) {
|
||||
_mediaEditSpoiler.cancel();
|
||||
_mediaEditManager.cancel();
|
||||
_canReplaceMedia = false;
|
||||
if (_preview) {
|
||||
_preview->setDisabled(false);
|
||||
|
@ -2749,6 +2749,8 @@ bool HistoryWidget::updateReplaceMediaButton() {
|
|||
controller(),
|
||||
{ _history->peer->id, _editMsgId },
|
||||
_field->getTextWithTags(),
|
||||
_mediaEditManager.spoilered(),
|
||||
_mediaEditManager.invertCaption(),
|
||||
crl::guard(_list, [=] { cancelEdit(); }));
|
||||
});
|
||||
});
|
||||
|
@ -4065,10 +4067,10 @@ void HistoryWidget::saveEditMsg() {
|
|||
item,
|
||||
sending,
|
||||
webPageDraft,
|
||||
{ .invertCaption = _mediaEditSpoiler.invertCaption() },
|
||||
{ .invertCaption = _mediaEditManager.invertCaption() },
|
||||
done,
|
||||
fail,
|
||||
_mediaEditSpoiler.spoilered());
|
||||
_mediaEditManager.spoilered());
|
||||
}
|
||||
|
||||
void HistoryWidget::hideChildWidgets() {
|
||||
|
@ -4228,7 +4230,7 @@ SendMenu::Details HistoryWidget::sendMenuDetails() const {
|
|||
|
||||
SendMenu::Details HistoryWidget::saveMenuDetails() const {
|
||||
return (_editMsgId && _replyEditMsg)
|
||||
? _mediaEditSpoiler.sendMenuDetails(HasSendText(_field))
|
||||
? _mediaEditManager.sendMenuDetails(HasSendText(_field))
|
||||
: SendMenu::Details();
|
||||
}
|
||||
|
||||
|
@ -5613,6 +5615,8 @@ bool HistoryWidget::confirmSendingFiles(
|
|||
{ _history->peer->id, _editMsgId },
|
||||
std::move(list),
|
||||
_field->getTextWithTags(),
|
||||
_mediaEditManager.spoilered(),
|
||||
_mediaEditManager.invertCaption(),
|
||||
crl::guard(_list, [=] { cancelEdit(); }));
|
||||
return true;
|
||||
}
|
||||
|
@ -6599,7 +6603,7 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
|||
if (_editMsgId
|
||||
&& (_inDetails || _inPhotoEdit)
|
||||
&& (e->button() == Qt::RightButton)) {
|
||||
_mediaEditSpoiler.showMenu(
|
||||
_mediaEditManager.showMenu(
|
||||
_list,
|
||||
[=] { mouseMoveEvent(nullptr); },
|
||||
HasSendText(_field));
|
||||
|
@ -6609,6 +6613,8 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
|||
_photoEditMedia,
|
||||
{ _history->peer->id, _editMsgId },
|
||||
_field->getTextWithTags(),
|
||||
_mediaEditManager.spoilered(),
|
||||
_mediaEditManager.invertCaption(),
|
||||
crl::guard(_list, [=] { cancelEdit(); }));
|
||||
} else if (!_inDetails) {
|
||||
return;
|
||||
|
@ -8186,7 +8192,7 @@ void HistoryWidget::updateReplyEditTexts(bool force) {
|
|||
? _replyEditMsg->media()
|
||||
: nullptr;
|
||||
if (_editMsgId && _replyEditMsg) {
|
||||
_mediaEditSpoiler.start(_replyEditMsg);
|
||||
_mediaEditManager.start(_replyEditMsg);
|
||||
}
|
||||
_canReplaceMedia = editMedia && editMedia->allowsEditMedia();
|
||||
_photoEditMedia = (_canReplaceMedia
|
||||
|
@ -8281,12 +8287,12 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
|||
? drawMsgText->media()
|
||||
: nullptr;
|
||||
const auto hasPreview = media && media->hasReplyPreview();
|
||||
const auto preview = _mediaEditSpoiler
|
||||
? _mediaEditSpoiler.mediaPreview()
|
||||
const auto preview = _mediaEditManager
|
||||
? _mediaEditManager.mediaPreview()
|
||||
: hasPreview
|
||||
? media->replyPreview()
|
||||
: nullptr;
|
||||
const auto spoilered = _mediaEditSpoiler.spoilered();
|
||||
const auto spoilered = _mediaEditManager.spoilered();
|
||||
if (!spoilered) {
|
||||
_replySpoiler = nullptr;
|
||||
} else if (!_replySpoiler) {
|
||||
|
|
|
@ -661,7 +661,7 @@ private:
|
|||
MsgId _editMsgId = 0;
|
||||
std::shared_ptr<Data::PhotoMedia> _photoEditMedia;
|
||||
bool _canReplaceMedia = false;
|
||||
HistoryView::MediaEditSpoilerManager _mediaEditSpoiler;
|
||||
HistoryView::MediaEditManager _mediaEditManager;
|
||||
|
||||
HistoryItem *_replyEditMsg = nullptr;
|
||||
Ui::Text::String _replyEditMsgText;
|
||||
|
|
|
@ -21,7 +21,7 @@ struct MessageToEdit {
|
|||
FullMsgId fullId;
|
||||
Api::SendOptions options;
|
||||
TextWithTags textWithTags;
|
||||
std::optional<bool> spoilerMediaOverride;
|
||||
bool spoilered = false;
|
||||
};
|
||||
struct VoiceToSend {
|
||||
QByteArray bytes;
|
||||
|
|
|
@ -216,7 +216,7 @@ private:
|
|||
bool _repaintScheduled : 1 = false;
|
||||
bool _inClickable : 1 = false;
|
||||
|
||||
HistoryView::MediaEditSpoilerManager _mediaEditSpoiler;
|
||||
HistoryView::MediaEditManager _mediaEditManager;
|
||||
|
||||
const not_null<Data::Session*> _data;
|
||||
const not_null<Ui::IconButton*> _cancel;
|
||||
|
@ -409,7 +409,7 @@ void FieldHeader::init() {
|
|||
}
|
||||
} else if (!isLeftButton) {
|
||||
if (inPreviewRect && isEditingMessage()) {
|
||||
_mediaEditSpoiler.showMenu(
|
||||
_mediaEditManager.showMenu(
|
||||
this,
|
||||
[=] { update(); },
|
||||
_hasSendText());
|
||||
|
@ -587,12 +587,12 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) {
|
|||
|
||||
const auto media = _shownMessage->media();
|
||||
_shownMessageHasPreview = media && media->hasReplyPreview();
|
||||
const auto preview = _mediaEditSpoiler
|
||||
? _mediaEditSpoiler.mediaPreview()
|
||||
const auto preview = _mediaEditManager
|
||||
? _mediaEditManager.mediaPreview()
|
||||
: _shownMessageHasPreview
|
||||
? media->replyPreview()
|
||||
: nullptr;
|
||||
const auto spoilered = _mediaEditSpoiler.spoilered();
|
||||
const auto spoilered = _mediaEditManager.spoilered();
|
||||
if (!spoilered) {
|
||||
_shownPreviewSpoiler = nullptr;
|
||||
} else if (!_shownPreviewSpoiler) {
|
||||
|
@ -737,7 +737,7 @@ void FieldHeader::editMessage(FullMsgId id, bool photoEditAllowed) {
|
|||
_photoEditAllowed = photoEditAllowed;
|
||||
_editMsgId = id;
|
||||
if (!photoEditAllowed) {
|
||||
_mediaEditSpoiler.cancel();
|
||||
_mediaEditManager.cancel();
|
||||
_inPhotoEdit = false;
|
||||
_inPhotoEditOver.stop();
|
||||
}
|
||||
|
@ -784,9 +784,9 @@ MessageToEdit FieldHeader::queryToEdit() {
|
|||
.options = {
|
||||
.scheduled = item->isScheduled() ? item->date() : 0,
|
||||
.shortcutId = item->shortcutId(),
|
||||
.invertCaption = _mediaEditSpoiler.invertCaption(),
|
||||
.invertCaption = _mediaEditManager.invertCaption(),
|
||||
},
|
||||
.spoilerMediaOverride = _mediaEditSpoiler.spoilered(),
|
||||
.spoilered = _mediaEditManager.spoilered(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1138,11 +1138,14 @@ bool ComposeControls::confirmMediaEdit(Ui::PreparedList &list) {
|
|||
if (!isEditingMessage() || !_regularWindow) {
|
||||
return false;
|
||||
} else if (_canReplaceMedia) {
|
||||
const auto queryToEdit = _header->queryToEdit();
|
||||
EditCaptionBox::StartMediaReplace(
|
||||
_regularWindow,
|
||||
_editingId,
|
||||
std::move(list),
|
||||
_field->getTextWithTags(),
|
||||
queryToEdit.spoilered,
|
||||
queryToEdit.options.invertCaption,
|
||||
crl::guard(_wrap.get(), [=] { cancelEditMessage(); }));
|
||||
} else {
|
||||
_show->showToast(tr::lng_edit_caption_attach(tr::now));
|
||||
|
@ -1401,11 +1404,14 @@ void ComposeControls::init() {
|
|||
|
||||
_header->editPhotoRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto queryToEdit = _header->queryToEdit();
|
||||
EditCaptionBox::StartPhotoEdit(
|
||||
_regularWindow,
|
||||
_photoEditMedia,
|
||||
_editingId,
|
||||
_field->getTextWithTags(),
|
||||
queryToEdit.spoilered,
|
||||
queryToEdit.options.invertCaption,
|
||||
crl::guard(_wrap.get(), [=] { cancelEditMessage(); }));
|
||||
}, _wrap->lifetime());
|
||||
|
||||
|
@ -2943,10 +2949,13 @@ bool ComposeControls::updateReplaceMediaButton() {
|
|||
const auto hideDuration = st::historyReplaceMedia.ripple.hideDuration;
|
||||
_replaceMedia->setClickedCallback([=] {
|
||||
base::call_delayed(hideDuration, _wrap.get(), [=] {
|
||||
const auto queryToEdit = _header->queryToEdit();
|
||||
EditCaptionBox::StartMediaReplace(
|
||||
_regularWindow,
|
||||
_editingId,
|
||||
_field->getTextWithTags(),
|
||||
queryToEdit.spoilered,
|
||||
queryToEdit.options.invertCaption,
|
||||
crl::guard(_wrap.get(), [=] { cancelEditMessage(); }));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -21,16 +21,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace HistoryView {
|
||||
|
||||
MediaEditSpoilerManager::MediaEditSpoilerManager() = default;
|
||||
MediaEditManager::MediaEditManager() = default;
|
||||
|
||||
void MediaEditSpoilerManager::start(not_null<HistoryItem*> item) {
|
||||
void MediaEditManager::start(
|
||||
not_null<HistoryItem*> item,
|
||||
std::optional<bool> spoilered,
|
||||
std::optional<bool> invertCaption) {
|
||||
const auto media = item->media();
|
||||
if (!media) {
|
||||
return;
|
||||
}
|
||||
_item = item;
|
||||
_spoilered = media->hasSpoiler();
|
||||
_invertCaption = item->invertMedia();
|
||||
_spoilered = spoilered.value_or(media->hasSpoiler());
|
||||
_invertCaption = invertCaption.value_or(item->invertMedia());
|
||||
_lifetime = item->history()->owner().itemRemoved(
|
||||
) | rpl::start_with_next([=](not_null<const HistoryItem*> removed) {
|
||||
if (removed == _item) {
|
||||
|
@ -39,7 +42,7 @@ void MediaEditSpoilerManager::start(not_null<HistoryItem*> item) {
|
|||
});
|
||||
}
|
||||
|
||||
void MediaEditSpoilerManager::apply(SendMenu::Action action) {
|
||||
void MediaEditManager::apply(SendMenu::Action action) {
|
||||
using Type = SendMenu::Action::Type;
|
||||
if (action.type == Type::CaptionUp) {
|
||||
_invertCaption = true;
|
||||
|
@ -52,13 +55,13 @@ void MediaEditSpoilerManager::apply(SendMenu::Action action) {
|
|||
}
|
||||
}
|
||||
|
||||
void MediaEditSpoilerManager::cancel() {
|
||||
void MediaEditManager::cancel() {
|
||||
_menu = nullptr;
|
||||
_item = nullptr;
|
||||
_lifetime.destroy();
|
||||
}
|
||||
|
||||
void MediaEditSpoilerManager::showMenu(
|
||||
void MediaEditManager::showMenu(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
Fn<void()> finished,
|
||||
bool hasCaptionText) {
|
||||
|
@ -88,7 +91,7 @@ void MediaEditSpoilerManager::showMenu(
|
|||
_menu->popup(position);
|
||||
}
|
||||
|
||||
[[nodiscard]] Image *MediaEditSpoilerManager::mediaPreview() {
|
||||
Image *MediaEditManager::mediaPreview() {
|
||||
if (const auto media = _item ? _item->media() : nullptr) {
|
||||
if (const auto photo = media->photo()) {
|
||||
return photo->getReplyPreview(
|
||||
|
@ -105,15 +108,15 @@ void MediaEditSpoilerManager::showMenu(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool MediaEditSpoilerManager::spoilered() const {
|
||||
bool MediaEditManager::spoilered() const {
|
||||
return _spoilered;
|
||||
}
|
||||
|
||||
bool MediaEditSpoilerManager::invertCaption() const {
|
||||
bool MediaEditManager::invertCaption() const {
|
||||
return _invertCaption;
|
||||
}
|
||||
|
||||
SendMenu::Details MediaEditSpoilerManager::sendMenuDetails(
|
||||
SendMenu::Details MediaEditManager::sendMenuDetails(
|
||||
bool hasCaptionText) const {
|
||||
const auto media = _item ? _item->media() : nullptr;
|
||||
if (!media) {
|
||||
|
@ -122,10 +125,12 @@ SendMenu::Details MediaEditSpoilerManager::sendMenuDetails(
|
|||
const auto editingMedia = media->allowsEditMedia();
|
||||
const auto editPhoto = editingMedia ? media->photo() : nullptr;
|
||||
const auto editDocument = editingMedia ? media->document() : nullptr;
|
||||
const auto canSaveSpoiler = (editPhoto && !editPhoto->isNull())
|
||||
|| (editDocument
|
||||
const auto canSaveSpoiler = CanBeSpoilered(_item);
|
||||
const auto canMoveCaption = media->allowsEditCaption()
|
||||
&& hasCaptionText
|
||||
&& (editPhoto
|
||||
|| editDocument
|
||||
&& (editDocument->isVideoFile() || editDocument->isGifv()));
|
||||
const auto canMoveCaption = media->allowsEditCaption() && hasCaptionText;
|
||||
return {
|
||||
.spoiler = (!canSaveSpoiler
|
||||
? SendMenu::SpoilerState::None
|
||||
|
@ -140,4 +145,14 @@ SendMenu::Details MediaEditSpoilerManager::sendMenuDetails(
|
|||
};
|
||||
}
|
||||
|
||||
bool MediaEditManager::CanBeSpoilered(not_null<HistoryItem*> item) {
|
||||
const auto media = item ? item->media() : nullptr;
|
||||
const auto editingMedia = media && media->allowsEditMedia();
|
||||
const auto editPhoto = editingMedia ? media->photo() : nullptr;
|
||||
const auto editDocument = editingMedia ? media->document() : nullptr;
|
||||
return (editPhoto && !editPhoto->isNull())
|
||||
|| (editDocument
|
||||
&& (editDocument->isVideoFile() || editDocument->isGifv()));
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -24,11 +24,14 @@ class HistoryItem;
|
|||
|
||||
namespace HistoryView {
|
||||
|
||||
class MediaEditSpoilerManager final {
|
||||
class MediaEditManager final {
|
||||
public:
|
||||
MediaEditSpoilerManager();
|
||||
MediaEditManager();
|
||||
|
||||
void start(not_null<HistoryItem*> item);
|
||||
void start(
|
||||
not_null<HistoryItem*> item,
|
||||
std::optional<bool> spoilered = {},
|
||||
std::optional<bool> invertCaption = {});
|
||||
void apply(SendMenu::Action action);
|
||||
void cancel();
|
||||
|
||||
|
@ -49,6 +52,8 @@ public:
|
|||
return _item != nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool CanBeSpoilered(not_null<HistoryItem*> item);
|
||||
|
||||
private:
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
HistoryItem *_item = nullptr;
|
||||
|
|
|
@ -740,7 +740,7 @@ void RepliesWidget::setupComposeControls() {
|
|||
_composeControls->editRequests(
|
||||
) | rpl::start_with_next([=](auto data) {
|
||||
if (const auto item = session().data().message(data.fullId)) {
|
||||
const auto spoiler = data.spoilerMediaOverride;
|
||||
const auto spoiler = data.spoilered;
|
||||
edit(item, data.options, saveEditMsgRequestId, spoiler);
|
||||
}
|
||||
}, lifetime());
|
||||
|
@ -1213,7 +1213,7 @@ void RepliesWidget::edit(
|
|||
not_null<HistoryItem*> item,
|
||||
Api::SendOptions options,
|
||||
mtpRequestId *const saveEditMsgRequestId,
|
||||
std::optional<bool> spoilerMediaOverride) {
|
||||
bool spoilered) {
|
||||
if (*saveEditMsgRequestId) {
|
||||
return;
|
||||
}
|
||||
|
@ -1282,7 +1282,7 @@ void RepliesWidget::edit(
|
|||
options,
|
||||
crl::guard(this, done),
|
||||
crl::guard(this, fail),
|
||||
spoilerMediaOverride);
|
||||
spoilered);
|
||||
|
||||
_composeControls->hidePanelsAnimated();
|
||||
doSetInnerFocus();
|
||||
|
|
|
@ -247,7 +247,7 @@ private:
|
|||
not_null<HistoryItem*> item,
|
||||
Api::SendOptions options,
|
||||
mtpRequestId *const saveEditMsgRequestId,
|
||||
std::optional<bool> spoilerMediaOverride);
|
||||
bool spoilered);
|
||||
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
|
||||
[[nodiscard]] SendMenu::Details sendMenuDetails() const;
|
||||
[[nodiscard]] FullReplyTo replyTo() const;
|
||||
|
|
|
@ -320,7 +320,7 @@ void ScheduledWidget::setupComposeControls() {
|
|||
) | rpl::start_with_next([=](auto data) {
|
||||
if (const auto item = session().data().message(data.fullId)) {
|
||||
if (item->isScheduled()) {
|
||||
const auto spoiler = data.spoilerMediaOverride;
|
||||
const auto spoiler = data.spoilered;
|
||||
edit(item, data.options, saveEditMsgRequestId, spoiler);
|
||||
}
|
||||
}
|
||||
|
@ -733,7 +733,7 @@ void ScheduledWidget::edit(
|
|||
not_null<HistoryItem*> item,
|
||||
Api::SendOptions options,
|
||||
mtpRequestId *const saveEditMsgRequestId,
|
||||
std::optional<bool> spoilerMediaOverride) {
|
||||
bool spoilered) {
|
||||
if (*saveEditMsgRequestId) {
|
||||
return;
|
||||
}
|
||||
|
@ -802,7 +802,7 @@ void ScheduledWidget::edit(
|
|||
options,
|
||||
crl::guard(this, done),
|
||||
crl::guard(this, fail),
|
||||
spoilerMediaOverride);
|
||||
spoilered);
|
||||
|
||||
_composeControls->hidePanelsAnimated();
|
||||
_composeControls->focus();
|
||||
|
|
|
@ -218,7 +218,7 @@ private:
|
|||
not_null<HistoryItem*> item,
|
||||
Api::SendOptions options,
|
||||
mtpRequestId *const saveEditMsgRequestId,
|
||||
std::optional<bool> spoilerMediaOverride);
|
||||
bool spoilered);
|
||||
void highlightSingleNewMessage(const Data::MessagesSlice &slice);
|
||||
void chooseAttach();
|
||||
[[nodiscard]] SendMenu::Details sendMenuDetails() const;
|
||||
|
|
|
@ -240,7 +240,7 @@ private:
|
|||
not_null<HistoryItem*> item,
|
||||
Api::SendOptions options,
|
||||
mtpRequestId *const saveEditMsgRequestId,
|
||||
std::optional<bool> spoilerMediaOverride);
|
||||
bool spoilered);
|
||||
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
|
||||
[[nodiscard]] FullReplyTo replyTo() const;
|
||||
void doSetInnerFocus();
|
||||
|
@ -675,7 +675,7 @@ void ShortcutMessages::setupComposeControls() {
|
|||
) | rpl::start_with_next([=](auto data) {
|
||||
if (const auto item = _session->data().message(data.fullId)) {
|
||||
if (item->isBusinessShortcut()) {
|
||||
const auto spoiler = data.spoilerMediaOverride;
|
||||
const auto spoiler = data.spoilered;
|
||||
edit(item, data.options, saveEditMsgRequestId, spoiler);
|
||||
}
|
||||
}
|
||||
|
@ -1221,7 +1221,7 @@ void ShortcutMessages::edit(
|
|||
not_null<HistoryItem*> item,
|
||||
Api::SendOptions options,
|
||||
mtpRequestId *const saveEditMsgRequestId,
|
||||
std::optional<bool> spoilerMediaOverride) {
|
||||
bool spoilered) {
|
||||
if (*saveEditMsgRequestId) {
|
||||
return;
|
||||
}
|
||||
|
@ -1290,7 +1290,7 @@ void ShortcutMessages::edit(
|
|||
options,
|
||||
crl::guard(this, done),
|
||||
crl::guard(this, fail),
|
||||
spoilerMediaOverride);
|
||||
spoilered);
|
||||
|
||||
_composeControls->hidePanelsAnimated();
|
||||
doSetInnerFocus();
|
||||
|
|
|
@ -78,6 +78,10 @@ bool AbstractSingleMediaPreview::canHaveSpoiler() const {
|
|||
return supportsSpoilers();
|
||||
}
|
||||
|
||||
rpl::producer<bool> AbstractSingleMediaPreview::spoileredChanges() const {
|
||||
return _spoileredChanges.events();
|
||||
}
|
||||
|
||||
void AbstractSingleMediaPreview::preparePreview(QImage preview) {
|
||||
auto maxW = 0;
|
||||
auto maxH = 0;
|
||||
|
@ -275,6 +279,7 @@ void AbstractSingleMediaPreview::showContextMenu(QPoint position) {
|
|||
? tr::lng_context_disable_spoiler(tr::now)
|
||||
: tr::lng_context_spoiler_effect(tr::now), [=] {
|
||||
setSpoiler(!spoilered);
|
||||
_spoileredChanges.fire_copy(!spoilered);
|
||||
}, spoilered ? &icons.menuSpoilerOff : &icons.menuSpoiler);
|
||||
|
||||
if (_menu->empty()) {
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
void setSpoiler(bool spoiler);
|
||||
[[nodiscard]] bool hasSpoiler() const;
|
||||
[[nodiscard]] bool canHaveSpoiler() const;
|
||||
[[nodiscard]] rpl::producer<bool> spoileredChanges() const;
|
||||
|
||||
protected:
|
||||
virtual bool supportsSpoilers() const = 0;
|
||||
|
@ -79,6 +80,7 @@ private:
|
|||
int _previewHeight = 0;
|
||||
|
||||
std::unique_ptr<SpoilerAnimation> _spoiler;
|
||||
rpl::event_stream<bool> _spoileredChanges;
|
||||
|
||||
const int _minThumbH;
|
||||
const base::unique_qptr<AttachControlsWidget> _controls;
|
||||
|
|
|
@ -237,6 +237,18 @@ bool PreparedList::hasSticker() const {
|
|||
return ranges::any_of(files, &PreparedFile::isSticker);
|
||||
}
|
||||
|
||||
bool PreparedList::hasSpoilerMenu(bool compress) const {
|
||||
const auto allAreVideo = !ranges::any_of(files, [](const auto &f) {
|
||||
using Type = Ui::PreparedFile::Type;
|
||||
return (f.type != Type::Video);
|
||||
});
|
||||
const auto allAreMedia = !ranges::any_of(files, [](const auto &f) {
|
||||
using Type = Ui::PreparedFile::Type;
|
||||
return (f.type != Type::Photo) && (f.type != Type::Video);
|
||||
});
|
||||
return allAreVideo || (allAreMedia && compress);
|
||||
}
|
||||
|
||||
int MaxAlbumItems() {
|
||||
return kMaxAlbumCount;
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ struct PreparedList {
|
|||
[[nodiscard]] bool hasSendImagesAsPhotosOption(bool slowmode) const;
|
||||
[[nodiscard]] bool canHaveEditorHintLabel() const;
|
||||
[[nodiscard]] bool hasSticker() const;
|
||||
[[nodiscard]] bool hasSpoilerMenu(bool compress) const;
|
||||
|
||||
Error error = Error::None;
|
||||
QString errorData;
|
||||
|
|
Loading…
Add table
Reference in a new issue