mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Added ability to hide under spoiler gif with caption on send.
Fixed #30126.
This commit is contained in:
@@ -35,6 +35,7 @@ struct SendOptions {
|
||||
bool handleSupportSwitch = false;
|
||||
bool invertCaption = false;
|
||||
bool hideViaBot = false;
|
||||
bool mediaSpoiler = false;
|
||||
crl::time ttlSeconds = 0;
|
||||
SuggestOptions suggest;
|
||||
|
||||
|
||||
@@ -247,6 +247,7 @@ void SendExistingMedia(
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
.mediaSpoiler = action.options.mediaSpoiler,
|
||||
}, media, caption);
|
||||
|
||||
const auto performRequest = [=](const auto &repeatRequest) -> void {
|
||||
@@ -302,7 +303,9 @@ void SendExistingDocument(
|
||||
std::optional<MsgId> localMessageId) {
|
||||
const auto inputMedia = [=] {
|
||||
return MTP_inputMediaDocument(
|
||||
MTP_flags(0),
|
||||
MTP_flags(message.action.options.mediaSpoiler
|
||||
? MTPDinputMediaDocument::Flag::f_spoiler
|
||||
: MTPDinputMediaDocument::Flags(0)),
|
||||
document->mtpInput(),
|
||||
MTPInputPhoto(), // video_cover
|
||||
MTPint(), // ttl_seconds
|
||||
|
||||
@@ -36,31 +36,39 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "menu/menu_send.h"
|
||||
#include "ui/controls/emoji_button.h"
|
||||
#include "ui/controls/emoji_button_factory.h"
|
||||
#include "ui/effects/spoiler_mess.h"
|
||||
#include "ui/image/image_prepare.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/text/text_entity.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
namespace Ui {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] not_null<Ui::RpWidget*> AddGifWidget(
|
||||
struct State final {
|
||||
std::shared_ptr<Data::DocumentMedia> mediaView;
|
||||
::Media::Clip::ReaderPointer gif;
|
||||
std::unique_ptr<Ui::SpoilerAnimation> spoiler;
|
||||
QImage firstFrame;
|
||||
QImage blurredFrame;
|
||||
bool hasSpoiler = false;
|
||||
rpl::lifetime loadingLifetime;
|
||||
};
|
||||
|
||||
[[nodiscard]] not_null<State*> AddGifWidget(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
not_null<DocumentData*> document,
|
||||
int width) {
|
||||
struct State final {
|
||||
std::shared_ptr<Data::DocumentMedia> mediaView;
|
||||
::Media::Clip::ReaderPointer gif;
|
||||
rpl::lifetime loadingLifetime;
|
||||
};
|
||||
|
||||
const auto state = container->lifetime().make_state<State>();
|
||||
state->mediaView = document->createMediaView();
|
||||
state->mediaView->automaticLoad(Data::FileOriginSavedGifs(), nullptr);
|
||||
@@ -75,9 +83,40 @@ namespace {
|
||||
std::numeric_limits<int>::max(),
|
||||
Qt::KeepAspectRatio).height()),
|
||||
st::boxRowPadding);
|
||||
widget->paintRequest(
|
||||
) | rpl::on_next([=] {
|
||||
auto p = QPainter(widget);
|
||||
widget->paintOn([=](QPainter &p) {
|
||||
if (state->hasSpoiler) {
|
||||
if (state->firstFrame.isNull()
|
||||
&& state->gif
|
||||
&& state->gif->ready()) {
|
||||
state->firstFrame = state->gif->current(
|
||||
{ .frame = widget->size() },
|
||||
crl::now());
|
||||
state->blurredFrame = Images::BlurLargeImage(
|
||||
base::duplicate(state->firstFrame),
|
||||
24);
|
||||
}
|
||||
if (!state->blurredFrame.isNull()) {
|
||||
p.drawImage(0, 0, state->blurredFrame);
|
||||
} else if (const auto thumb = state->mediaView->thumbnail()) {
|
||||
p.drawImage(
|
||||
widget->rect(),
|
||||
thumb->pixNoCache(
|
||||
widget->size() * style::DevicePixelRatio(),
|
||||
{
|
||||
.options = Images::Option::Blur,
|
||||
.outer = widget->size(),
|
||||
}).toImage());
|
||||
}
|
||||
if (!state->spoiler) {
|
||||
state->spoiler = std::make_unique<Ui::SpoilerAnimation>(
|
||||
[=] { widget->update(); });
|
||||
}
|
||||
const auto now = crl::now();
|
||||
const auto index = state->spoiler->index(now, false);
|
||||
const auto frame = Ui::DefaultImageSpoiler().frame(index);
|
||||
Ui::FillSpoilerRect(p, widget->rect(), frame);
|
||||
return;
|
||||
}
|
||||
if (state->gif && state->gif->started()) {
|
||||
p.drawImage(
|
||||
0,
|
||||
@@ -99,7 +138,7 @@ namespace {
|
||||
.outer = widget->size(),
|
||||
}).toImage());
|
||||
}
|
||||
}, widget->lifetime());
|
||||
});
|
||||
|
||||
const auto updateThumbnail = [=] {
|
||||
if (document->dimensions.isEmpty()) {
|
||||
@@ -130,7 +169,37 @@ namespace {
|
||||
}, state->loadingLifetime);
|
||||
}
|
||||
|
||||
return widget;
|
||||
base::install_event_filter(widget, [=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::ContextMenu) {
|
||||
const auto menu = Ui::CreateChild<Ui::PopupMenu>(
|
||||
widget,
|
||||
st::popupMenuWithIcons);
|
||||
menu->addAction(
|
||||
state->hasSpoiler
|
||||
? tr::lng_context_disable_spoiler(tr::now)
|
||||
: tr::lng_context_spoiler_effect(tr::now),
|
||||
[=] {
|
||||
state->hasSpoiler = !state->hasSpoiler;
|
||||
if (!state->hasSpoiler) {
|
||||
state->spoiler = nullptr;
|
||||
state->firstFrame = QImage();
|
||||
state->blurredFrame = QImage();
|
||||
if (state->gif && state->gif->ready()) {
|
||||
state->gif->start({ .frame = widget->size() });
|
||||
}
|
||||
}
|
||||
widget->update();
|
||||
},
|
||||
state->hasSpoiler
|
||||
? &st::menuIconSpoilerOff
|
||||
: &st::menuIconSpoiler);
|
||||
menu->popup(QCursor::pos());
|
||||
return base::EventFilterResult::Cancel;
|
||||
}
|
||||
return base::EventFilterResult::Continue;
|
||||
});
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
[[nodiscard]] not_null<Ui::InputField*> AddInputField(
|
||||
@@ -354,12 +423,16 @@ void SendGifWithCaptionBox(
|
||||
const SendMenu::Details &details,
|
||||
Fn<void(Api::SendOptions, TextWithTags)> c) {
|
||||
box->setTitle(tr::lng_send_gif_with_caption());
|
||||
[[maybe_unused]] const auto gifWidget = AddGifWidget(
|
||||
const auto state = AddGifWidget(
|
||||
box->verticalLayout(),
|
||||
document,
|
||||
st::boxWidth);
|
||||
Ui::AddSkip(box->verticalLayout());
|
||||
CaptionBox(box, tr::lng_send_button(), {}, peer, details, std::move(c));
|
||||
const auto d = [=](Api::SendOptions o, TextWithTags t) {
|
||||
o.mediaSpoiler = state->hasSpoiler;
|
||||
c(std::move(o), std::move(t));
|
||||
};
|
||||
CaptionBox(box, tr::lng_send_button(), {}, peer, details, std::move(d));
|
||||
}
|
||||
|
||||
void EditCaptionBox(
|
||||
|
||||
@@ -518,7 +518,8 @@ void GifsListWidget::selectInlineResult(
|
||||
|| (media && media->image(PhotoSize::Large))) {
|
||||
_photoChosen.fire({
|
||||
.photo = photo,
|
||||
.options = options });
|
||||
.options = options
|
||||
});
|
||||
} else if (!photo->loading(PhotoSize::Thumbnail)) {
|
||||
photo->load(PhotoSize::Thumbnail, Data::FileOrigin());
|
||||
}
|
||||
|
||||
@@ -698,6 +698,7 @@ HistoryItem::HistoryItem(
|
||||
_media = std::make_unique<Data::MediaFile>(this, document, Args{
|
||||
.hasQualitiesList = video && !video->qualities.empty(),
|
||||
.skipPremiumEffect = !history->session().premium(),
|
||||
.spoiler = fields.mediaSpoiler,
|
||||
});
|
||||
setText(caption);
|
||||
}
|
||||
@@ -710,7 +711,7 @@ HistoryItem::HistoryItem(
|
||||
: HistoryItem(history, fields) {
|
||||
createComponentsHelper(std::move(fields));
|
||||
|
||||
const auto spoiler = false;
|
||||
const auto spoiler = fields.mediaSpoiler;
|
||||
_media = std::make_unique<Data::MediaPhoto>(this, photo, spoiler);
|
||||
setText(caption);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ struct HistoryItemCommonFields {
|
||||
HistoryMessageSuggestInfo suggest;
|
||||
bool ignoreForwardFrom = false;
|
||||
bool ignoreForwardCaptions = false;
|
||||
bool mediaSpoiler = false;
|
||||
};
|
||||
|
||||
enum class HistoryReactionSource : char {
|
||||
|
||||
Reference in New Issue
Block a user