Implement full theming of attachments in stories.
This commit is contained in:
parent
ae4d660c38
commit
2c5d990e1c
|
@ -344,11 +344,6 @@ autoDownloadLimitSlider: MediaSlider(defaultContinuousSlider) {
|
|||
}
|
||||
autoDownloadLimitPadding: margins(22px, 8px, 22px, 8px);
|
||||
|
||||
confirmCaptionArea: InputField(defaultInputField) {
|
||||
textMargins: margins(1px, 26px, 31px, 4px);
|
||||
heightMax: 158px;
|
||||
}
|
||||
confirmBg: windowBgOver;
|
||||
confirmMaxHeight: 245px;
|
||||
|
||||
supportInfoField: InputField(defaultInputField) {
|
||||
|
@ -391,51 +386,11 @@ sendMediaPreviewSize: 308px;
|
|||
sendMediaPreviewHeightMax: 1280;
|
||||
sendMediaRowSkip: 10px;
|
||||
|
||||
editMediaButtonSize: 32px;
|
||||
|
||||
editMediaButtonIconFile: icon {{ "send_media/send_media_replace", menuIconFg }};
|
||||
editMediaButton: IconButton(defaultIconButton) {
|
||||
width: editMediaButtonSize;
|
||||
height: editMediaButtonSize;
|
||||
|
||||
icon: editMediaButtonIconFile;
|
||||
|
||||
rippleAreaSize: editMediaButtonSize;
|
||||
ripple: defaultRippleAnimation;
|
||||
}
|
||||
|
||||
editMediaHintLabel: FlatLabel(defaultFlatLabel) {
|
||||
textFg: windowSubTextFg;
|
||||
minWidth: sendMediaPreviewSize;
|
||||
}
|
||||
|
||||
// SendFilesBox
|
||||
|
||||
sendBoxAlbumGroupEditInternalSkip: 8px;
|
||||
sendBoxAlbumGroupSkipRight: 5px;
|
||||
sendBoxAlbumGroupSkipTop: 5px;
|
||||
sendBoxAlbumGroupRadius: 4px;
|
||||
sendBoxAlbumGroupSize: size(62px, 25px);
|
||||
sendBoxAlbumSmallGroupSize: size(30px, 25px);
|
||||
|
||||
sendBoxFileGroupSkipTop: 2px;
|
||||
sendBoxFileGroupSkipRight: 5px;
|
||||
sendBoxFileGroupEditInternalSkip: -1px;
|
||||
|
||||
sendBoxAlbumGroupButtonFile: IconButton(editMediaButton) {
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgRipple;
|
||||
}
|
||||
}
|
||||
sendBoxAlbumGroupEditButtonIconFile: editMediaButtonIconFile;
|
||||
sendBoxAlbumGroupDeleteButtonIconFile: icon {{ "send_media/send_media_delete", menuIconFg }};
|
||||
|
||||
sendBoxAlbumButtonMediaEdit: icon {{ "send_media/send_media_replace", roundedFg }};
|
||||
sendBoxAlbumGroupButtonMediaEdit: icon {{ "send_media/send_media_replace", roundedFg, point(4px, 1px) }};
|
||||
sendBoxAlbumGroupButtonMediaDelete: icon {{ "send_media/send_media_delete", roundedFg }};
|
||||
|
||||
// End of SendFilesBox
|
||||
|
||||
calendarTitleHeight: boxTitleHeight;
|
||||
calendarPrevious: IconButton {
|
||||
width: calendarTitleHeight;
|
||||
|
|
|
@ -246,12 +246,12 @@ EditCaptionBox::EditCaptionBox(
|
|||
, _scroll(base::make_unique_q<Ui::ScrollArea>(this, st::boxScroll))
|
||||
, _field(base::make_unique_q<Ui::InputField>(
|
||||
this,
|
||||
st::confirmCaptionArea,
|
||||
st::defaultComposeFiles.caption,
|
||||
Ui::InputField::Mode::MultiLine,
|
||||
tr::lng_photo_caption()))
|
||||
, _emojiToggle(base::make_unique_q<Ui::EmojiButton>(
|
||||
this,
|
||||
st::boxAttachEmoji))
|
||||
st::defaultComposeFiles.emoji))
|
||||
, _initialText(std::move(text))
|
||||
, _initialList(std::move(list))
|
||||
, _saved(std::move(saved)) {
|
||||
|
@ -402,6 +402,7 @@ void EditCaptionBox::rebuildPreview() {
|
|||
if (photo || document->isVideoFile() || document->isAnimation()) {
|
||||
const auto media = Ui::CreateChild<Ui::ItemSingleMediaPreview>(
|
||||
this,
|
||||
st::defaultComposeControls,
|
||||
gifPaused,
|
||||
_historyItem,
|
||||
Ui::AttachControls::Type::EditOnly);
|
||||
|
@ -410,6 +411,7 @@ void EditCaptionBox::rebuildPreview() {
|
|||
} else {
|
||||
_content.reset(Ui::CreateChild<Ui::ItemSingleFilePreview>(
|
||||
this,
|
||||
st::defaultComposeControls,
|
||||
_historyItem,
|
||||
Ui::AttachControls::Type::EditOnly));
|
||||
}
|
||||
|
@ -418,6 +420,7 @@ void EditCaptionBox::rebuildPreview() {
|
|||
|
||||
const auto media = Ui::SingleMediaPreview::Create(
|
||||
this,
|
||||
st::defaultComposeControls,
|
||||
gifPaused,
|
||||
file,
|
||||
Ui::AttachControls::Type::EditOnly);
|
||||
|
@ -429,6 +432,7 @@ void EditCaptionBox::rebuildPreview() {
|
|||
} else {
|
||||
_content.reset(Ui::CreateChild<Ui::SingleFilePreview>(
|
||||
this,
|
||||
st::defaultComposeControls,
|
||||
file,
|
||||
Ui::AttachControls::Type::EditOnly));
|
||||
}
|
||||
|
@ -482,7 +486,7 @@ void EditCaptionBox::setupField() {
|
|||
|
||||
_field->setSubmitSettings(
|
||||
Core::App().settings().sendSubmitWay());
|
||||
_field->setMaxHeight(st::confirmCaptionArea.heightMax);
|
||||
_field->setMaxHeight(st::defaultComposeFiles.caption.heightMax);
|
||||
|
||||
connect(_field, &Ui::InputField::submitted, [=] { save(); });
|
||||
connect(_field, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
|
@ -596,7 +600,7 @@ void EditCaptionBox::setupPhotoEditorEventHandler() {
|
|||
if (!_preparedList.files.empty()) {
|
||||
Editor::OpenWithPreparedFile(
|
||||
this,
|
||||
controller,
|
||||
controller->uiShow(),
|
||||
&_preparedList.files.front(),
|
||||
st::sendMediaPreviewSize,
|
||||
[=] { rebuildPreview(); });
|
||||
|
@ -845,7 +849,8 @@ bool EditCaptionBox::validateLength(const QString &text) const {
|
|||
if (remove <= 0) {
|
||||
return true;
|
||||
}
|
||||
_controller->show(Box(CaptionLimitReachedBox, session, remove));
|
||||
_controller->show(
|
||||
Box(CaptionLimitReachedBox, session, remove, nullptr));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -404,6 +404,7 @@ std::unique_ptr<PeerListRow> PublicsController::createRow(
|
|||
|
||||
void SimpleLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
const style::PremiumLimits *stOverride,
|
||||
not_null<Main::Session*> session,
|
||||
bool premiumPossible,
|
||||
rpl::producer<QString> title,
|
||||
|
@ -411,6 +412,8 @@ void SimpleLimitBox(
|
|||
const QString &refAddition,
|
||||
const InfographicDescriptor &descriptor,
|
||||
bool fixed = false) {
|
||||
const auto &st = stOverride ? *stOverride : st::defaultPremiumLimits;
|
||||
|
||||
box->setWidth(st::boxWideWidth);
|
||||
|
||||
const auto top = fixed
|
||||
|
@ -431,6 +434,7 @@ void SimpleLimitBox(
|
|||
if (premiumPossible) {
|
||||
Ui::Premium::AddLimitRow(
|
||||
top,
|
||||
st,
|
||||
descriptor.premiumLimit,
|
||||
descriptor.phrase,
|
||||
0,
|
||||
|
@ -473,6 +477,7 @@ void SimpleLimitBox(
|
|||
|
||||
void SimpleLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
const style::PremiumLimits *stOverride,
|
||||
not_null<Main::Session*> session,
|
||||
rpl::producer<QString> title,
|
||||
rpl::producer<TextWithEntities> text,
|
||||
|
@ -481,6 +486,7 @@ void SimpleLimitBox(
|
|||
bool fixed = false) {
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
stOverride,
|
||||
session,
|
||||
session->premiumPossible(),
|
||||
std::move(title),
|
||||
|
@ -524,6 +530,7 @@ void SimplePinsLimitBox(
|
|||
});
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
nullptr,
|
||||
session,
|
||||
tr::lng_filter_pin_limit_title(),
|
||||
std::move(text),
|
||||
|
@ -561,6 +568,7 @@ void ChannelsLimitBox(
|
|||
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
nullptr,
|
||||
session,
|
||||
tr::lng_channels_limit_title(),
|
||||
std::move(text),
|
||||
|
@ -650,6 +658,7 @@ void PublicLinksLimitBox(
|
|||
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
nullptr,
|
||||
session,
|
||||
tr::lng_links_limit_title(),
|
||||
std::move(text),
|
||||
|
@ -716,6 +725,7 @@ void FilterChatsLimitBox(
|
|||
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
nullptr,
|
||||
session,
|
||||
tr::lng_filter_chats_limit_title(),
|
||||
std::move(text),
|
||||
|
@ -753,6 +763,7 @@ void FilterLinksLimitBox(
|
|||
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
nullptr,
|
||||
session,
|
||||
tr::lng_filter_links_limit_title(),
|
||||
std::move(text),
|
||||
|
@ -798,6 +809,7 @@ void FiltersLimitBox(
|
|||
});
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
nullptr,
|
||||
session,
|
||||
tr::lng_filters_limit_title(),
|
||||
std::move(text),
|
||||
|
@ -836,6 +848,7 @@ void ShareableFiltersLimitBox(
|
|||
});
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
nullptr,
|
||||
session,
|
||||
tr::lng_filter_shared_limit_title(),
|
||||
std::move(text),
|
||||
|
@ -900,6 +913,7 @@ void ForumPinsLimitBox(
|
|||
Ui::Text::RichLangValue);
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
nullptr,
|
||||
&forum->session(),
|
||||
false,
|
||||
tr::lng_filter_pin_limit_title(),
|
||||
|
@ -911,7 +925,8 @@ void ForumPinsLimitBox(
|
|||
void CaptionLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session,
|
||||
int remove) {
|
||||
int remove,
|
||||
const style::PremiumLimits *stOverride) {
|
||||
const auto premium = session->premium();
|
||||
const auto premiumPossible = session->premiumPossible();
|
||||
|
||||
|
@ -943,6 +958,7 @@ void CaptionLimitBox(
|
|||
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
stOverride,
|
||||
session,
|
||||
tr::lng_caption_limit_title(),
|
||||
std::move(text),
|
||||
|
@ -953,15 +969,17 @@ void CaptionLimitBox(
|
|||
void CaptionLimitReachedBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session,
|
||||
int remove) {
|
||||
int remove,
|
||||
const style::PremiumLimits *stOverride) {
|
||||
Ui::ConfirmBox(box, Ui::ConfirmBoxArgs{
|
||||
.text = tr::lng_caption_limit_reached(tr::now, lt_count, remove),
|
||||
.labelStyle = stOverride ? &stOverride->boxLabel : nullptr,
|
||||
.inform = true,
|
||||
});
|
||||
if (!session->premium()) {
|
||||
box->addLeftButton(tr::lng_limits_increase(), [=] {
|
||||
box->getDelegate()->showBox(
|
||||
Box(CaptionLimitBox, session, remove),
|
||||
Box(CaptionLimitBox, session, remove, stOverride),
|
||||
Ui::LayerOption::KeepOther,
|
||||
anim::type::normal);
|
||||
box->closeBox();
|
||||
|
@ -972,7 +990,8 @@ void CaptionLimitReachedBox(
|
|||
void FileSizeLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session,
|
||||
uint64 fileSizeBytes) {
|
||||
uint64 fileSizeBytes,
|
||||
const style::PremiumLimits *stOverride) {
|
||||
const auto limits = Data::PremiumLimits(session);
|
||||
const auto defaultLimit = float64(limits.uploadMaxDefault());
|
||||
const auto premiumLimit = float64(limits.uploadMaxPremium());
|
||||
|
@ -1011,6 +1030,7 @@ void FileSizeLimitBox(
|
|||
|
||||
SimpleLimitBox(
|
||||
box,
|
||||
stOverride,
|
||||
session,
|
||||
premiumPossible,
|
||||
tr::lng_file_size_limit_title(),
|
||||
|
@ -1084,6 +1104,7 @@ void AccountsLimitBox(
|
|||
if (premiumPossible) {
|
||||
Ui::Premium::AddLimitRow(
|
||||
top,
|
||||
st::defaultPremiumLimits,
|
||||
(QString::number(std::max(current, defaultLimit) + 1)
|
||||
+ ((current + 1 == premiumLimit) ? "" : "+")),
|
||||
QString::number(defaultLimit));
|
||||
|
|
|
@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "ui/layers/generic_box.h"
|
||||
|
||||
namespace style {
|
||||
struct PremiumLimits;
|
||||
} // namespace style
|
||||
|
||||
namespace Data {
|
||||
class Forum;
|
||||
} // namespace Data
|
||||
|
@ -57,15 +61,18 @@ void ForumPinsLimitBox(
|
|||
void CaptionLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session,
|
||||
int remove);
|
||||
int remove,
|
||||
const style::PremiumLimits *stOverride = nullptr);
|
||||
void CaptionLimitReachedBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session,
|
||||
int remove);
|
||||
int remove,
|
||||
const style::PremiumLimits *stOverride = nullptr);
|
||||
void FileSizeLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session,
|
||||
uint64 fileSizeBytes);
|
||||
uint64 fileSizeBytes,
|
||||
const style::PremiumLimits *stOverride = nullptr);
|
||||
void AccountsLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session);
|
||||
|
|
|
@ -76,7 +76,7 @@ bool operator==(const Descriptor &a, const Descriptor &b) {
|
|||
struct Preload {
|
||||
Descriptor descriptor;
|
||||
std::shared_ptr<Data::DocumentMedia> media;
|
||||
base::weak_ptr<Window::SessionController> controller;
|
||||
std::weak_ptr<ChatHelpers::Show> show;
|
||||
};
|
||||
|
||||
[[nodiscard]] std::vector<Preload> &Preloads() {
|
||||
|
@ -168,7 +168,7 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
|
||||
[[nodiscard]] not_null<Ui::RpWidget*> StickerPreview(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
const std::shared_ptr<Data::DocumentMedia> &media,
|
||||
Fn<void()> readyCallback = nullptr) {
|
||||
using namespace HistoryView;
|
||||
|
@ -194,6 +194,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
struct State {
|
||||
std::unique_ptr<Lottie::SinglePlayer> lottie;
|
||||
std::unique_ptr<Lottie::SinglePlayer> effect;
|
||||
style::owned_color pathFg = style::owned_color(
|
||||
QColor(255, 255, 255, 64));
|
||||
std::unique_ptr<Ui::PathShiftGradient> pathGradient;
|
||||
bool readyInvoked = false;
|
||||
};
|
||||
|
@ -239,15 +241,17 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
};
|
||||
createLottieIfReady();
|
||||
if (!state->lottie || !state->effect) {
|
||||
controller->session().downloaderTaskFinished(
|
||||
show->session().downloaderTaskFinished(
|
||||
) | rpl::take_while([=] {
|
||||
createLottieIfReady();
|
||||
return !state->lottie || !state->effect;
|
||||
}) | rpl::start(result->lifetime());
|
||||
}
|
||||
state->pathGradient = MakePathShiftGradient(
|
||||
controller->chatStyle(),
|
||||
[=] { result->update(); });
|
||||
state->pathGradient = std::make_unique<Ui::PathShiftGradient>(
|
||||
st::shadowFg,
|
||||
state->pathFg.color(),
|
||||
[=] { result->update(); },
|
||||
rpl::never<>());
|
||||
|
||||
result->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
|
@ -262,7 +266,7 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
if (!state->lottie
|
||||
|| !state->lottie->ready()
|
||||
|| !state->effect->ready()) {
|
||||
p.setBrush(controller->chatStyle()->msgServiceBg());
|
||||
p.setBrush(st::shadowFg);
|
||||
ChatHelpers::PaintStickerThumbnailPath(
|
||||
p,
|
||||
media.get(),
|
||||
|
@ -302,7 +306,7 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
|
||||
[[nodiscard]] not_null<Ui::RpWidget*> StickersPreview(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
Fn<void()> readyCallback) {
|
||||
const auto result = Ui::CreateChild<Ui::RpWidget>(parent.get());
|
||||
result->show();
|
||||
|
@ -327,7 +331,7 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
bool nextReady = false;
|
||||
int index = 0;
|
||||
};
|
||||
const auto premium = &controller->session().api().premium();
|
||||
const auto premium = &show->session().api().premium();
|
||||
const auto state = lifetime.make_state<State>();
|
||||
const auto create = [=](std::shared_ptr<Data::DocumentMedia> media) {
|
||||
const auto outer = Ui::CreateChild<Ui::RpWidget>(result);
|
||||
|
@ -340,7 +344,7 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
|
||||
[[maybe_unused]] const auto sticker = StickerPreview(
|
||||
outer,
|
||||
controller,
|
||||
show,
|
||||
media,
|
||||
state->singleReadyCallback);
|
||||
|
||||
|
@ -520,7 +524,7 @@ struct VideoPreviewDocument {
|
|||
|
||||
[[nodiscard]] not_null<Ui::RpWidget*> VideoPreview(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<DocumentData*> document,
|
||||
bool alignToBottom,
|
||||
Fn<void()> readyCallback) {
|
||||
|
@ -683,7 +687,7 @@ struct VideoPreviewDocument {
|
|||
|
||||
[[nodiscard]] not_null<Ui::RpWidget*> GenericPreview(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
PremiumPreview section,
|
||||
Fn<void()> readyCallback) {
|
||||
const auto result = Ui::CreateChild<Ui::RpWidget>(parent.get());
|
||||
|
@ -699,7 +703,7 @@ struct VideoPreviewDocument {
|
|||
std::vector<std::shared_ptr<Data::DocumentMedia>> medias;
|
||||
Ui::RpWidget *single = nullptr;
|
||||
};
|
||||
const auto session = &controller->session();
|
||||
const auto session = &show->session();
|
||||
const auto state = lifetime.make_state<State>();
|
||||
const auto create = [=] {
|
||||
const auto document = LookupVideo(session, section);
|
||||
|
@ -708,7 +712,7 @@ struct VideoPreviewDocument {
|
|||
}
|
||||
state->single = VideoPreview(
|
||||
result,
|
||||
controller,
|
||||
show,
|
||||
document,
|
||||
!VideoAlignToTop(section),
|
||||
readyCallback);
|
||||
|
@ -724,14 +728,18 @@ struct VideoPreviewDocument {
|
|||
|
||||
[[nodiscard]] not_null<Ui::RpWidget*> GenerateDefaultPreview(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
PremiumPreview section,
|
||||
Fn<void()> readyCallback) {
|
||||
switch (section) {
|
||||
case PremiumPreview::Stickers:
|
||||
return StickersPreview(parent, controller, readyCallback);
|
||||
return StickersPreview(parent, std::move(show), readyCallback);
|
||||
default:
|
||||
return GenericPreview(parent, controller, section, readyCallback);
|
||||
return GenericPreview(
|
||||
parent,
|
||||
std::move(show),
|
||||
section,
|
||||
readyCallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -792,7 +800,7 @@ struct VideoPreviewDocument {
|
|||
|
||||
void PreviewBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
const Descriptor &descriptor,
|
||||
const std::shared_ptr<Data::DocumentMedia> &media,
|
||||
const QImage &back) {
|
||||
|
@ -825,7 +833,7 @@ void PreviewBox(
|
|||
};
|
||||
const auto state = outer->lifetime().make_state<State>();
|
||||
state->selected = descriptor.section;
|
||||
state->order = Settings::PremiumPreviewOrder(&controller->session());
|
||||
state->order = Settings::PremiumPreviewOrder(&show->session());
|
||||
|
||||
const auto index = [=](PremiumPreview section) {
|
||||
const auto it = ranges::find(state->order, section);
|
||||
|
@ -880,7 +888,7 @@ void PreviewBox(
|
|||
};
|
||||
state->stickersPreload = GenerateDefaultPreview(
|
||||
outer,
|
||||
controller,
|
||||
show,
|
||||
PremiumPreview::Stickers,
|
||||
ready);
|
||||
state->stickersPreload->hide();
|
||||
|
@ -890,13 +898,13 @@ void PreviewBox(
|
|||
switch (descriptor.section) {
|
||||
case PremiumPreview::Stickers:
|
||||
state->content = media
|
||||
? StickerPreview(outer, controller, media, state->preload)
|
||||
: StickersPreview(outer, controller, state->preload);
|
||||
? StickerPreview(outer, show, media, state->preload)
|
||||
: StickersPreview(outer, show, state->preload);
|
||||
break;
|
||||
default:
|
||||
state->content = GenericPreview(
|
||||
outer,
|
||||
controller,
|
||||
show,
|
||||
descriptor.section,
|
||||
state->preload);
|
||||
break;
|
||||
|
@ -955,7 +963,7 @@ void PreviewBox(
|
|||
} else {
|
||||
state->content = GenerateDefaultPreview(
|
||||
outer,
|
||||
controller,
|
||||
show,
|
||||
now,
|
||||
state->preload);
|
||||
}
|
||||
|
@ -1003,7 +1011,7 @@ void PreviewBox(
|
|||
state->preload();
|
||||
}
|
||||
};
|
||||
if (descriptor.fromSettings && controller->session().premium()) {
|
||||
if (descriptor.fromSettings && show->session().premium()) {
|
||||
box->setShowFinishedCallback(showFinished);
|
||||
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
|
||||
} else {
|
||||
|
@ -1030,16 +1038,21 @@ void PreviewBox(
|
|||
auto button = descriptor.fromSettings
|
||||
? object_ptr<Ui::GradientButton>::fromRaw(
|
||||
Settings::CreateSubscribeButton({
|
||||
controller,
|
||||
box,
|
||||
computeRef,
|
||||
.parent = box,
|
||||
.computeRef = computeRef,
|
||||
.show = show,
|
||||
}))
|
||||
: CreateUnlockButton(box, std::move(unlock));
|
||||
button->resizeToWidth(width);
|
||||
if (!descriptor.fromSettings) {
|
||||
button->setClickedCallback([=] {
|
||||
const auto window = show->resolveWindow(
|
||||
ChatHelpers::WindowUsage::PremiumPromo);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
Settings::ShowPremium(
|
||||
controller,
|
||||
window,
|
||||
Settings::LookupPremiumRef(state->selected.current()));
|
||||
});
|
||||
}
|
||||
|
@ -1052,7 +1065,7 @@ void PreviewBox(
|
|||
|
||||
if (descriptor.fromSettings) {
|
||||
Data::AmPremiumValue(
|
||||
&controller->session()
|
||||
&show->session()
|
||||
) | rpl::skip(1) | rpl::start_with_next([=] {
|
||||
box->closeBox();
|
||||
}, box->lifetime());
|
||||
|
@ -1076,25 +1089,26 @@ void PreviewBox(
|
|||
}
|
||||
|
||||
void Show(
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
const Descriptor &descriptor,
|
||||
const std::shared_ptr<Data::DocumentMedia> &media,
|
||||
QImage back) {
|
||||
const auto box = controller->show(
|
||||
Box(PreviewBox, controller, descriptor, media, back));
|
||||
auto box = Box(PreviewBox, show, descriptor, media, back);
|
||||
const auto raw = box.data();
|
||||
show->showBox(std::move(box));
|
||||
if (descriptor.shownCallback) {
|
||||
descriptor.shownCallback(box);
|
||||
descriptor.shownCallback(raw);
|
||||
}
|
||||
}
|
||||
|
||||
void Show(not_null<Window::SessionController*> controller, QImage back) {
|
||||
void Show(std::shared_ptr<ChatHelpers::Show> show, QImage back) {
|
||||
auto &list = Preloads();
|
||||
for (auto i = begin(list); i != end(list);) {
|
||||
const auto already = i->controller.get();
|
||||
const auto already = i->show.lock();
|
||||
if (!already) {
|
||||
i = list.erase(i);
|
||||
} else if (already == controller) {
|
||||
Show(controller, i->descriptor, i->media, back);
|
||||
} else if (already == show) {
|
||||
Show(std::move(show), i->descriptor, i->media, back);
|
||||
i = list.erase(i);
|
||||
return;
|
||||
} else {
|
||||
|
@ -1104,21 +1118,23 @@ void Show(not_null<Window::SessionController*> controller, QImage back) {
|
|||
}
|
||||
|
||||
void Show(
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
Descriptor &&descriptor) {
|
||||
if (!controller->session().premiumPossible()) {
|
||||
const auto box = controller->show(Box(PremiumUnavailableBox));
|
||||
if (!show->session().premiumPossible()) {
|
||||
auto box = Box(PremiumUnavailableBox);
|
||||
const auto raw = box.data();
|
||||
show->showBox(std::move(box));
|
||||
if (descriptor.shownCallback) {
|
||||
descriptor.shownCallback(box);
|
||||
descriptor.shownCallback(raw);
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto &list = Preloads();
|
||||
for (auto i = begin(list); i != end(list);) {
|
||||
const auto already = i->controller.get();
|
||||
const auto already = i->show.lock();
|
||||
if (!already) {
|
||||
i = list.erase(i);
|
||||
} else if (already == controller) {
|
||||
} else if (already == show) {
|
||||
if (i->descriptor == descriptor) {
|
||||
return;
|
||||
}
|
||||
|
@ -1135,13 +1151,13 @@ void Show(
|
|||
}
|
||||
}
|
||||
|
||||
const auto weak = base::make_weak(controller);
|
||||
const auto weak = std::weak_ptr(show);
|
||||
list.push_back({
|
||||
.descriptor = descriptor,
|
||||
.media = (descriptor.requestedSticker
|
||||
? descriptor.requestedSticker->createMediaView()
|
||||
: nullptr),
|
||||
.controller = weak,
|
||||
.show = weak,
|
||||
});
|
||||
if (const auto &media = list.back().media) {
|
||||
PreloadSticker(media);
|
||||
|
@ -1166,8 +1182,8 @@ void Show(
|
|||
Images::CornersMask(st::boxRadius),
|
||||
RectPart::TopLeft | RectPart::TopRight);
|
||||
crl::on_main([=] {
|
||||
if (const auto strong = weak.get()) {
|
||||
Show(strong, result);
|
||||
if (auto strong = weak.lock()) {
|
||||
Show(std::move(strong), result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -1178,7 +1194,7 @@ void Show(
|
|||
void ShowStickerPreviewBox(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<DocumentData*> document) {
|
||||
Show(controller, Descriptor{
|
||||
Show(controller->uiShow(), Descriptor{
|
||||
.section = PremiumPreview::Stickers,
|
||||
.requestedSticker = document,
|
||||
});
|
||||
|
@ -1188,7 +1204,14 @@ void ShowPremiumPreviewBox(
|
|||
not_null<Window::SessionController*> controller,
|
||||
PremiumPreview section,
|
||||
Fn<void(not_null<Ui::BoxContent*>)> shown) {
|
||||
Show(controller, Descriptor{
|
||||
ShowPremiumPreviewBox(controller->uiShow(), section, std::move(shown));
|
||||
}
|
||||
|
||||
void ShowPremiumPreviewBox(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
PremiumPreview section,
|
||||
Fn<void(not_null<Ui::BoxContent*>)> shown) {
|
||||
Show(std::move(show), Descriptor{
|
||||
.section = section,
|
||||
.shownCallback = std::move(shown),
|
||||
});
|
||||
|
@ -1198,7 +1221,7 @@ void ShowPremiumPreviewToBuy(
|
|||
not_null<Window::SessionController*> controller,
|
||||
PremiumPreview section,
|
||||
Fn<void()> hiddenCallback) {
|
||||
Show(controller, Descriptor{
|
||||
Show(controller->uiShow(), Descriptor{
|
||||
.section = section,
|
||||
.fromSettings = true,
|
||||
.hiddenCallback = std::move(hiddenCallback),
|
||||
|
@ -1337,7 +1360,10 @@ void DoubledLimitsPreviewBox(
|
|||
Main::Domain::kPremiumMaxAccounts,
|
||||
till,
|
||||
});
|
||||
Ui::Premium::ShowListBox(box, std::move(entries));
|
||||
Ui::Premium::ShowListBox(
|
||||
box,
|
||||
st::defaultPremiumLimits,
|
||||
std::move(entries));
|
||||
}
|
||||
|
||||
object_ptr<Ui::GradientButton> CreateUnlockButton(
|
||||
|
|
|
@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
class DocumentData;
|
||||
|
||||
namespace ChatHelpers {
|
||||
class Show;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Data {
|
||||
struct ReactionId;
|
||||
} // namespace Data
|
||||
|
@ -59,6 +63,11 @@ void ShowPremiumPreviewBox(
|
|||
PremiumPreview section,
|
||||
Fn<void(not_null<Ui::BoxContent*>)> shown = nullptr);
|
||||
|
||||
void ShowPremiumPreviewBox(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
PremiumPreview section,
|
||||
Fn<void(not_null<Ui::BoxContent*>)> shown = nullptr);
|
||||
|
||||
void ShowPremiumPreviewToBuy(
|
||||
not_null<Window::SessionController*> controller,
|
||||
PremiumPreview section,
|
||||
|
|
|
@ -137,13 +137,19 @@ SendFilesLimits DefaultLimitsForPeer(not_null<PeerData*> peer) {
|
|||
SendFilesCheck DefaultCheckForPeer(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer) {
|
||||
return DefaultCheckForPeer(controller->uiShow(), peer);
|
||||
}
|
||||
|
||||
SendFilesCheck DefaultCheckForPeer(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
not_null<PeerData*> peer) {
|
||||
return [=](
|
||||
const Ui::PreparedFile &file,
|
||||
bool compress,
|
||||
bool silent) {
|
||||
const auto error = Data::FileRestrictionError(peer, file, compress);
|
||||
if (error && !silent) {
|
||||
controller->showToast(*error);
|
||||
show->showToast(*error);
|
||||
}
|
||||
return !error.has_value();
|
||||
};
|
||||
|
@ -151,6 +157,7 @@ SendFilesCheck DefaultCheckForPeer(
|
|||
|
||||
SendFilesBox::Block::Block(
|
||||
not_null<QWidget*> parent,
|
||||
const style::ComposeControls &st,
|
||||
not_null<std::vector<Ui::PreparedFile>*> items,
|
||||
int from,
|
||||
int till,
|
||||
|
@ -170,20 +177,24 @@ SendFilesBox::Block::Block(
|
|||
if (_isAlbum) {
|
||||
const auto preview = Ui::CreateChild<Ui::AlbumPreview>(
|
||||
parent.get(),
|
||||
st,
|
||||
my,
|
||||
way);
|
||||
_preview.reset(preview);
|
||||
} else {
|
||||
const auto media = Ui::SingleMediaPreview::Create(
|
||||
parent,
|
||||
st,
|
||||
gifPaused,
|
||||
first);
|
||||
if (media) {
|
||||
_isSingleMedia = true;
|
||||
_preview.reset(media);
|
||||
} else {
|
||||
_preview.reset(
|
||||
Ui::CreateChild<Ui::SingleFilePreview>(parent.get(), first));
|
||||
_preview.reset(Ui::CreateChild<Ui::SingleFilePreview>(
|
||||
parent.get(),
|
||||
st,
|
||||
first));
|
||||
}
|
||||
}
|
||||
_preview->show();
|
||||
|
@ -328,15 +339,32 @@ SendFilesBox::SendFilesBox(
|
|||
SendFilesCheck check,
|
||||
Api::SendType sendType,
|
||||
SendMenu::Type sendMenuType)
|
||||
: _controller(controller)
|
||||
, _sendType(sendType)
|
||||
: SendFilesBox(nullptr, {
|
||||
.show = controller->uiShow(),
|
||||
.list = std::move(list),
|
||||
.caption = caption,
|
||||
.limits = limits,
|
||||
.check = check,
|
||||
.sendType = sendType,
|
||||
.sendMenuType = sendMenuType,
|
||||
}) {
|
||||
}
|
||||
|
||||
SendFilesBox::SendFilesBox(QWidget*, SendFilesBoxDescriptor &&descriptor)
|
||||
: _show(std::move(descriptor.show))
|
||||
, _st(descriptor.stOverride
|
||||
? *descriptor.stOverride
|
||||
: st::defaultComposeControls)
|
||||
, _sendType(descriptor.sendType)
|
||||
, _titleHeight(st::boxTitleHeight)
|
||||
, _list(std::move(list))
|
||||
, _limits(limits)
|
||||
, _sendMenuType(sendMenuType)
|
||||
, _check(std::move(check))
|
||||
, _caption(this, st::confirmCaptionArea, Ui::InputField::Mode::MultiLine)
|
||||
, _prefilledCaptionText(std::move(caption))
|
||||
, _list(std::move(descriptor.list))
|
||||
, _limits(descriptor.limits)
|
||||
, _sendMenuType(descriptor.sendMenuType)
|
||||
, _check(std::move(descriptor.check))
|
||||
, _confirmedCallback(std::move(descriptor.confirmed))
|
||||
, _cancelledCallback(std::move(descriptor.cancelled))
|
||||
, _caption(this, _st.files.caption, Ui::InputField::Mode::MultiLine)
|
||||
, _prefilledCaptionText(std::move(descriptor.caption))
|
||||
, _scroll(this, st::boxScroll)
|
||||
, _inner(
|
||||
_scroll->setOwnedWidget(
|
||||
|
@ -431,7 +459,7 @@ void SendFilesBox::setupDragArea() {
|
|||
const auto droppedCallback = [=](bool compress) {
|
||||
return [=](const QMimeData *data) {
|
||||
addFiles(data);
|
||||
Window::ActivateWindow(_controller);
|
||||
_show->activate();
|
||||
};
|
||||
};
|
||||
areas.document->setDroppedCallback(droppedCallback(false));
|
||||
|
@ -479,7 +507,7 @@ void SendFilesBox::openDialogToAddFileToAlbum() {
|
|||
return true;
|
||||
};
|
||||
const auto callback = [=](FileDialog::OpenResult &&result) {
|
||||
const auto premium = _controller->session().premium();
|
||||
const auto premium = _show->session().premium();
|
||||
FileDialogCallback(
|
||||
std::move(result),
|
||||
checkResult,
|
||||
|
@ -563,11 +591,11 @@ void SendFilesBox::addMenuButton() {
|
|||
return;
|
||||
}
|
||||
|
||||
const auto top = addTopButton(st::infoTopBarMenu);
|
||||
const auto top = addTopButton(_st.files.menu);
|
||||
top->setClickedCallback([=] {
|
||||
_menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
top,
|
||||
st::popupMenuExpandedSeparator);
|
||||
const auto &tabbed = _st.tabbed;
|
||||
const auto &icons = tabbed.icons;
|
||||
_menu = base::make_unique_q<Ui::PopupMenu>(top, tabbed.menu);
|
||||
if (hasSpoilerMenu()) {
|
||||
const auto spoilered = allWithSpoilers();
|
||||
_menu->addAction(
|
||||
|
@ -575,9 +603,9 @@ void SendFilesBox::addMenuButton() {
|
|||
? tr::lng_context_disable_spoiler(tr::now)
|
||||
: tr::lng_context_spoiler_effect(tr::now)),
|
||||
[=] { toggleSpoilers(!spoilered); },
|
||||
spoilered ? &st::menuIconSpoilerOff : &st::menuIconSpoiler);
|
||||
spoilered ? &icons.menuSpoilerOff : &icons.menuSpoiler);
|
||||
if (hasSendMenu()) {
|
||||
_menu->addSeparator();
|
||||
_menu->addSeparator(&tabbed.expandedSeparator);
|
||||
}
|
||||
}
|
||||
if (hasSendMenu()) {
|
||||
|
@ -586,7 +614,8 @@ void SendFilesBox::addMenuButton() {
|
|||
_sendMenuType,
|
||||
[=] { sendSilent(); },
|
||||
[=] { sendScheduled(); },
|
||||
[=] { sendWhenOnline(); });
|
||||
[=] { sendWhenOnline(); },
|
||||
&_st.tabbed.icons);
|
||||
}
|
||||
_menu->popup(QCursor::pos());
|
||||
return true;
|
||||
|
@ -711,12 +740,12 @@ void SendFilesBox::generatePreviewFrom(int fromBlock) {
|
|||
}
|
||||
|
||||
void SendFilesBox::pushBlock(int from, int till) {
|
||||
const auto gifPaused = [controller = _controller] {
|
||||
return controller->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::Layer);
|
||||
const auto gifPaused = [show = _show] {
|
||||
return show->paused(Window::GifPauseReason::Layer);
|
||||
};
|
||||
_blocks.emplace_back(
|
||||
_inner.data(),
|
||||
_st,
|
||||
&_list.files,
|
||||
from,
|
||||
till,
|
||||
|
@ -807,7 +836,7 @@ void SendFilesBox::pushBlock(int from, int till) {
|
|||
return checkSlowmode(list) && checkRights(list);
|
||||
};
|
||||
const auto callback = [=](FileDialog::OpenResult &&result) {
|
||||
const auto premium = _controller->session().premium();
|
||||
const auto premium = _show->session().premium();
|
||||
FileDialogCallback(
|
||||
std::move(result),
|
||||
checkResult,
|
||||
|
@ -825,15 +854,15 @@ void SendFilesBox::pushBlock(int from, int till) {
|
|||
|
||||
const auto openedOnce = widget->lifetime().make_state<bool>(false);
|
||||
block.itemModifyRequest(
|
||||
) | rpl::start_with_next([=, controller = _controller](int index) {
|
||||
) | rpl::start_with_next([=, show = _show](int index) {
|
||||
if (!(*openedOnce)) {
|
||||
controller->session().settings().incrementPhotoEditorHintShown();
|
||||
controller->session().saveSettings();
|
||||
show->session().settings().incrementPhotoEditorHintShown();
|
||||
show->session().saveSettings();
|
||||
}
|
||||
*openedOnce = true;
|
||||
Editor::OpenWithPreparedFile(
|
||||
this,
|
||||
controller,
|
||||
show,
|
||||
&_list.files[index],
|
||||
st::sendMediaPreviewSize,
|
||||
[=] { refreshAllAfterChanges(from); });
|
||||
|
@ -856,12 +885,14 @@ void SendFilesBox::setupSendWayControls() {
|
|||
this,
|
||||
tr::lng_send_grouped(tr::now),
|
||||
groupFilesFirst,
|
||||
st::defaultBoxCheckbox);
|
||||
_st.files.checkbox,
|
||||
_st.files.check);
|
||||
_sendImagesAsPhotos.create(
|
||||
this,
|
||||
tr::lng_send_compressed(tr::now),
|
||||
_sendWay.current().sendImagesAsPhotos(),
|
||||
st::defaultBoxCheckbox);
|
||||
_st.files.checkbox,
|
||||
_st.files.check);
|
||||
|
||||
_sendWay.changes(
|
||||
) | rpl::start_with_next([=](SendFilesWay value) {
|
||||
|
@ -905,7 +936,8 @@ void SendFilesBox::setupSendWayControls() {
|
|||
this,
|
||||
tr::lng_remember(tr::now),
|
||||
false,
|
||||
st::defaultBoxCheckbox);
|
||||
_st.files.checkbox,
|
||||
_st.files.check);
|
||||
_wayRemember->hide();
|
||||
rpl::combine(
|
||||
_groupFiles->checkedValue(),
|
||||
|
@ -953,25 +985,32 @@ void SendFilesBox::updateSendWayControls() {
|
|||
: tr::lng_send_compressed_one(tr::now));
|
||||
|
||||
_hintLabel->setVisible(
|
||||
_controller->session().settings().photoEditorHintShown()
|
||||
_show->session().settings().photoEditorHintShown()
|
||||
? _list.canHaveEditorHintLabel()
|
||||
: false);
|
||||
}
|
||||
|
||||
void SendFilesBox::setupCaption() {
|
||||
const auto allow = [=](const auto&) {
|
||||
const auto allow = [=](const auto &) {
|
||||
return (_limits & SendFilesAllow::EmojiWithoutPremium);
|
||||
};
|
||||
const auto show = _show;
|
||||
InitMessageFieldHandlers(
|
||||
_controller,
|
||||
&show->session(),
|
||||
show,
|
||||
_caption.data(),
|
||||
Window::GifPauseReason::Layer,
|
||||
allow);
|
||||
[=] { return show->paused(Window::GifPauseReason::Layer); },
|
||||
allow,
|
||||
&_st.files.caption);
|
||||
Ui::Emoji::SuggestionsController::Init(
|
||||
getDelegate()->outerContainer(),
|
||||
_caption,
|
||||
&_controller->session(),
|
||||
{ .suggestCustomEmoji = true, .allowCustomWithoutPremium = allow });
|
||||
&_show->session(),
|
||||
{
|
||||
.suggestCustomEmoji = true,
|
||||
.allowCustomWithoutPremium = allow,
|
||||
.st = &_st.suggestions,
|
||||
});
|
||||
|
||||
if (!_prefilledCaptionText.text.isEmpty()) {
|
||||
_caption->setTextWithTags(
|
||||
|
@ -1019,12 +1058,21 @@ void SendFilesBox::setupEmojiPanel() {
|
|||
using Selector = ChatHelpers::TabbedSelector;
|
||||
_emojiPanel = base::make_unique_q<ChatHelpers::TabbedPanel>(
|
||||
container,
|
||||
_controller,
|
||||
object_ptr<Selector>(
|
||||
nullptr,
|
||||
_controller->uiShow(),
|
||||
Window::GifPauseReason::Layer,
|
||||
Selector::Mode::EmojiOnly));
|
||||
ChatHelpers::TabbedPanelDescriptor{
|
||||
.ownedSelector = object_ptr<Selector>(
|
||||
nullptr,
|
||||
ChatHelpers::TabbedSelectorDescriptor{
|
||||
.show = _show,
|
||||
.st = _st.tabbed,
|
||||
.level = Window::GifPauseReason::Layer,
|
||||
.mode = ChatHelpers::TabbedSelector::Mode::EmojiOnly,
|
||||
.features = {
|
||||
.megagroupSet = false,
|
||||
.stickersSettings = false,
|
||||
.openStickerSets = false,
|
||||
},
|
||||
}),
|
||||
});
|
||||
_emojiPanel->setDesiredHeightValues(
|
||||
1.,
|
||||
st::emojiPanMinHeight / 2,
|
||||
|
@ -1041,11 +1089,9 @@ void SendFilesBox::setupEmojiPanel() {
|
|||
const auto info = data.document->sticker();
|
||||
if (info
|
||||
&& info->setType == Data::StickersType::Emoji
|
||||
&& !_controller->session().premium()
|
||||
&& !_show->session().premium()
|
||||
&& !(_limits & SendFilesAllow::EmojiWithoutPremium)) {
|
||||
ShowPremiumPreviewBox(
|
||||
_controller,
|
||||
PremiumPreview::AnimatedEmoji);
|
||||
ShowPremiumPreviewBox(_show, PremiumPreview::AnimatedEmoji);
|
||||
} else {
|
||||
Data::InsertCustomEmoji(_caption.data(), data.document);
|
||||
}
|
||||
|
@ -1057,7 +1103,7 @@ void SendFilesBox::setupEmojiPanel() {
|
|||
};
|
||||
_emojiFilter.reset(base::install_event_filter(container, filterCallback));
|
||||
|
||||
_emojiToggle.create(this, st::boxAttachEmoji);
|
||||
_emojiToggle.create(this, _st.files.emoji);
|
||||
_emojiToggle->setVisible(!_caption->isHidden());
|
||||
_emojiToggle->installEventFilter(_emojiPanel);
|
||||
_emojiToggle->addClickHandler([=] {
|
||||
|
@ -1095,7 +1141,7 @@ bool SendFilesBox::canAddFiles(not_null<const QMimeData*> data) const {
|
|||
}
|
||||
|
||||
bool SendFilesBox::addFiles(not_null<const QMimeData*> data) {
|
||||
const auto premium = _controller->session().premium();
|
||||
const auto premium = _show->session().premium();
|
||||
auto list = [&] {
|
||||
const auto urls = Core::ReadMimeUrls(data);
|
||||
auto result = CanAddUrls(urls)
|
||||
|
@ -1242,7 +1288,7 @@ void SendFilesBox::paintEvent(QPaintEvent *e) {
|
|||
Painter p(this);
|
||||
|
||||
p.setFont(st::boxTitleFont);
|
||||
p.setPen(st::boxTitleFg);
|
||||
p.setPen(getDelegate()->style().title.textFg);
|
||||
p.drawTextLeft(
|
||||
st::boxPhotoTitlePosition.x(),
|
||||
st::boxTitlePosition.y() - st::boxTopMargin,
|
||||
|
@ -1318,7 +1364,7 @@ void SendFilesBox::saveSendWaySettings() {
|
|||
}
|
||||
|
||||
bool SendFilesBox::validateLength(const QString &text) const {
|
||||
const auto session = &_controller->session();
|
||||
const auto session = &_show->session();
|
||||
const auto limit = Data::PremiumLimits(session).captionLengthCurrent();
|
||||
const auto remove = int(text.size()) - limit;
|
||||
const auto way = _sendWay.current();
|
||||
|
@ -1328,7 +1374,8 @@ bool SendFilesBox::validateLength(const QString &text) const {
|
|||
way.sendImagesAsPhotos())) {
|
||||
return true;
|
||||
}
|
||||
_controller->show(Box(CaptionLimitReachedBox, session, remove));
|
||||
_show->showBox(
|
||||
Box(CaptionLimitReachedBox, session, remove, &_st.premium));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1385,8 +1432,7 @@ void SendFilesBox::sendScheduled() {
|
|||
? SendMenu::Type::ScheduledToUser
|
||||
: _sendMenuType;
|
||||
const auto callback = [=](Api::SendOptions options) { send(options); };
|
||||
_controller->show(
|
||||
HistoryView::PrepareScheduleBox(this, type, callback));
|
||||
_show->showBox(HistoryView::PrepareScheduleBox(this, type, callback));
|
||||
}
|
||||
|
||||
void SendFilesBox::sendWhenOnline() {
|
||||
|
|
|
@ -15,6 +15,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "storage/localimageloader.h"
|
||||
#include "storage/storage_media_prepare.h"
|
||||
|
||||
namespace style {
|
||||
struct ComposeControls;
|
||||
} // namespace style
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
@ -26,6 +30,7 @@ enum class SendType;
|
|||
|
||||
namespace ChatHelpers {
|
||||
class TabbedPanel;
|
||||
class Show;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Ui {
|
||||
|
@ -71,6 +76,29 @@ using SendFilesCheck = Fn<bool(
|
|||
[[nodiscard]] SendFilesCheck DefaultCheckForPeer(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer);
|
||||
[[nodiscard]] SendFilesCheck DefaultCheckForPeer(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
using SendFilesConfirmed = Fn<void(
|
||||
Ui::PreparedList &&list,
|
||||
Ui::SendFilesWay way,
|
||||
TextWithTags &&caption,
|
||||
Api::SendOptions options,
|
||||
bool ctrlShiftEnter)>;
|
||||
|
||||
struct SendFilesBoxDescriptor {
|
||||
std::shared_ptr<ChatHelpers::Show> show;
|
||||
Ui::PreparedList list;
|
||||
TextWithTags caption;
|
||||
SendFilesLimits limits = {};
|
||||
SendFilesCheck check;
|
||||
Api::SendType sendType = {};
|
||||
SendMenu::Type sendMenuType = {};
|
||||
const style::ComposeControls *stOverride = nullptr;
|
||||
SendFilesConfirmed confirmed;
|
||||
Fn<void()> cancelled;
|
||||
};
|
||||
|
||||
class SendFilesBox : public Ui::BoxContent {
|
||||
public:
|
||||
|
@ -87,14 +115,9 @@ public:
|
|||
SendFilesCheck check,
|
||||
Api::SendType sendType,
|
||||
SendMenu::Type sendMenuType);
|
||||
SendFilesBox(QWidget*, SendFilesBoxDescriptor &&descriptor);
|
||||
|
||||
void setConfirmedCallback(
|
||||
Fn<void(
|
||||
Ui::PreparedList &&list,
|
||||
Ui::SendFilesWay way,
|
||||
TextWithTags &&caption,
|
||||
Api::SendOptions options,
|
||||
bool ctrlShiftEnter)> callback) {
|
||||
void setConfirmedCallback(SendFilesConfirmed callback) {
|
||||
_confirmedCallback = std::move(callback);
|
||||
}
|
||||
void setCancelledCallback(Fn<void()> callback) {
|
||||
|
@ -116,6 +139,7 @@ private:
|
|||
public:
|
||||
Block(
|
||||
not_null<QWidget*> parent,
|
||||
const style::ComposeControls &st,
|
||||
not_null<std::vector<Ui::PreparedFile>*> items,
|
||||
int from,
|
||||
int till,
|
||||
|
@ -201,7 +225,8 @@ private:
|
|||
void enqueueNextPrepare();
|
||||
void addPreparedAsyncFile(Ui::PreparedFile &&file);
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const std::shared_ptr<ChatHelpers::Show> _show;
|
||||
const style::ComposeControls &_st;
|
||||
const Api::SendType _sendType = Api::SendType();
|
||||
|
||||
QString _titleText;
|
||||
|
@ -211,15 +236,10 @@ private:
|
|||
std::optional<int> _removingIndex;
|
||||
|
||||
SendFilesLimits _limits = {};
|
||||
SendMenu::Type _sendMenuType = SendMenu::Type();
|
||||
SendMenu::Type _sendMenuType = {};
|
||||
|
||||
SendFilesCheck _check;
|
||||
Fn<void(
|
||||
Ui::PreparedList &&list,
|
||||
Ui::SendFilesWay way,
|
||||
TextWithTags &&caption,
|
||||
Api::SendOptions options,
|
||||
bool ctrlShiftEnter)> _confirmedCallback;
|
||||
SendFilesConfirmed _confirmedCallback;
|
||||
Fn<void()> _cancelledCallback;
|
||||
bool _confirmed = false;
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ void Show::showOrHideBoxOrLayer(
|
|||
} else if (const auto panel = _panel.get()) {
|
||||
panel->hideLayer(animated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
not_null<QWidget*> Show::toastParent() const {
|
||||
const auto panel = _panel.get();
|
||||
|
|
|
@ -11,6 +11,7 @@ using "boxes/boxes.style";
|
|||
using "ui/layers/layers.style";
|
||||
using "ui/widgets/widgets.style";
|
||||
using "ui/menu_icons.style";
|
||||
using "ui/effects/premium.style";
|
||||
|
||||
GroupCallUserpics {
|
||||
size: pixels;
|
||||
|
@ -66,6 +67,8 @@ ComposeIcons {
|
|||
menuMute: icon;
|
||||
menuSchedule: icon;
|
||||
menuWhenOnline: icon;
|
||||
menuSpoiler: icon;
|
||||
menuSpoilerOff: icon;
|
||||
}
|
||||
|
||||
EmojiSuggestions {
|
||||
|
@ -107,6 +110,7 @@ EmojiPan {
|
|||
fadeLeft: icon;
|
||||
fadeRight: icon;
|
||||
menu: PopupMenu;
|
||||
expandedSeparator: MenuSeparator;
|
||||
tabs: SettingsSlider;
|
||||
search: TabbedSearch;
|
||||
searchMargin: margins;
|
||||
|
@ -162,6 +166,24 @@ RecordBar {
|
|||
remove: IconButton;
|
||||
}
|
||||
|
||||
ComposeFiles {
|
||||
check: Check;
|
||||
checkbox: Checkbox;
|
||||
menu: IconButton;
|
||||
caption: InputField;
|
||||
emoji: EmojiButton;
|
||||
confirmBg: color;
|
||||
buttonFile: IconButton;
|
||||
buttonFileEdit: icon;
|
||||
buttonFileDelete: icon;
|
||||
iconBg: color;
|
||||
iconPlay: icon;
|
||||
iconImage: icon;
|
||||
iconDocument: icon;
|
||||
nameFg: color;
|
||||
statusFg: color;
|
||||
}
|
||||
|
||||
ComposeControls {
|
||||
bg: color;
|
||||
radius: pixels;
|
||||
|
@ -175,6 +197,8 @@ ComposeControls {
|
|||
tabbedHeightMin: pixels;
|
||||
tabbedHeightMax: pixels;
|
||||
record: RecordBar;
|
||||
files: ComposeFiles;
|
||||
premium: PremiumLimits;
|
||||
}
|
||||
|
||||
switchPmButton: RoundButton(defaultBoxButton) {
|
||||
|
@ -416,6 +440,42 @@ stickersToast: Toast(defaultToast) {
|
|||
stickersEmpty: icon {{ "stickers_empty", windowSubTextFg }};
|
||||
emojiEmpty: icon {{ "emoji_empty", windowSubTextFg }};
|
||||
|
||||
editMediaButtonSize: 32px;
|
||||
|
||||
editMediaButtonIconFile: icon {{ "send_media/send_media_replace", menuIconFg }};
|
||||
editMediaButton: IconButton(defaultIconButton) {
|
||||
width: editMediaButtonSize;
|
||||
height: editMediaButtonSize;
|
||||
|
||||
icon: editMediaButtonIconFile;
|
||||
|
||||
rippleAreaSize: editMediaButtonSize;
|
||||
ripple: defaultRippleAnimation;
|
||||
}
|
||||
|
||||
sendBoxAlbumGroupEditInternalSkip: 8px;
|
||||
sendBoxAlbumGroupSkipRight: 5px;
|
||||
sendBoxAlbumGroupSkipTop: 5px;
|
||||
sendBoxAlbumGroupRadius: 4px;
|
||||
sendBoxAlbumGroupSize: size(62px, 25px);
|
||||
sendBoxAlbumSmallGroupSize: size(30px, 25px);
|
||||
|
||||
sendBoxFileGroupSkipTop: 2px;
|
||||
sendBoxFileGroupSkipRight: 5px;
|
||||
sendBoxFileGroupEditInternalSkip: -1px;
|
||||
|
||||
sendBoxAlbumGroupButtonFile: IconButton(editMediaButton) {
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgRipple;
|
||||
}
|
||||
}
|
||||
sendBoxAlbumGroupEditButtonIconFile: editMediaButtonIconFile;
|
||||
sendBoxAlbumGroupDeleteButtonIconFile: icon {{ "send_media/send_media_delete", menuIconFg }};
|
||||
|
||||
sendBoxAlbumButtonMediaEdit: icon {{ "send_media/send_media_replace", roundedFg }};
|
||||
sendBoxAlbumGroupButtonMediaEdit: icon {{ "send_media/send_media_replace", roundedFg, point(4px, 1px) }};
|
||||
sendBoxAlbumGroupButtonMediaDelete: icon {{ "send_media/send_media_delete", roundedFg }};
|
||||
|
||||
defaultComposeIcons: ComposeIcons {
|
||||
settings: icon {{ "emoji/emoji_settings", emojiIconFg }};
|
||||
|
||||
|
@ -445,6 +505,8 @@ defaultComposeIcons: ComposeIcons {
|
|||
menuMute: menuIconMute;
|
||||
menuSchedule: menuIconSchedule;
|
||||
menuWhenOnline: menuIconWhenOnline;
|
||||
menuSpoiler: menuIconSpoiler;
|
||||
menuSpoilerOff: menuIconSpoilerOff;
|
||||
}
|
||||
defaultEmojiPan: EmojiPan {
|
||||
margin: margins(7px, 0px, 7px, 0px);
|
||||
|
@ -476,6 +538,10 @@ defaultEmojiPan: EmojiPan {
|
|||
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }};
|
||||
fadeRight: icon {{ "fade_horizontal", emojiPanCategories }};
|
||||
menu: popupMenuWithIcons;
|
||||
expandedSeparator: MenuSeparator(defaultMenuSeparator) {
|
||||
padding: margins(0px, 4px, 0px, 4px);
|
||||
width: 6px;
|
||||
}
|
||||
tabs: emojiTabs;
|
||||
search: defaultTabbedSearch;
|
||||
searchMargin: margins(1px, 11px, 2px, 5px);
|
||||
|
@ -974,6 +1040,41 @@ historySend: SendButton {
|
|||
sendDisabledFg: historyComposeIconFg;
|
||||
}
|
||||
|
||||
defaultComposeFilesMenu: IconButton(defaultIconButton) {
|
||||
width: 48px;
|
||||
height: 54px;
|
||||
|
||||
icon: icon {{ "title_menu_dots", boxTitleCloseFg }};
|
||||
iconOver: icon {{ "title_menu_dots", boxTitleCloseFgOver }};
|
||||
iconPosition: point(18px, -1px);
|
||||
|
||||
rippleAreaPosition: point(1px, 6px);
|
||||
rippleAreaSize: 42px;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
}
|
||||
defaultComposeFilesField: InputField(defaultInputField) {
|
||||
textMargins: margins(1px, 26px, 31px, 4px);
|
||||
heightMax: 158px;
|
||||
}
|
||||
defaultComposeFiles: ComposeFiles {
|
||||
check: defaultCheck;
|
||||
checkbox: defaultBoxCheckbox;
|
||||
menu: defaultComposeFilesMenu;
|
||||
caption: defaultComposeFilesField;
|
||||
emoji: boxAttachEmoji;
|
||||
confirmBg: windowBgOver;
|
||||
buttonFile: sendBoxAlbumGroupButtonFile;
|
||||
buttonFileEdit: sendBoxAlbumGroupEditButtonIconFile;
|
||||
buttonFileDelete: sendBoxAlbumGroupDeleteButtonIconFile;
|
||||
iconBg: msgFileInBg;
|
||||
iconPlay: icon {{ "history_file_play", historyFileInIconFg }};
|
||||
iconImage: icon {{ "history_file_image", historyFileInIconFg }};
|
||||
iconDocument: icon {{ "history_file_document", historyFileInIconFg }};
|
||||
nameFg: historyFileNameInFg;
|
||||
statusFg: mediaInFg;
|
||||
}
|
||||
defaultComposeControls: ComposeControls {
|
||||
bg: historyComposeAreaBg;
|
||||
radius: 0px;
|
||||
|
@ -987,4 +1088,6 @@ defaultComposeControls: ComposeControls {
|
|||
tabbedHeightMin: emojiPanMinHeight;
|
||||
tabbedHeightMax: emojiPanMaxHeight;
|
||||
record: defaultRecordBar;
|
||||
files: defaultComposeFiles;
|
||||
premium: defaultPremiumLimits;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ enum class WindowUsage {
|
|||
|
||||
class Show : public Main::SessionShow {
|
||||
public:
|
||||
virtual void activate() = 0;
|
||||
|
||||
[[nodiscard]] virtual bool paused(PauseReason reason) const = 0;
|
||||
[[nodiscard]] virtual rpl::producer<> pauseChanged() const = 0;
|
||||
|
||||
|
|
|
@ -726,6 +726,7 @@ object_ptr<TabbedSelector::InnerFooter> EmojiListWidget::createFooter() {
|
|||
.paused = footerPaused,
|
||||
.parent = this,
|
||||
.st = &st(),
|
||||
.features = { .stickersSettings = false },
|
||||
});
|
||||
_footer = result;
|
||||
|
||||
|
|
|
@ -172,6 +172,7 @@ object_ptr<TabbedSelector::InnerFooter> GifsListWidget::createFooter() {
|
|||
.paused = pausedMethod(),
|
||||
.parent = this,
|
||||
.st = &st(),
|
||||
.features = { .stickersSettings = false },
|
||||
});
|
||||
_footer = result;
|
||||
_chosenSetId = Data::Stickers::RecentSetId;
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "chat_helpers/stickers_list_widget.h"
|
||||
|
||||
#include "core/application.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -221,9 +222,15 @@ StickersListWidget::StickersListWidget(
|
|||
}
|
||||
|
||||
_settings->addClickHandler([=] {
|
||||
using Section = StickersBox::Section;
|
||||
_show->showBox(
|
||||
Box<StickersBox>(_show, Section::Installed, _isMasks));
|
||||
if (const auto window = _show->resolveWindow(
|
||||
WindowUsage::PremiumPromo)) {
|
||||
// While media viewer can't show StickersBox.
|
||||
using Section = StickersBox::Section;
|
||||
window->show(
|
||||
Box<StickersBox>(_show, Section::Installed, _isMasks));
|
||||
Core::App().hideMediaView();
|
||||
Window::ActivateWindow(window);
|
||||
}
|
||||
});
|
||||
|
||||
session().downloaderTaskFinished(
|
||||
|
|
|
@ -30,7 +30,7 @@ struct TabbedPanelDescriptor {
|
|||
Window::SessionController *regularWindow = nullptr;
|
||||
object_ptr<TabbedSelector> ownedSelector = { nullptr };
|
||||
TabbedSelector *nonOwnedSelector = nullptr;
|
||||
};;
|
||||
};
|
||||
|
||||
class TabbedPanel : public Ui::RpWidget {
|
||||
public:
|
||||
|
|
|
@ -12,21 +12,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_session_controller.h" // Window::GifPauseReason
|
||||
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_media_view.h"
|
||||
|
||||
namespace Editor {
|
||||
|
||||
StickersPanelController::StickersPanelController(
|
||||
not_null<Ui::RpWidget*> panelContainer,
|
||||
not_null<Window::SessionController*> controller)
|
||||
std::shared_ptr<ChatHelpers::Show> show)
|
||||
: _stickersPanel(
|
||||
base::make_unique_q<ChatHelpers::TabbedPanel>(
|
||||
panelContainer,
|
||||
controller,
|
||||
object_ptr<ChatHelpers::TabbedSelector>(
|
||||
nullptr,
|
||||
controller->uiShow(),
|
||||
Window::GifPauseReason::Layer,
|
||||
ChatHelpers::TabbedSelector::Mode::MediaEditor))) {
|
||||
ChatHelpers::TabbedPanelDescriptor{
|
||||
.ownedSelector = object_ptr<ChatHelpers::TabbedSelector>(
|
||||
nullptr,
|
||||
ChatHelpers::TabbedSelectorDescriptor{
|
||||
.show = show,
|
||||
.st = st::storiesComposeControls.tabbed,
|
||||
.level = Window::GifPauseReason::Layer,
|
||||
.mode = ChatHelpers::TabbedSelector::Mode::MediaEditor,
|
||||
.features = {
|
||||
.megagroupSet = false,
|
||||
.stickersSettings = false,
|
||||
.openStickerSets = false,
|
||||
},
|
||||
}),
|
||||
})) {
|
||||
_stickersPanel->setDesiredHeightValues(
|
||||
1.,
|
||||
st::emojiPanMinHeight / 2,
|
||||
|
|
|
@ -11,16 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace ChatHelpers {
|
||||
class TabbedPanel;
|
||||
class Show;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Editor {
|
||||
|
||||
class StickersPanelController final {
|
||||
|
@ -34,7 +31,7 @@ public:
|
|||
|
||||
StickersPanelController(
|
||||
not_null<Ui::RpWidget*> panelContainer,
|
||||
not_null<Window::SessionController*> controller);
|
||||
std::shared_ptr<ChatHelpers::Show> show);
|
||||
|
||||
[[nodiscard]] auto stickerChosen() const
|
||||
-> rpl::producer<not_null<DocumentData*>>;
|
||||
|
|
|
@ -52,16 +52,34 @@ PhotoEditor::PhotoEditor(
|
|||
std::shared_ptr<Image> photo,
|
||||
PhotoModifications modifications,
|
||||
EditorData data)
|
||||
: PhotoEditor(
|
||||
parent,
|
||||
controller->uiShow(),
|
||||
(controller->sessionController()
|
||||
? controller->sessionController()->uiShow()
|
||||
: nullptr),
|
||||
std::move(photo),
|
||||
std::move(modifications),
|
||||
std::move(data)) {
|
||||
}
|
||||
|
||||
PhotoEditor::PhotoEditor(
|
||||
not_null<QWidget*> parent,
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
std::shared_ptr<ChatHelpers::Show> sessionShow,
|
||||
std::shared_ptr<Image> photo,
|
||||
PhotoModifications modifications,
|
||||
EditorData data)
|
||||
: RpWidget(parent)
|
||||
, _modifications(std::move(modifications))
|
||||
, _controllers(std::make_shared<Controllers>(
|
||||
controller->sessionController()
|
||||
sessionShow
|
||||
? std::make_unique<StickersPanelController>(
|
||||
this,
|
||||
controller->sessionController())
|
||||
std::move(sessionShow))
|
||||
: nullptr,
|
||||
std::make_unique<UndoController>(),
|
||||
controller->uiShow()))
|
||||
std::move(show)))
|
||||
, _content(base::make_unique_q<PhotoEditorContent>(
|
||||
this,
|
||||
photo,
|
||||
|
|
|
@ -15,8 +15,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Ui {
|
||||
class LayerWidget;
|
||||
class Show;
|
||||
} // namespace Ui
|
||||
|
||||
namespace ChatHelpers {
|
||||
class Show;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Window {
|
||||
class Controller;
|
||||
} // namespace Window
|
||||
|
@ -36,6 +41,13 @@ public:
|
|||
std::shared_ptr<Image> photo,
|
||||
PhotoModifications modifications,
|
||||
EditorData data = EditorData());
|
||||
PhotoEditor(
|
||||
not_null<QWidget*> parent,
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
std::shared_ptr<ChatHelpers::Show> sessionShow,
|
||||
std::shared_ptr<Image> photo,
|
||||
PhotoModifications modifications,
|
||||
EditorData data = EditorData());
|
||||
|
||||
void save();
|
||||
[[nodiscard]] rpl::producer<PhotoModifications> doneRequests() const;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Editor {
|
|||
|
||||
void OpenWithPreparedFile(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<Ui::PreparedFile*> file,
|
||||
int previewWidth,
|
||||
Fn<void()> &&doneCallback) {
|
||||
|
@ -56,13 +56,14 @@ void OpenWithPreparedFile(
|
|||
const auto fileImage = std::make_shared<Image>(std::move(copy));
|
||||
auto editor = base::make_unique_q<PhotoEditor>(
|
||||
parent,
|
||||
&controller->window(),
|
||||
show,
|
||||
show,
|
||||
fileImage,
|
||||
image->modifications);
|
||||
const auto raw = editor.get();
|
||||
auto layer = std::make_unique<LayerWidget>(parent, std::move(editor));
|
||||
InitEditorLayer(layer.get(), raw, std::move(callback));
|
||||
controller->showLayer(std::move(layer), Ui::LayerOption::KeepOther);
|
||||
show->showLayer(std::move(layer), Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
void PrepareProfilePhoto(
|
||||
|
|
|
@ -6,13 +6,13 @@ For license and copyright information please follow this link:
|
|||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
//
|
||||
//#include "ui/image/image.h"
|
||||
//#include "editor/photo_editor_common.h"
|
||||
//#include "base/unique_qptr.h"
|
||||
|
||||
enum class ImageRoundRadius;
|
||||
|
||||
namespace ChatHelpers {
|
||||
class Show;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
struct PreparedFile;
|
||||
|
@ -31,7 +31,7 @@ struct EditorData;
|
|||
|
||||
void OpenWithPreparedFile(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<Ui::PreparedFile*> file,
|
||||
int previewWidth,
|
||||
Fn<void()> &&doneCallback);
|
||||
|
|
|
@ -5142,7 +5142,8 @@ bool HistoryWidget::showSendingFilesError(
|
|||
return false;
|
||||
} else if (text == u"(toolarge)"_q) {
|
||||
const auto fileSize = list.files.back().size;
|
||||
controller()->show(Box(FileSizeLimitBox, &session(), fileSize));
|
||||
controller()->show(
|
||||
Box(FileSizeLimitBox, &session(), fileSize, nullptr));
|
||||
return true;
|
||||
}
|
||||
controller()->showToast(text);
|
||||
|
|
|
@ -1123,7 +1123,8 @@ bool RepliesWidget::showSendingFilesError(
|
|||
return false;
|
||||
} else if (text == u"(toolarge)"_q) {
|
||||
const auto fileSize = list.files.back().size;
|
||||
controller()->show(Box(FileSizeLimitBox, &session(), fileSize));
|
||||
controller()->show(
|
||||
Box(FileSizeLimitBox, &session(), fileSize, nullptr));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -559,7 +559,8 @@ bool ScheduledWidget::showSendingFilesError(
|
|||
return false;
|
||||
} else if (text == u"(toolarge)"_q) {
|
||||
const auto fileSize = list.files.back().size;
|
||||
controller()->show(Box(FileSizeLimitBox, &session(), fileSize));
|
||||
controller()->show(
|
||||
Box(FileSizeLimitBox, &session(), fileSize, nullptr));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,16 +7,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "media/stories/media_stories_reply.h"
|
||||
|
||||
#include "api/api_common.h"
|
||||
#include "apiwrap.h"
|
||||
#include "base/call_delayed.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/send_files_box.h"
|
||||
#include "chat_helpers/compose/compose_show.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/mime_type.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/view/controls/compose_controls_common.h"
|
||||
#include "history/view/controls/history_view_compose_controls.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "history/history.h"
|
||||
#include "inline_bots/inline_bot_result.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "media/stories/media_stories_controller.h"
|
||||
#include "menu/menu_send.h"
|
||||
#include "storage/localimageloader.h"
|
||||
#include "storage/storage_media_prepare.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "styles/style_boxes.h" // sendMediaPreviewSize.
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_media_view.h"
|
||||
|
||||
|
@ -85,15 +99,276 @@ void ReplyArea::initGeometry() {
|
|||
}
|
||||
|
||||
void ReplyArea::send(Api::SendOptions options) {
|
||||
// #TODO stories
|
||||
const auto webPageId = _controls->webPageId();
|
||||
|
||||
auto message = ApiWrap::MessageToSend(prepareSendAction(options));
|
||||
message.textWithTags = _controls->getTextWithAppliedMarkdown();
|
||||
message.webPageId = webPageId;
|
||||
|
||||
const auto error = GetErrorTextForSending(
|
||||
_data.user,
|
||||
{
|
||||
.topicRootId = MsgId(0),
|
||||
.text = &message.textWithTags,
|
||||
.ignoreSlowmodeCountdown = (options.scheduled != 0),
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
_controller->uiShow()->showToast(error);
|
||||
}
|
||||
|
||||
session().api().sendMessage(std::move(message));
|
||||
|
||||
_controls->clear();
|
||||
finishSending();
|
||||
}
|
||||
|
||||
void ReplyArea::sendVoice(VoiceToSend &&data) {
|
||||
// #TODO stories
|
||||
auto action = prepareSendAction(data.options);
|
||||
session().api().sendVoiceMessage(
|
||||
data.bytes,
|
||||
data.waveform,
|
||||
data.duration,
|
||||
std::move(action));
|
||||
|
||||
_controls->clearListenState();
|
||||
finishSending();
|
||||
}
|
||||
|
||||
void ReplyArea::chooseAttach(std::optional<bool> overrideCompress) {
|
||||
// #TODO stories
|
||||
void ReplyArea::finishSending() {
|
||||
_controls->hidePanelsAnimated();
|
||||
_controller->wrap()->setFocus();
|
||||
}
|
||||
|
||||
void ReplyArea::uploadFile(
|
||||
const QByteArray &fileContent,
|
||||
SendMediaType type) {
|
||||
session().api().sendFile(fileContent, type, prepareSendAction({}));
|
||||
}
|
||||
|
||||
bool ReplyArea::showSendingFilesError(
|
||||
const Ui::PreparedList &list) const {
|
||||
return showSendingFilesError(list, std::nullopt);
|
||||
}
|
||||
|
||||
bool ReplyArea::showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const {
|
||||
const auto text = [&] {
|
||||
const auto peer = _data.user;
|
||||
const auto error = Data::FileRestrictionError(peer, list, compress);
|
||||
if (error) {
|
||||
return *error;
|
||||
}
|
||||
using Error = Ui::PreparedList::Error;
|
||||
switch (list.error) {
|
||||
case Error::None: return QString();
|
||||
case Error::EmptyFile:
|
||||
case Error::Directory:
|
||||
case Error::NonLocalUrl: return tr::lng_send_image_empty(
|
||||
tr::now,
|
||||
lt_name,
|
||||
list.errorData);
|
||||
case Error::TooLargeFile: return u"(toolarge)"_q;
|
||||
}
|
||||
return tr::lng_forward_send_files_cant(tr::now);
|
||||
}();
|
||||
if (text.isEmpty()) {
|
||||
return false;
|
||||
} else if (text == u"(toolarge)"_q) {
|
||||
const auto fileSize = list.files.back().size;
|
||||
_controller->uiShow()->showBox(Box(
|
||||
FileSizeLimitBox,
|
||||
&session(),
|
||||
fileSize,
|
||||
&st::storiesComposePremium));
|
||||
return true;
|
||||
}
|
||||
|
||||
_controller->uiShow()->showToast(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
Api::SendAction ReplyArea::prepareSendAction(
|
||||
Api::SendOptions options) const {
|
||||
Expects(_data.user != nullptr);
|
||||
|
||||
const auto history = _data.user->owner().history(_data.user);
|
||||
auto result = Api::SendAction(history, options);
|
||||
result.options.sendAs = _controls->sendAsPeer();
|
||||
return result;
|
||||
}
|
||||
|
||||
void ReplyArea::chooseAttach(
|
||||
std::optional<bool> overrideSendImagesAsPhotos) {
|
||||
if (!_data.user) {
|
||||
return;
|
||||
}
|
||||
const auto user = not_null(_data.user);
|
||||
_choosingAttach = false;
|
||||
if (const auto error = Data::AnyFileRestrictionError(user)) {
|
||||
_controller->uiShow()->showToast(*error);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto filter = (overrideSendImagesAsPhotos == true)
|
||||
? FileDialog::ImagesOrAllFilter()
|
||||
: FileDialog::AllOrImagesFilter();
|
||||
const auto callback = [=](FileDialog::OpenResult &&result) {
|
||||
if (result.paths.isEmpty() && result.remoteContent.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.remoteContent.isEmpty()) {
|
||||
auto read = Images::Read({
|
||||
.content = result.remoteContent,
|
||||
});
|
||||
if (!read.image.isNull() && !read.animated) {
|
||||
confirmSendingFiles(
|
||||
std::move(read.image),
|
||||
std::move(result.remoteContent),
|
||||
overrideSendImagesAsPhotos);
|
||||
} else {
|
||||
uploadFile(result.remoteContent, SendMediaType::File);
|
||||
}
|
||||
} else {
|
||||
const auto premium = session().premium();
|
||||
auto list = Storage::PrepareMediaList(
|
||||
result.paths,
|
||||
st::sendMediaPreviewSize,
|
||||
premium);
|
||||
list.overrideSendImagesAsPhotos = overrideSendImagesAsPhotos;
|
||||
confirmSendingFiles(std::move(list));
|
||||
}
|
||||
};
|
||||
FileDialog::GetOpenPaths(
|
||||
_controller->wrap().get(),
|
||||
tr::lng_choose_files(tr::now),
|
||||
filter,
|
||||
crl::guard(&_shownUserGuard, callback),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
bool ReplyArea::confirmSendingFiles(
|
||||
not_null<const QMimeData*> data,
|
||||
std::optional<bool> overrideSendImagesAsPhotos,
|
||||
const QString &insertTextOnCancel) {
|
||||
const auto hasImage = data->hasImage();
|
||||
const auto premium = session().user()->isPremium();
|
||||
|
||||
if (const auto urls = Core::ReadMimeUrls(data); !urls.empty()) {
|
||||
auto list = Storage::PrepareMediaList(
|
||||
urls,
|
||||
st::sendMediaPreviewSize,
|
||||
premium);
|
||||
if (list.error != Ui::PreparedList::Error::NonLocalUrl) {
|
||||
if (list.error == Ui::PreparedList::Error::None
|
||||
|| !hasImage) {
|
||||
const auto emptyTextOnCancel = QString();
|
||||
list.overrideSendImagesAsPhotos = overrideSendImagesAsPhotos;
|
||||
confirmSendingFiles(std::move(list), emptyTextOnCancel);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (auto read = Core::ReadMimeImage(data)) {
|
||||
confirmSendingFiles(
|
||||
std::move(read.image),
|
||||
std::move(read.content),
|
||||
overrideSendImagesAsPhotos,
|
||||
insertTextOnCancel);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReplyArea::confirmSendingFiles(
|
||||
Ui::PreparedList &&list,
|
||||
const QString &insertTextOnCancel) {
|
||||
if (_controls->confirmMediaEdit(list)) {
|
||||
return true;
|
||||
} else if (showSendingFilesError(list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto show = _controller->uiShow();
|
||||
auto confirmed = [=](auto &&...args) {
|
||||
sendingFilesConfirmed(std::forward<decltype(args)>(args)...);
|
||||
};
|
||||
auto box = Box<SendFilesBox>(SendFilesBoxDescriptor{
|
||||
.show = show,
|
||||
.list = std::move(list),
|
||||
.caption = _controls->getTextWithAppliedMarkdown(),
|
||||
.limits = DefaultLimitsForPeer(_data.user),
|
||||
.check = DefaultCheckForPeer(show, _data.user),
|
||||
.sendType = Api::SendType::Normal,
|
||||
.sendMenuType = SendMenu::Type::SilentOnly,
|
||||
.stOverride = &st::storiesComposeControls,
|
||||
.confirmed = crl::guard(this, confirmed),
|
||||
.cancelled = _controls->restoreTextCallback(insertTextOnCancel),
|
||||
});
|
||||
if (const auto shown = show->show(std::move(box))) {
|
||||
shown->setCloseByOutsideClick(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReplyArea::sendingFilesConfirmed(
|
||||
Ui::PreparedList &&list,
|
||||
Ui::SendFilesWay way,
|
||||
TextWithTags &&caption,
|
||||
Api::SendOptions options,
|
||||
bool ctrlShiftEnter) {
|
||||
Expects(list.filesToProcess.empty());
|
||||
|
||||
if (showSendingFilesError(list, way.sendImagesAsPhotos())) {
|
||||
return;
|
||||
}
|
||||
auto groups = DivideByGroups(
|
||||
std::move(list),
|
||||
way,
|
||||
_data.user->slowmodeApplied());
|
||||
const auto type = way.sendImagesAsPhotos()
|
||||
? SendMediaType::Photo
|
||||
: SendMediaType::File;
|
||||
auto action = prepareSendAction(options);
|
||||
action.clearDraft = false;
|
||||
if ((groups.size() != 1 || !groups.front().sentWithCaption())
|
||||
&& !caption.text.isEmpty()) {
|
||||
auto message = Api::MessageToSend(action);
|
||||
message.textWithTags = base::take(caption);
|
||||
session().api().sendMessage(std::move(message));
|
||||
}
|
||||
for (auto &group : groups) {
|
||||
const auto album = (group.type != Ui::AlbumType::None)
|
||||
? std::make_shared<SendingAlbum>()
|
||||
: nullptr;
|
||||
session().api().sendFiles(
|
||||
std::move(group.list),
|
||||
type,
|
||||
base::take(caption),
|
||||
album,
|
||||
action);
|
||||
}
|
||||
finishSending();
|
||||
}
|
||||
|
||||
bool ReplyArea::confirmSendingFiles(
|
||||
QImage &&image,
|
||||
QByteArray &&content,
|
||||
std::optional<bool> overrideSendImagesAsPhotos,
|
||||
const QString &insertTextOnCancel) {
|
||||
if (image.isNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto list = Storage::PrepareMediaFromImage(
|
||||
std::move(image),
|
||||
std::move(content),
|
||||
st::sendMediaPreviewSize);
|
||||
list.overrideSendImagesAsPhotos = overrideSendImagesAsPhotos;
|
||||
return confirmSendingFiles(std::move(list), insertTextOnCancel);
|
||||
}
|
||||
|
||||
void ReplyArea::initActions() {
|
||||
|
@ -180,6 +455,7 @@ void ReplyArea::show(ReplyAreaData data) {
|
|||
}
|
||||
return;
|
||||
}
|
||||
invalidate_weak_ptrs(&_shownUserGuard);
|
||||
const auto user = data.user;
|
||||
const auto history = user ? user->owner().history(user).get() : nullptr;
|
||||
_controls->setHistory({
|
||||
|
@ -188,6 +464,12 @@ void ReplyArea::show(ReplyAreaData data) {
|
|||
_controls->clear();
|
||||
}
|
||||
|
||||
Main::Session &ReplyArea::session() const {
|
||||
Expects(_data.user != nullptr);
|
||||
|
||||
return _data.user->session();
|
||||
}
|
||||
|
||||
rpl::producer<bool> ReplyArea::focusedValue() const {
|
||||
return _controls->focusedValue();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "base/weak_ptr.h"
|
||||
|
||||
enum class SendMediaType;
|
||||
|
||||
namespace Api {
|
||||
struct SendAction;
|
||||
struct SendOptions;
|
||||
} // namespace Api
|
||||
|
||||
|
@ -21,6 +24,15 @@ namespace HistoryView::Controls {
|
|||
struct VoiceToSend;
|
||||
} // namespace HistoryView::Controls
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
struct PreparedList;
|
||||
class SendFilesWay;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
class Controller;
|
||||
|
@ -45,9 +57,44 @@ public:
|
|||
private:
|
||||
using VoiceToSend = HistoryView::Controls::VoiceToSend;
|
||||
|
||||
[[nodiscard]] Main::Session &session() const;
|
||||
|
||||
bool confirmSendingFiles(const QStringList &files);
|
||||
bool confirmSendingFiles(not_null<const QMimeData*> data);
|
||||
|
||||
void uploadFile(const QByteArray &fileContent, SendMediaType type);
|
||||
bool confirmSendingFiles(
|
||||
QImage &&image,
|
||||
QByteArray &&content,
|
||||
std::optional<bool> overrideSendImagesAsPhotos = std::nullopt,
|
||||
const QString &insertTextOnCancel = QString());
|
||||
bool confirmSendingFiles(
|
||||
const QStringList &files,
|
||||
const QString &insertTextOnCancel);
|
||||
bool confirmSendingFiles(
|
||||
Ui::PreparedList &&list,
|
||||
const QString &insertTextOnCancel = QString());
|
||||
bool confirmSendingFiles(
|
||||
not_null<const QMimeData*> data,
|
||||
std::optional<bool> overrideSendImagesAsPhotos,
|
||||
const QString &insertTextOnCancel = QString());
|
||||
bool showSendingFilesError(const Ui::PreparedList &list) const;
|
||||
bool showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const;
|
||||
void sendingFilesConfirmed(
|
||||
Ui::PreparedList &&list,
|
||||
Ui::SendFilesWay way,
|
||||
TextWithTags &&caption,
|
||||
Api::SendOptions options,
|
||||
bool ctrlShiftEnter);
|
||||
void finishSending();
|
||||
|
||||
void initGeometry();
|
||||
void initActions();
|
||||
|
||||
[[nodiscard]] Api::SendAction prepareSendAction(
|
||||
Api::SendOptions options) const;
|
||||
void send(Api::SendOptions options);
|
||||
void sendVoice(VoiceToSend &&data);
|
||||
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
|
||||
|
@ -58,6 +105,7 @@ private:
|
|||
const std::unique_ptr<HistoryView::ComposeControls> _controls;
|
||||
|
||||
ReplyAreaData _data;
|
||||
base::has_weak_ptr _shownUserGuard;
|
||||
bool _choosingAttach = false;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
|
|
@ -467,6 +467,9 @@ storiesRemoveSet: IconButton(stickerPanRemoveSet) {
|
|||
iconOver: icon {{ "simple_close", storiesComposeGrayIcon }};
|
||||
ripple: storiesComposeRippleLight;
|
||||
}
|
||||
storiesMenuSeparator: MenuSeparator(defaultMenuSeparator) {
|
||||
fg: groupCallMenuBgOver;
|
||||
}
|
||||
storiesMenu: Menu(defaultMenu) {
|
||||
itemBg: groupCallMenuBg;
|
||||
itemBgOver: groupCallMenuBgOver;
|
||||
|
@ -477,9 +480,7 @@ storiesMenu: Menu(defaultMenu) {
|
|||
itemFgShortcutOver: groupCallMemberNotJoinedStatus;
|
||||
itemFgShortcutDisabled: groupCallMemberNotJoinedStatus;
|
||||
|
||||
separator: MenuSeparator(defaultMenuSeparator) {
|
||||
fg: groupCallMenuBgOver;
|
||||
}
|
||||
separator: storiesMenuSeparator;
|
||||
arrow: icon {{ "menu/submenu_arrow", groupCallMemberNotJoinedStatus }};
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
|
@ -507,6 +508,23 @@ storiesPopupMenuWithIcons: PopupMenu(storiesPopupMenu) {
|
|||
menu: storiesMenuWithIcons;
|
||||
}
|
||||
|
||||
storiesAttachEmojiInner: IconButton(storiesAttach) {
|
||||
icon: icon {{ "chat/input_smile_face", storiesComposeGrayIcon }};
|
||||
iconOver: icon {{ "chat/input_smile_face", storiesComposeGrayIcon }};
|
||||
}
|
||||
storiesAttachEmoji: EmojiButton(historyAttachEmoji) {
|
||||
inner: storiesAttachEmojiInner;
|
||||
bg: storiesComposeBg;
|
||||
lineFg: storiesComposeGrayIcon;
|
||||
lineFgOver: storiesComposeGrayIcon;
|
||||
}
|
||||
storiesComposePremium: PremiumLimits(defaultPremiumLimits) {
|
||||
boxLabel: FlatLabel(boxLabel) {
|
||||
textFg: groupCallMembersFg;
|
||||
}
|
||||
nonPremiumBg: storiesComposeBgOver;
|
||||
nonPremiumFg: storiesComposeWhiteText;
|
||||
}
|
||||
storiesComposeControls: ComposeControls(defaultComposeControls) {
|
||||
bg: storiesComposeBg;
|
||||
radius: storiesRadius;
|
||||
|
@ -528,15 +546,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
|
|||
sendDisabledFg: storiesComposeGrayText;
|
||||
}
|
||||
attach: storiesAttach;
|
||||
emoji: EmojiButton(historyAttachEmoji) {
|
||||
inner: IconButton(storiesAttach) {
|
||||
icon: icon {{ "chat/input_smile_face", storiesComposeGrayIcon }};
|
||||
iconOver: icon {{ "chat/input_smile_face", storiesComposeGrayIcon }};
|
||||
}
|
||||
bg: storiesComposeBg;
|
||||
lineFg: storiesComposeGrayIcon;
|
||||
lineFgOver: storiesComposeGrayIcon;
|
||||
}
|
||||
emoji: storiesAttachEmoji;
|
||||
suggestions: EmojiSuggestions(defaultEmojiSuggestions) {
|
||||
dropdown: InnerDropdown(emojiSuggestionsDropdown) {
|
||||
animation: PanelAnimation(defaultPanelAnimation) {
|
||||
|
@ -569,6 +579,10 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
|
|||
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", storiesComposeBg }};
|
||||
fadeRight: icon {{ "fade_horizontal", storiesComposeBg }};
|
||||
menu: storiesPopupMenuWithIcons;
|
||||
expandedSeparator: MenuSeparator(storiesMenuSeparator) {
|
||||
padding: margins(0px, 4px, 0px, 4px);
|
||||
width: 6px;
|
||||
}
|
||||
tabs: SettingsSlider(emojiTabs) {
|
||||
barFgActive: storiesComposeBlue;
|
||||
labelFg: storiesComposeGrayText;
|
||||
|
@ -638,6 +652,8 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
|
|||
menuMute: icon {{ "menu/mute", storiesComposeWhiteText }};
|
||||
menuSchedule: icon {{ "menu/calendar", storiesComposeWhiteText }};
|
||||
menuWhenOnline: icon {{ "menu/send_when_online", storiesComposeWhiteText }};
|
||||
menuSpoiler: icon {{ "menu/spoiler_on", storiesComposeWhiteText }};
|
||||
menuSpoilerOff: icon {{ "menu/spoiler_off", storiesComposeWhiteText }};
|
||||
}
|
||||
autocompleteBottomSkip: 10px;
|
||||
}
|
||||
|
@ -664,4 +680,51 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
|
|||
iconPosition: point(10px, 11px);
|
||||
}
|
||||
}
|
||||
files: ComposeFiles(defaultComposeFiles) {
|
||||
check: Check(defaultCheck) {
|
||||
untoggledFg: groupCallMemberNotJoinedStatus;
|
||||
toggledFg: groupCallActiveFg;
|
||||
icon: icon {{ "default_checkbox_check", groupCallMembersFg, point(4px, 7px) }};
|
||||
}
|
||||
checkbox: Checkbox(defaultBoxCheckbox) {
|
||||
textFg: groupCallMembersFg;
|
||||
textFgActive: groupCallMembersFg;
|
||||
rippleBg: groupCallMembersBgRipple;
|
||||
rippleBgActive: groupCallMembersBgRipple;
|
||||
}
|
||||
menu: IconButton(defaultComposeFilesMenu) {
|
||||
icon: icon {{ "title_menu_dots", storiesComposeGrayIcon }};
|
||||
iconOver: icon {{ "title_menu_dots", storiesComposeGrayIcon }};
|
||||
ripple: storiesComposeRippleLight;
|
||||
}
|
||||
caption: InputField(defaultComposeFilesField) {
|
||||
textFg: storiesComposeWhiteText;
|
||||
textBg: storiesComposeBg;
|
||||
placeholderFg: storiesComposeGrayText;
|
||||
placeholderFgActive: storiesComposeBlue;
|
||||
borderFg: storiesComposeGrayText;
|
||||
borderFgActive: storiesComposeBlue;
|
||||
menu: storiesPopupMenu;
|
||||
}
|
||||
emoji: EmojiButton(storiesAttachEmoji) {
|
||||
inner: IconButton(storiesAttachEmojiInner) {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
rippleAreaSize: 0px;
|
||||
}
|
||||
}
|
||||
confirmBg: storiesComposeBgOver;
|
||||
buttonFile: IconButton(sendBoxAlbumGroupButtonFile) {
|
||||
ripple: storiesComposeRipple;
|
||||
}
|
||||
buttonFileEdit: icon {{ "send_media/send_media_replace", storiesComposeGrayIcon }};
|
||||
buttonFileDelete: icon {{ "send_media/send_media_delete", storiesComposeGrayIcon }};
|
||||
iconBg: storiesComposeBlue;
|
||||
iconPlay: icon {{ "history_file_play", storiesComposeWhiteText }};
|
||||
iconImage: icon {{ "history_file_image", storiesComposeWhiteText }};
|
||||
iconDocument: icon {{ "history_file_document", storiesComposeWhiteText }};
|
||||
nameFg: storiesComposeWhiteText;
|
||||
statusFg: storiesComposeGrayText;
|
||||
}
|
||||
premium: storiesComposePremium;
|
||||
}
|
||||
|
|
|
@ -287,6 +287,87 @@ struct OverlayWidget::PipWrap {
|
|||
rpl::lifetime lifetime;
|
||||
};
|
||||
|
||||
class OverlayWidget::Show final : public ChatHelpers::Show {
|
||||
public:
|
||||
explicit Show(not_null<OverlayWidget*> widget) : _widget(widget) {
|
||||
}
|
||||
|
||||
void activate() override {
|
||||
if (!_widget->isHidden()) {
|
||||
_widget->activate();
|
||||
}
|
||||
}
|
||||
|
||||
void showOrHideBoxOrLayer(
|
||||
std::variant<
|
||||
v::null_t,
|
||||
object_ptr<Ui::BoxContent>,
|
||||
std::unique_ptr<Ui::LayerWidget>> &&layer,
|
||||
Ui::LayerOptions options,
|
||||
anim::type animated) const override {
|
||||
_widget->_layerBg->uiShow()->showOrHideBoxOrLayer(
|
||||
std::move(layer),
|
||||
options,
|
||||
anim::type::normal);
|
||||
}
|
||||
not_null<QWidget*> toastParent() const override {
|
||||
return _widget->_body;
|
||||
}
|
||||
bool valid() const override {
|
||||
return _widget->_storiesSession != nullptr;
|
||||
}
|
||||
operator bool() const override {
|
||||
return valid();
|
||||
}
|
||||
|
||||
Main::Session &session() const override {
|
||||
Expects(_widget->_storiesSession != nullptr);
|
||||
|
||||
return *_widget->_storiesSession;
|
||||
}
|
||||
bool paused(ChatHelpers::PauseReason reason) const override {
|
||||
if (_widget->isHidden()
|
||||
|| (!_widget->_fullscreen
|
||||
&& !_widget->_window->isActiveWindow())) {
|
||||
return true;
|
||||
} else if (reason < ChatHelpers::PauseReason::Layer
|
||||
&& _widget->_layerBg->topShownLayer() != nullptr) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
rpl::producer<> pauseChanged() const override {
|
||||
return rpl::never<>();
|
||||
}
|
||||
|
||||
rpl::producer<bool> adjustShadowLeft() const override {
|
||||
return rpl::single(false);
|
||||
}
|
||||
SendMenu::Type sendMenuType() const override {
|
||||
return SendMenu::Type::SilentOnly;
|
||||
}
|
||||
|
||||
bool showMediaPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<DocumentData*> document) const override {
|
||||
return false; // #TODO stories
|
||||
}
|
||||
bool showMediaPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<PhotoData*> photo) const override {
|
||||
return false; // #TODO stories
|
||||
}
|
||||
|
||||
void processChosenSticker(
|
||||
ChatHelpers::FileChosen &&chosen) const override {
|
||||
_widget->_storiesStickerOrEmojiChosen.fire(std::move(chosen));
|
||||
}
|
||||
|
||||
private:
|
||||
not_null<OverlayWidget*> _widget;
|
||||
|
||||
};
|
||||
|
||||
OverlayWidget::Streamed::Streamed(
|
||||
not_null<DocumentData*> document,
|
||||
Data::FileOrigin origin,
|
||||
|
@ -3936,81 +4017,10 @@ not_null<Ui::RpWidget*> OverlayWidget::storiesWrap() {
|
|||
}
|
||||
|
||||
std::shared_ptr<ChatHelpers::Show> OverlayWidget::storiesShow() {
|
||||
class Show final : public ChatHelpers::Show {
|
||||
public:
|
||||
explicit Show(not_null<OverlayWidget*> widget) : _widget(widget) {
|
||||
}
|
||||
|
||||
void showBox(
|
||||
object_ptr<Ui::BoxContent> content,
|
||||
Ui::LayerOptions options
|
||||
= Ui::LayerOption::KeepOther) const override {
|
||||
_widget->_layerBg->showBox(
|
||||
std::move(content),
|
||||
options,
|
||||
anim::type::normal);
|
||||
}
|
||||
void hideLayer() const override {
|
||||
_widget->_layerBg->hideAll(anim::type::normal);
|
||||
}
|
||||
not_null<QWidget*> toastParent() const override {
|
||||
return _widget->_body;
|
||||
}
|
||||
bool valid() const override {
|
||||
return _widget->_storiesSession != nullptr;
|
||||
}
|
||||
operator bool() const override {
|
||||
return valid();
|
||||
}
|
||||
|
||||
Main::Session &session() const override {
|
||||
Expects(_widget->_storiesSession != nullptr);
|
||||
|
||||
return *_widget->_storiesSession;
|
||||
}
|
||||
bool paused(ChatHelpers::PauseReason reason) const override {
|
||||
if (_widget->isHidden()
|
||||
|| (!_widget->_fullscreen
|
||||
&& !_widget->_window->isActiveWindow())) {
|
||||
return true;
|
||||
} else if (reason < ChatHelpers::PauseReason::Layer
|
||||
&& _widget->_layerBg->topShownLayer() != nullptr) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
rpl::producer<> pauseChanged() const override {
|
||||
return rpl::never<>();
|
||||
}
|
||||
|
||||
rpl::producer<bool> adjustShadowLeft() const override {
|
||||
return rpl::single(false);
|
||||
}
|
||||
SendMenu::Type sendMenuType() const override {
|
||||
return SendMenu::Type::SilentOnly;
|
||||
}
|
||||
|
||||
bool showMediaPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<DocumentData*> document) const override {
|
||||
return false; // #TODO stories
|
||||
}
|
||||
bool showMediaPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<PhotoData*> photo) const override {
|
||||
return false; // #TODO stories
|
||||
}
|
||||
|
||||
void processChosenSticker(
|
||||
ChatHelpers::FileChosen &&chosen) const override {
|
||||
_widget->_storiesStickerOrEmojiChosen.fire(std::move(chosen));
|
||||
}
|
||||
|
||||
private:
|
||||
not_null<OverlayWidget*> _widget;
|
||||
|
||||
};
|
||||
return std::make_shared<Show>(this);
|
||||
if (!_cachedShow) {
|
||||
_cachedShow = std::make_shared<Show>(this);
|
||||
}
|
||||
return _cachedShow;
|
||||
}
|
||||
|
||||
auto OverlayWidget::storiesStickerOrEmojiChosen()
|
||||
|
@ -5753,6 +5763,7 @@ void OverlayWidget::clearBeforeHide() {
|
|||
_collageData = std::nullopt;
|
||||
clearStreaming();
|
||||
setStoriesUser(nullptr);
|
||||
_layerBg->hideAll(anim::type::instant);
|
||||
assignMediaPointer(nullptr);
|
||||
_preloadPhotos.clear();
|
||||
_preloadDocuments.clear();
|
||||
|
|
|
@ -131,6 +131,7 @@ public:
|
|||
rpl::lifetime &lifetime();
|
||||
|
||||
private:
|
||||
class Show;
|
||||
struct Streamed;
|
||||
struct PipWrap;
|
||||
class Renderer;
|
||||
|
@ -600,6 +601,7 @@ private:
|
|||
bool _showAsPip = false;
|
||||
|
||||
std::unique_ptr<Stories::View> _stories;
|
||||
std::shared_ptr<Show> _cachedShow;
|
||||
rpl::event_stream<> _storiesChanged;
|
||||
Main::Session *_storiesSession = nullptr;
|
||||
rpl::event_stream<ChatHelpers::FileChosen> _storiesStickerOrEmojiChosen;
|
||||
|
|
|
@ -1782,6 +1782,11 @@ QString LookupPremiumRef(PremiumPreview section) {
|
|||
|
||||
not_null<Ui::GradientButton*> CreateSubscribeButton(
|
||||
SubscribeButtonArgs &&args) {
|
||||
Expects(args.show || args.controller);
|
||||
|
||||
if (!args.show && args.controller) {
|
||||
args.show = args.controller->uiShow();
|
||||
}
|
||||
const auto result = Ui::CreateChild<Ui::GradientButton>(
|
||||
args.parent.get(),
|
||||
args.gradientStops
|
||||
|
@ -1789,9 +1794,14 @@ not_null<Ui::GradientButton*> CreateSubscribeButton(
|
|||
: Ui::Premium::ButtonGradientStops());
|
||||
|
||||
result->setClickedCallback([
|
||||
controller = args.controller,
|
||||
show = args.show,
|
||||
computeRef = args.computeRef,
|
||||
computeBotUrl = args.computeBotUrl] {
|
||||
const auto window = show->resolveWindow(
|
||||
ChatHelpers::WindowUsage::PremiumPromo);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
const auto url = computeBotUrl ? computeBotUrl() : QString();
|
||||
if (!url.isEmpty()) {
|
||||
const auto local = Core::TryConvertUrlToLocal(url);
|
||||
|
@ -1801,12 +1811,12 @@ not_null<Ui::GradientButton*> CreateSubscribeButton(
|
|||
UrlClickHandler::Open(
|
||||
local,
|
||||
QVariant::fromValue(ClickHandlerContext{
|
||||
.sessionWindow = base::make_weak(controller),
|
||||
.sessionWindow = base::make_weak(window),
|
||||
.botStartAutoSubmit = true,
|
||||
}));
|
||||
} else {
|
||||
SendScreenAccept(controller);
|
||||
StartPremiumPayment(controller, computeRef());
|
||||
SendScreenAccept(window);
|
||||
StartPremiumPayment(window, computeRef());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
enum class PremiumPreview;
|
||||
|
||||
namespace ChatHelpers {
|
||||
class Show;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
class GradientButton;
|
||||
|
@ -48,12 +52,13 @@ void StartPremiumPayment(
|
|||
[[nodiscard]] QString LookupPremiumRef(PremiumPreview section);
|
||||
|
||||
struct SubscribeButtonArgs final {
|
||||
not_null<Window::SessionController*> controller;
|
||||
Window::SessionController *controller = nullptr;
|
||||
not_null<Ui::RpWidget*> parent;
|
||||
Fn<QString()> computeRef;
|
||||
std::optional<rpl::producer<QString>> text;
|
||||
std::optional<QGradientStops> gradientStops;
|
||||
Fn<QString()> computeBotUrl; // nullable
|
||||
std::shared_ptr<ChatHelpers::Show> show;
|
||||
};
|
||||
|
||||
[[nodiscard]] not_null<Ui::GradientButton*> CreateSubscribeButton(
|
||||
|
|
|
@ -1101,7 +1101,7 @@ void FileLoadTask::finish() {
|
|||
} else if (_result->filesize > kFileSizePremiumLimit
|
||||
|| (_result->filesize > kFileSizeLimit && !premium)) {
|
||||
Ui::show(
|
||||
Box(FileSizeLimitBox, session, _result->filesize),
|
||||
Box(FileSizeLimitBox, session, _result->filesize, nullptr),
|
||||
Ui::LayerOption::KeepOther);
|
||||
removeFromAlbum();
|
||||
} else {
|
||||
|
|
|
@ -20,14 +20,16 @@ namespace Ui {
|
|||
|
||||
AbstractSingleFilePreview::AbstractSingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
AttachControls::Type type)
|
||||
: AbstractSinglePreview(parent)
|
||||
, _st(st)
|
||||
, _type(type)
|
||||
, _editMedia(this, st::sendBoxAlbumGroupButtonFile)
|
||||
, _deleteMedia(this, st::sendBoxAlbumGroupButtonFile) {
|
||||
, _editMedia(this, _st.files.buttonFile)
|
||||
, _deleteMedia(this, _st.files.buttonFile) {
|
||||
|
||||
_editMedia->setIconOverride(&st::sendBoxAlbumGroupEditButtonIconFile);
|
||||
_deleteMedia->setIconOverride(&st::sendBoxAlbumGroupDeleteButtonIconFile);
|
||||
_editMedia->setIconOverride(&_st.files.buttonFileEdit);
|
||||
_deleteMedia->setIconOverride(&_st.files.buttonFileDelete);
|
||||
|
||||
if (type == AttachControls::Type::Full) {
|
||||
_deleteMedia->show();
|
||||
|
@ -100,18 +102,17 @@ void AbstractSingleFilePreview::paintEvent(QPaintEvent *e) {
|
|||
if (_data.fileIsAudio && !_data.fileThumb.isNull()) {
|
||||
p.drawPixmap(inner.topLeft(), _data.fileThumb);
|
||||
} else {
|
||||
p.setBrush(st::msgFileInBg);
|
||||
p.setBrush(_st.files.iconBg);
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawEllipse(inner);
|
||||
}
|
||||
|
||||
auto &icon = _data.fileIsAudio
|
||||
? (_data.fileThumb.isNull()
|
||||
? st::historyFileInPlay
|
||||
? _st.files.iconPlay
|
||||
: st::historyFileThumbPlay)
|
||||
: _data.fileIsImage
|
||||
? st::historyFileInImage
|
||||
: st::historyFileInDocument;
|
||||
? _st.files.iconImage
|
||||
: _st.files.iconDocument;
|
||||
icon.paintInCenter(p, inner);
|
||||
} else {
|
||||
QRect rthumb(
|
||||
|
@ -119,7 +120,7 @@ void AbstractSingleFilePreview::paintEvent(QPaintEvent *e) {
|
|||
p.drawPixmap(rthumb.topLeft(), _data.fileThumb);
|
||||
}
|
||||
p.setFont(st::semiboldFont);
|
||||
p.setPen(st::historyFileNameInFg);
|
||||
p.setPen(_st.files.nameFg);
|
||||
p.drawTextLeft(
|
||||
x + nameleft,
|
||||
y + nametop, width(),
|
||||
|
@ -127,7 +128,7 @@ void AbstractSingleFilePreview::paintEvent(QPaintEvent *e) {
|
|||
_data.nameWidth);
|
||||
|
||||
p.setFont(st::normalFont);
|
||||
p.setPen(st::mediaInFg);
|
||||
p.setPen(_st.files.statusFg);
|
||||
p.drawTextLeft(
|
||||
x + nameleft,
|
||||
y + statustop,
|
||||
|
@ -167,7 +168,7 @@ void AbstractSingleFilePreview::updateTextWidthFor(Data &data) {
|
|||
- st.thumbSize
|
||||
- st.thumbSkip
|
||||
// Right buttons.
|
||||
- st::sendBoxAlbumGroupButtonFile.width * buttonsCount
|
||||
- _st.files.buttonFile.width * buttonsCount
|
||||
- st::sendBoxAlbumGroupEditInternalSkip * buttonsCount
|
||||
- st::sendBoxAlbumGroupSkipRight;
|
||||
data.nameWidth = st::semiboldFont->width(data.name);
|
||||
|
|
|
@ -11,13 +11,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/chat/attach/attach_controls.h"
|
||||
#include "base/object_ptr.h"
|
||||
|
||||
namespace style {
|
||||
struct ComposeControls;
|
||||
} // namespace style
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class IconButton;
|
||||
|
||||
class AbstractSingleFilePreview : public AbstractSinglePreview {
|
||||
public:
|
||||
AbstractSingleFilePreview(QWidget *parent, AttachControls::Type type);
|
||||
AbstractSingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
AttachControls::Type type);
|
||||
~AbstractSingleFilePreview();
|
||||
|
||||
[[nodiscard]] rpl::producer<> deleteRequests() const override;
|
||||
|
@ -46,6 +53,7 @@ private:
|
|||
|
||||
void updateTextWidthFor(Data &data);
|
||||
|
||||
const style::ComposeControls &_st;
|
||||
const AttachControls::Type _type;
|
||||
|
||||
Data _data;
|
||||
|
|
|
@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
|
@ -30,8 +31,10 @@ constexpr auto kMinPreviewWidth = 20;
|
|||
|
||||
AbstractSingleMediaPreview::AbstractSingleMediaPreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
AttachControls::Type type)
|
||||
: AbstractSinglePreview(parent)
|
||||
, _st(st)
|
||||
, _minThumbH(st::sendBoxAlbumGroupSize.height()
|
||||
+ st::sendBoxAlbumGroupSkipTop * 2)
|
||||
, _controls(base::make_unique_q<AttachControlsWidget>(this, type)) {
|
||||
|
@ -173,7 +176,7 @@ void AbstractSingleMediaPreview::paintEvent(QPaintEvent *e) {
|
|||
_previewTop,
|
||||
_previewLeft - padding.left(),
|
||||
_previewHeight,
|
||||
st::confirmBg);
|
||||
_st.files.confirmBg);
|
||||
}
|
||||
if ((_previewLeft + _previewWidth) < (width() - padding.right())) {
|
||||
p.fillRect(
|
||||
|
@ -181,7 +184,7 @@ void AbstractSingleMediaPreview::paintEvent(QPaintEvent *e) {
|
|||
_previewTop,
|
||||
width() - padding.right() - _previewLeft - _previewWidth,
|
||||
_previewHeight,
|
||||
st::confirmBg);
|
||||
_st.files.confirmBg);
|
||||
}
|
||||
if (_previewTop > 0) {
|
||||
p.fillRect(
|
||||
|
@ -189,7 +192,7 @@ void AbstractSingleMediaPreview::paintEvent(QPaintEvent *e) {
|
|||
0,
|
||||
width() - padding.right() - padding.left(),
|
||||
height(),
|
||||
st::confirmBg);
|
||||
_st.files.confirmBg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,14 +267,15 @@ void AbstractSingleMediaPreview::showContextMenu(QPoint position) {
|
|||
}
|
||||
_menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
this,
|
||||
st::popupMenuWithIcons);
|
||||
_st.tabbed.menu);
|
||||
|
||||
const auto &icons = _st.tabbed.icons;
|
||||
const auto spoilered = hasSpoiler();
|
||||
_menu->addAction(spoilered
|
||||
? tr::lng_context_disable_spoiler(tr::now)
|
||||
: tr::lng_context_spoiler_effect(tr::now), [=] {
|
||||
setSpoiler(!spoilered);
|
||||
}, spoilered ? &st::menuIconSpoilerOff : &st::menuIconSpoiler);
|
||||
}, spoilered ? &icons.menuSpoilerOff : &icons.menuSpoiler);
|
||||
|
||||
if (_menu->empty()) {
|
||||
_menu = nullptr;
|
||||
|
|
|
@ -12,13 +12,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/chat/attach/attach_send_files_way.h"
|
||||
#include "ui/abstract_button.h"
|
||||
|
||||
namespace style {
|
||||
struct ComposeControls;
|
||||
} // namespace style
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class PopupMenu;
|
||||
|
||||
class AbstractSingleMediaPreview : public AbstractSinglePreview {
|
||||
public:
|
||||
AbstractSingleMediaPreview(QWidget *parent, AttachControls::Type type);
|
||||
AbstractSingleMediaPreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
AttachControls::Type type);
|
||||
~AbstractSingleMediaPreview();
|
||||
|
||||
void setSendWay(SendFilesWay way);
|
||||
|
@ -60,6 +67,7 @@ private:
|
|||
void applyCursor(style::cursor cursor);
|
||||
void showContextMenu(QPoint position);
|
||||
|
||||
const style::ComposeControls &_st;
|
||||
SendFilesWay _sendWay;
|
||||
bool _animated = false;
|
||||
QPixmap _preview;
|
||||
|
|
|
@ -28,9 +28,11 @@ constexpr auto kDragDuration = crl::time(200);
|
|||
|
||||
AlbumPreview::AlbumPreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
gsl::span<Ui::PreparedFile> items,
|
||||
SendFilesWay way)
|
||||
: RpWidget(parent)
|
||||
, _st(st)
|
||||
, _sendWay(way)
|
||||
, _dragTimer([=] { switchToDrag(); }) {
|
||||
setMouseTracking(true);
|
||||
|
@ -135,6 +137,7 @@ void AlbumPreview::prepareThumbs(gsl::span<Ui::PreparedFile> items) {
|
|||
_thumbs.reserve(count);
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
_thumbs.push_back(std::make_unique<AlbumThumbnail>(
|
||||
_st,
|
||||
items[i],
|
||||
layout[i],
|
||||
this,
|
||||
|
|
|
@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/chat/attach/attach_send_files_way.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
namespace style {
|
||||
struct ComposeControls;
|
||||
} // namespace style
|
||||
|
||||
namespace Ui {
|
||||
|
||||
struct PreparedFile;
|
||||
|
@ -22,6 +26,7 @@ class AlbumPreview final : public RpWidget {
|
|||
public:
|
||||
AlbumPreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
gsl::span<Ui::PreparedFile> items,
|
||||
SendFilesWay way);
|
||||
~AlbumPreview();
|
||||
|
@ -86,6 +91,7 @@ private:
|
|||
|
||||
void showContextMenu(not_null<AlbumThumbnail*> thumb, QPoint position);
|
||||
|
||||
const style::ComposeControls &_st;
|
||||
SendFilesWay _sendWay;
|
||||
style::cursor _cursor = style::cur_default;
|
||||
std::vector<int> _order;
|
||||
|
|
|
@ -26,13 +26,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace Ui {
|
||||
|
||||
AlbumThumbnail::AlbumThumbnail(
|
||||
const style::ComposeControls &st,
|
||||
const PreparedFile &file,
|
||||
const GroupMediaLayout &layout,
|
||||
QWidget *parent,
|
||||
Fn<void()> repaint,
|
||||
Fn<void()> editCallback,
|
||||
Fn<void()> deleteCallback)
|
||||
: _layout(layout)
|
||||
: _st(st)
|
||||
, _layout(layout)
|
||||
, _fullPreview(file.preview)
|
||||
, _shrinkSize(int(std::ceil(st::roundRadiusLarge / 1.4)))
|
||||
, _isPhoto(file.type == PreparedFile::Type::Photo)
|
||||
|
@ -60,8 +62,8 @@ AlbumThumbnail::AlbumThumbnail(
|
|||
.outer = { imageWidth, imageHeight },
|
||||
}));
|
||||
|
||||
const auto &st = st::attachPreviewThumbLayout;
|
||||
const auto idealSize = st.thumbSize * style::DevicePixelRatio();
|
||||
const auto &layoutSt = st::attachPreviewThumbLayout;
|
||||
const auto idealSize = layoutSt.thumbSize * style::DevicePixelRatio();
|
||||
const auto fileThumbSize = (previewWidth > previewHeight)
|
||||
? QSize(previewWidth * idealSize / previewHeight, idealSize)
|
||||
: QSize(idealSize, previewHeight * idealSize / previewWidth);
|
||||
|
@ -70,12 +72,12 @@ AlbumThumbnail::AlbumThumbnail(
|
|||
fileThumbSize,
|
||||
{
|
||||
.options = Option::RoundSmall,
|
||||
.outer = { st.thumbSize, st.thumbSize },
|
||||
.outer = { layoutSt.thumbSize, layoutSt.thumbSize },
|
||||
}));
|
||||
|
||||
const auto availableFileWidth = st::sendMediaPreviewSize
|
||||
- st.thumbSize
|
||||
- st.thumbSkip
|
||||
- layoutSt.thumbSize
|
||||
- layoutSt.thumbSkip
|
||||
// Right buttons.
|
||||
- st::sendBoxAlbumGroupButtonFile.width * 2
|
||||
- st::sendBoxAlbumGroupEditInternalSkip * 2
|
||||
|
@ -99,8 +101,8 @@ AlbumThumbnail::AlbumThumbnail(
|
|||
}
|
||||
_statusWidth = st::normalFont->width(_status);
|
||||
|
||||
_editMedia.create(parent, st::sendBoxAlbumGroupButtonFile);
|
||||
_deleteMedia.create(parent, st::sendBoxAlbumGroupButtonFile);
|
||||
_editMedia.create(parent, _st.files.buttonFile);
|
||||
_deleteMedia.create(parent, _st.files.buttonFile);
|
||||
|
||||
const auto duration = st::historyAttach.ripple.hideDuration;
|
||||
_editMedia->setClickedCallback([=] {
|
||||
|
@ -108,8 +110,8 @@ AlbumThumbnail::AlbumThumbnail(
|
|||
});
|
||||
_deleteMedia->setClickedCallback(deleteCallback);
|
||||
|
||||
_editMedia->setIconOverride(&st::sendBoxAlbumGroupEditButtonIconFile);
|
||||
_deleteMedia->setIconOverride(&st::sendBoxAlbumGroupDeleteButtonIconFile);
|
||||
_editMedia->setIconOverride(&_st.files.buttonFileEdit);
|
||||
_deleteMedia->setIconOverride(&_st.files.buttonFileDelete);
|
||||
|
||||
setSpoiler(file.spoiler);
|
||||
setButtonVisible(false);
|
||||
|
@ -482,7 +484,7 @@ void AlbumThumbnail::paintFile(
|
|||
|
||||
p.drawPixmap(left, top, _fileThumb);
|
||||
p.setFont(st::semiboldFont);
|
||||
p.setPen(st::historyFileNameInFg);
|
||||
p.setPen(_st.files.nameFg);
|
||||
p.drawTextLeft(
|
||||
textLeft,
|
||||
top + st.nameTop,
|
||||
|
@ -490,7 +492,7 @@ void AlbumThumbnail::paintFile(
|
|||
_name,
|
||||
_nameWidth);
|
||||
p.setFont(st::normalFont);
|
||||
p.setPen(st::mediaInFg);
|
||||
p.setPen(_st.files.statusFg);
|
||||
p.drawTextLeft(
|
||||
textLeft,
|
||||
top + st.statusTop,
|
||||
|
|
|
@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/round_rect.h"
|
||||
#include "base/object_ptr.h"
|
||||
|
||||
namespace style {
|
||||
struct ComposeControls;
|
||||
} // namespace style
|
||||
|
||||
namespace Ui {
|
||||
|
||||
struct PreparedFile;
|
||||
|
@ -23,6 +27,7 @@ class SpoilerAnimation;
|
|||
class AlbumThumbnail final {
|
||||
public:
|
||||
AlbumThumbnail(
|
||||
const style::ComposeControls &st,
|
||||
const PreparedFile &file,
|
||||
const GroupMediaLayout &layout,
|
||||
QWidget *parent,
|
||||
|
@ -78,6 +83,7 @@ private:
|
|||
float64 shrinkProgress);
|
||||
void paintPlayVideo(QPainter &p, QRect geometry);
|
||||
|
||||
const style::ComposeControls &_st;
|
||||
GroupMediaLayout _layout;
|
||||
std::optional<QRect> _animateFromGeometry;
|
||||
const QImage _fullPreview;
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "ui/chat/attach/attach_controls.h"
|
||||
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
|
|
|
@ -37,9 +37,10 @@ AttachControls::Type CheckControlsType(
|
|||
|
||||
ItemSingleFilePreview::ItemSingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
not_null<HistoryItem*> item,
|
||||
AttachControls::Type type)
|
||||
: AbstractSingleFilePreview(parent, CheckControlsType(item, type)) {
|
||||
: AbstractSingleFilePreview(parent, st, CheckControlsType(item, type)) {
|
||||
const auto media = item->media();
|
||||
Assert(media != nullptr);
|
||||
const auto document = media->document();
|
||||
|
|
|
@ -25,6 +25,7 @@ class ItemSingleFilePreview final : public AbstractSingleFilePreview {
|
|||
public:
|
||||
ItemSingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
not_null<HistoryItem*> item,
|
||||
AttachControls::Type type);
|
||||
|
||||
|
|
|
@ -32,10 +32,11 @@ using namespace ::Media::Streaming;
|
|||
|
||||
ItemSingleMediaPreview::ItemSingleMediaPreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
Fn<bool()> gifPaused,
|
||||
not_null<HistoryItem*> item,
|
||||
AttachControls::Type type)
|
||||
: AbstractSingleMediaPreview(parent, type)
|
||||
: AbstractSingleMediaPreview(parent, st, type)
|
||||
, _gifPaused(std::move(gifPaused))
|
||||
, _fullId(item->fullId()) {
|
||||
const auto media = item->media();
|
||||
|
|
|
@ -32,6 +32,7 @@ class ItemSingleMediaPreview final : public AbstractSingleMediaPreview {
|
|||
public:
|
||||
ItemSingleMediaPreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
Fn<bool()> gifPaused,
|
||||
not_null<HistoryItem*> item,
|
||||
AttachControls::Type type);
|
||||
|
|
|
@ -19,9 +19,10 @@ namespace Ui {
|
|||
|
||||
SingleFilePreview::SingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
const PreparedFile &file,
|
||||
AttachControls::Type type)
|
||||
: AbstractSingleFilePreview(parent, type) {
|
||||
: AbstractSingleFilePreview(parent, st, type) {
|
||||
preparePreview(file);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ class SingleFilePreview final : public AbstractSingleFilePreview {
|
|||
public:
|
||||
SingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
const PreparedFile &file,
|
||||
AttachControls::Type type = AttachControls::Type::Full);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Ui {
|
|||
|
||||
SingleMediaPreview *SingleMediaPreview::Create(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
Fn<bool()> gifPaused,
|
||||
const PreparedFile &file,
|
||||
AttachControls::Type type) {
|
||||
|
@ -43,6 +44,7 @@ SingleMediaPreview *SingleMediaPreview::Create(
|
|||
}
|
||||
return CreateChild<SingleMediaPreview>(
|
||||
parent,
|
||||
st,
|
||||
std::move(gifPaused),
|
||||
preview,
|
||||
animated,
|
||||
|
@ -54,6 +56,7 @@ SingleMediaPreview *SingleMediaPreview::Create(
|
|||
|
||||
SingleMediaPreview::SingleMediaPreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
Fn<bool()> gifPaused,
|
||||
QImage preview,
|
||||
bool animated,
|
||||
|
@ -61,7 +64,7 @@ SingleMediaPreview::SingleMediaPreview(
|
|||
bool spoiler,
|
||||
const QString &animatedPreviewPath,
|
||||
AttachControls::Type type)
|
||||
: AbstractSingleMediaPreview(parent, type)
|
||||
: AbstractSingleMediaPreview(parent, st, type)
|
||||
, _gifPaused(std::move(gifPaused))
|
||||
, _sticker(sticker) {
|
||||
Expects(!preview.isNull());
|
||||
|
|
|
@ -22,12 +22,14 @@ class SingleMediaPreview final : public AbstractSingleMediaPreview {
|
|||
public:
|
||||
static SingleMediaPreview *Create(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
Fn<bool()> gifPaused,
|
||||
const PreparedFile &file,
|
||||
AttachControls::Type type = AttachControls::Type::Full);
|
||||
|
||||
SingleMediaPreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
Fn<bool()> gifPaused,
|
||||
QImage preview,
|
||||
bool animated,
|
||||
|
|
|
@ -7,7 +7,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
using "ui/basic.style";
|
||||
using "ui/widgets/widgets.style";
|
||||
using "settings/settings.style";
|
||||
using "ui/layers/layers.style";
|
||||
|
||||
PremiumLimits {
|
||||
boxLabel: FlatLabel;
|
||||
nonPremiumBg: color;
|
||||
nonPremiumFg: color;
|
||||
}
|
||||
|
||||
defaultPremiumBoxLabel: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 220px;
|
||||
align: align(topleft);
|
||||
style: TextStyle(boxTextStyle) {
|
||||
lineHeight: 22px;
|
||||
}
|
||||
}
|
||||
defaultPremiumLimits: PremiumLimits {
|
||||
boxLabel: defaultPremiumBoxLabel;
|
||||
nonPremiumBg: windowBgOver;
|
||||
nonPremiumFg: windowFg;
|
||||
}
|
||||
|
||||
// Preview.
|
||||
premiumPreviewBox: Box(defaultBox) {
|
||||
|
@ -144,8 +163,10 @@ premiumGiftUserpicPadding: margins(10px, 27px, 18px, 13px);
|
|||
premiumGiftTitlePadding: margins(18px, 0px, 18px, 0px);
|
||||
premiumGiftAboutPadding: margins(18px, 5px, 18px, 23px);
|
||||
premiumGiftTermsPadding: margins(18px, 27px, 18px, 0px);
|
||||
|
||||
premiumGiftTerms: FlatLabel(settingLocalPasscodeDescription) {
|
||||
premiumGiftTerms: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 256px;
|
||||
align: align(top);
|
||||
textFg: windowSubTextFg;
|
||||
style: TextStyle(defaultTextStyle) {
|
||||
font: font(11px);
|
||||
linkFont: font(11px);
|
||||
|
|
|
@ -596,12 +596,14 @@ class Line final : public Ui::RpWidget {
|
|||
public:
|
||||
Line(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
const style::PremiumLimits &st,
|
||||
int max,
|
||||
TextFactory textFactory,
|
||||
int min,
|
||||
float64 ratio);
|
||||
Line(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
const style::PremiumLimits &st,
|
||||
QString max,
|
||||
QString min,
|
||||
float64 ratio);
|
||||
|
@ -614,6 +616,8 @@ protected:
|
|||
private:
|
||||
void recache(const QSize &s);
|
||||
|
||||
const style::PremiumLimits &_st;
|
||||
|
||||
int _leftWidth = 0;
|
||||
int _rightWidth = 0;
|
||||
|
||||
|
@ -631,12 +635,14 @@ private:
|
|||
|
||||
Line::Line(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
const style::PremiumLimits &st,
|
||||
int max,
|
||||
TextFactory textFactory,
|
||||
int min,
|
||||
float64 ratio)
|
||||
: Line(
|
||||
parent,
|
||||
st,
|
||||
max ? textFactory(max) : QString(),
|
||||
min ? textFactory(min) : QString(),
|
||||
ratio) {
|
||||
|
@ -644,10 +650,12 @@ Line::Line(
|
|||
|
||||
Line::Line(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
const style::PremiumLimits &st,
|
||||
QString max,
|
||||
QString min,
|
||||
float64 ratio)
|
||||
: Ui::RpWidget(parent)
|
||||
, _st(st)
|
||||
, _leftText(st::semiboldTextStyle, tr::lng_premium_free(tr::now))
|
||||
, _rightText(st::semiboldTextStyle, tr::lng_premium(tr::now))
|
||||
, _rightLabel(st::semiboldTextStyle, max)
|
||||
|
@ -689,7 +697,7 @@ void Line::paintEvent(QPaintEvent *event) {
|
|||
+ _leftText.maxWidth()
|
||||
+ 3 * textPadding;
|
||||
if (_leftWidth >= leftMinWidth) {
|
||||
p.setPen(st::windowFg);
|
||||
p.setPen(_st.nonPremiumFg);
|
||||
_leftLabel.drawRight(
|
||||
p,
|
||||
textPadding,
|
||||
|
@ -751,7 +759,7 @@ void Line::recache(const QSize &s) {
|
|||
halfRect.setLeft(halfRect.center().x());
|
||||
pathRect.addRect(halfRect);
|
||||
|
||||
p.fillPath(pathRound(_leftWidth) + pathRect, st::windowBgOver);
|
||||
p.fillPath(pathRound(_leftWidth) + pathRect, _st.nonPremiumBg);
|
||||
|
||||
_leftPixmap = std::move(leftPixmap);
|
||||
}
|
||||
|
@ -811,16 +819,18 @@ void AddBubbleRow(
|
|||
|
||||
void AddLimitRow(
|
||||
not_null<Ui::VerticalLayout*> parent,
|
||||
const style::PremiumLimits &st,
|
||||
QString max,
|
||||
QString min,
|
||||
float64 ratio) {
|
||||
parent->add(
|
||||
object_ptr<Line>(parent, max, min, ratio),
|
||||
object_ptr<Line>(parent, st, max, min, ratio),
|
||||
st::boxRowPadding);
|
||||
}
|
||||
|
||||
void AddLimitRow(
|
||||
not_null<Ui::VerticalLayout*> parent,
|
||||
const style::PremiumLimits &st,
|
||||
int max,
|
||||
std::optional<tr::phrase<lngtag_count>> phrase,
|
||||
int min,
|
||||
|
@ -828,6 +838,7 @@ void AddLimitRow(
|
|||
const auto factory = ProcessTextFactory(phrase);
|
||||
AddLimitRow(
|
||||
parent,
|
||||
st,
|
||||
max ? factory(max) : QString(),
|
||||
min ? factory(min) : QString(),
|
||||
ratio);
|
||||
|
@ -1009,6 +1020,7 @@ QGradientStops GiftGradientStops() {
|
|||
|
||||
void ShowListBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
const style::PremiumLimits &st,
|
||||
std::vector<ListEntry> entries) {
|
||||
|
||||
const auto &stLabel = st::defaultFlatLabel;
|
||||
|
@ -1036,6 +1048,7 @@ void ShowListBox(
|
|||
const auto limitRow = content->add(
|
||||
object_ptr<Line>(
|
||||
content,
|
||||
st,
|
||||
entry.rightNumber,
|
||||
TextFactory([=, text = ProcessTextFactory(std::nullopt)](
|
||||
int n) {
|
||||
|
|
|
@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "ui/effects/round_checkbox.h"
|
||||
|
||||
namespace style {
|
||||
struct PremiumLimits;
|
||||
} // namespace style
|
||||
|
||||
namespace tr {
|
||||
template <typename ...>
|
||||
struct phrase;
|
||||
|
@ -48,12 +52,14 @@ void AddBubbleRow(
|
|||
|
||||
void AddLimitRow(
|
||||
not_null<Ui::VerticalLayout*> parent,
|
||||
const style::PremiumLimits &st,
|
||||
QString max,
|
||||
QString min = {},
|
||||
float64 ratio = kLimitRowRatio);
|
||||
|
||||
void AddLimitRow(
|
||||
not_null<Ui::VerticalLayout*> parent,
|
||||
const style::PremiumLimits &st,
|
||||
int max,
|
||||
std::optional<tr::phrase<lngtag_count>> phrase,
|
||||
int min = 0,
|
||||
|
@ -90,6 +96,7 @@ struct ListEntry final {
|
|||
};
|
||||
void ShowListBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
const style::PremiumLimits &st,
|
||||
std::vector<ListEntry> entries);
|
||||
|
||||
void AddGiftOptions(
|
||||
|
|
|
@ -113,6 +113,8 @@ class MainWindowShow final : public ChatHelpers::Show {
|
|||
public:
|
||||
explicit MainWindowShow(not_null<SessionController*> controller);
|
||||
|
||||
void activate() override;
|
||||
|
||||
void showOrHideBoxOrLayer(
|
||||
std::variant<
|
||||
v::null_t,
|
||||
|
@ -151,6 +153,12 @@ MainWindowShow::MainWindowShow(not_null<SessionController*> controller)
|
|||
: _window(base::make_weak(controller)) {
|
||||
}
|
||||
|
||||
void MainWindowShow::activate() {
|
||||
if (const auto window = _window.get()) {
|
||||
Window::ActivateWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindowShow::showOrHideBoxOrLayer(
|
||||
std::variant<
|
||||
v::null_t,
|
||||
|
@ -244,10 +252,7 @@ void MainWindowShow::processChosenSticker(
|
|||
} // namespace
|
||||
|
||||
void ActivateWindow(not_null<SessionController*> controller) {
|
||||
const auto window = controller->widget();
|
||||
window->raise();
|
||||
window->activateWindow();
|
||||
Ui::ActivateWindowDelayed(window);
|
||||
Ui::ActivateWindow(controller->widget());
|
||||
}
|
||||
|
||||
bool IsPaused(
|
||||
|
|
Loading…
Reference in New Issue