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