mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Added ability to change caption to every file in SendFilesBox.
This commit is contained in:
@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/call_delayed.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "boxes/send_gif_with_caption_box.h"
|
||||
#include "boxes/send_credits_box.h"
|
||||
#include "ui/effects/scroll_content_shadow.h"
|
||||
#include "ui/widgets/fields/number_input.h"
|
||||
@@ -57,6 +58,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "styles/style_boxes.h"
|
||||
@@ -164,6 +166,58 @@ void RenameFileBox(
|
||||
});
|
||||
}
|
||||
|
||||
void EditFileCaptionBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
const style::ComposeControls &st,
|
||||
PeerData *captionToPeer,
|
||||
TextWithTags currentCaption,
|
||||
Fn<bool(TextWithTags)> apply) {
|
||||
box->setTitle(tr::lng_context_upload_edit_caption());
|
||||
const auto wrap = box->addRow(
|
||||
object_ptr<Ui::RpWidget>(box),
|
||||
st::boxRowPadding);
|
||||
const auto field = Ui::CreateChild<Ui::InputField>(
|
||||
wrap,
|
||||
st.files.caption,
|
||||
Ui::InputField::Mode::MultiLine,
|
||||
tr::lng_photo_caption());
|
||||
field->setMaxLength(kMaxMessageLength);
|
||||
field->setSubmitSettings(Core::App().settings().sendSubmitWay());
|
||||
Ui::ResizeFitChild(wrap, field);
|
||||
if (const auto window = Core::App().findWindow(box)) {
|
||||
const auto controller = window->sessionController();
|
||||
Ui::SetupCaptionFieldInBox(
|
||||
box,
|
||||
controller,
|
||||
field,
|
||||
captionToPeer,
|
||||
[=](not_null<DocumentData*> emoji) {
|
||||
return captionToPeer
|
||||
&& Data::AllowEmojiWithoutPremium(captionToPeer, emoji);
|
||||
},
|
||||
PremiumFeature::EmojiStatus);
|
||||
}
|
||||
field->setTextWithTags(std::move(currentCaption));
|
||||
|
||||
box->setFocusCallback([=] {
|
||||
field->setFocusFast();
|
||||
});
|
||||
const auto save = [=] {
|
||||
const auto text = field->getTextWithAppliedMarkdown();
|
||||
if (!apply(text)) {
|
||||
return;
|
||||
}
|
||||
box->closeBox();
|
||||
};
|
||||
field->submits() | rpl::on_next([=] {
|
||||
save();
|
||||
}, box->lifetime());
|
||||
box->addButton(tr::lng_settings_save(), save);
|
||||
box->addButton(tr::lng_cancel(), [=] {
|
||||
box->closeBox();
|
||||
});
|
||||
}
|
||||
|
||||
void EditPriceBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session,
|
||||
@@ -1449,23 +1503,80 @@ void SendFilesBox::pushBlock(int from, int till) {
|
||||
if (from >= till || from >= _list.files.size()) {
|
||||
return base::EventFilterResult::Continue;
|
||||
}
|
||||
const auto fileIndex = from;
|
||||
auto fileIndex = from;
|
||||
if (const auto album = dynamic_cast<Ui::AlbumPreview*>(widget)) {
|
||||
const auto indexInBlock = album->indexFromPoint(mouse->pos());
|
||||
if (indexInBlock < 0) {
|
||||
return base::EventFilterResult::Continue;
|
||||
}
|
||||
fileIndex += indexInBlock;
|
||||
}
|
||||
if (fileIndex >= till || fileIndex >= _list.files.size()) {
|
||||
return base::EventFilterResult::Continue;
|
||||
}
|
||||
state->menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
widget,
|
||||
_st.tabbed.menu);
|
||||
state->menu->addAction(tr::lng_rename_file(tr::now), [=] {
|
||||
auto &file = _list.files[fileIndex];
|
||||
_show->show(Box(RenameFileBox, file.displayName, [=](
|
||||
QString newName) {
|
||||
const auto displayName = std::move(newName);
|
||||
_list.files[fileIndex].displayName = displayName;
|
||||
if (!setDisplayNameInSingleFilePreview(
|
||||
fileIndex,
|
||||
displayName)) {
|
||||
refreshAllAfterChanges(from);
|
||||
}
|
||||
}));
|
||||
}, &st::menuIconEdit);
|
||||
const auto &file = _list.files[fileIndex];
|
||||
const auto canEditFileData
|
||||
= !_sendWay.current().sendImagesAsPhotos()
|
||||
|| (file.type != Ui::PreparedFile::Type::Photo
|
||||
&& file.type != Ui::PreparedFile::Type::Video);
|
||||
if (canEditFileData) {
|
||||
state->menu->addAction(tr::lng_rename_file(tr::now), [=] {
|
||||
auto &file = _list.files[fileIndex];
|
||||
_show->show(Box(RenameFileBox, file.displayName, [=](
|
||||
QString newName) {
|
||||
const auto displayName = std::move(newName);
|
||||
_list.files[fileIndex].displayName = displayName;
|
||||
if (!setDisplayNameInSingleFilePreview(
|
||||
fileIndex,
|
||||
displayName)) {
|
||||
refreshAllAfterChanges(from);
|
||||
}
|
||||
}));
|
||||
}, &st::menuIconEdit);
|
||||
state->menu->addAction(
|
||||
tr::lng_context_upload_edit_caption(tr::now),
|
||||
[=] {
|
||||
auto &file = _list.files[fileIndex];
|
||||
_show->show(Box(
|
||||
EditFileCaptionBox,
|
||||
_st,
|
||||
_captionToPeer,
|
||||
file.caption,
|
||||
[=](TextWithTags text) {
|
||||
if (!validateSingleCaptionLength(text.text)) {
|
||||
return false;
|
||||
}
|
||||
auto updated = text;
|
||||
const auto syncMainCaption = (fileIndex == 0)
|
||||
&& _caption
|
||||
&& !_caption->isHidden()
|
||||
&& mainCaptionWillBeAttached();
|
||||
if (fileIndex == 0) {
|
||||
_mainCaptionAttachedToFirstFile = false;
|
||||
_firstFileCaptionBackup = text;
|
||||
}
|
||||
_list.files[fileIndex].caption
|
||||
= std::move(text);
|
||||
if (syncMainCaption) {
|
||||
_caption->setTextWithTags(updated);
|
||||
}
|
||||
if (!setCaptionInSingleFilePreview(
|
||||
fileIndex,
|
||||
updated)) {
|
||||
refreshAllAfterChanges(from);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
},
|
||||
&st::menuIconCaptionShow);
|
||||
}
|
||||
if (state->menu->empty()) {
|
||||
state->menu = nullptr;
|
||||
return base::EventFilterResult::Continue;
|
||||
}
|
||||
state->menu->popup(mouse->globalPos());
|
||||
return base::EventFilterResult::Cancel;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,89 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
void SetupCaptionFieldInBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::InputField*> field,
|
||||
PeerData *panelPeer,
|
||||
Fn<bool(not_null<DocumentData*>)> allowWithoutPremium,
|
||||
PremiumFeature premiumFeature) {
|
||||
using Limit = HistoryView::Controls::CharactersLimitLabel;
|
||||
struct State final {
|
||||
base::unique_qptr<ChatHelpers::TabbedPanel> emojiPanel;
|
||||
base::unique_qptr<Limit> charsLimitation;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
const auto container = box->getDelegate()->outerContainer();
|
||||
using Selector = ChatHelpers::TabbedSelector;
|
||||
state->emojiPanel = base::make_unique_q<ChatHelpers::TabbedPanel>(
|
||||
container,
|
||||
controller,
|
||||
object_ptr<Selector>(
|
||||
nullptr,
|
||||
controller->uiShow(),
|
||||
Window::GifPauseReason::Layer,
|
||||
Selector::Mode::EmojiOnly));
|
||||
const auto emojiPanel = state->emojiPanel.get();
|
||||
emojiPanel->setDesiredHeightValues(
|
||||
1.,
|
||||
st::emojiPanMinHeight / 2,
|
||||
st::emojiPanMinHeight);
|
||||
emojiPanel->hide();
|
||||
emojiPanel->selector()->setCurrentPeer(
|
||||
panelPeer ? panelPeer : controller->session().user());
|
||||
emojiPanel->selector()->emojiChosen(
|
||||
) | rpl::on_next([=](ChatHelpers::EmojiChosen data) {
|
||||
Ui::InsertEmojiAtCursor(field->textCursor(), data.emoji);
|
||||
}, field->lifetime());
|
||||
emojiPanel->selector()->customEmojiChosen(
|
||||
) | rpl::on_next([=](ChatHelpers::FileChosen data) {
|
||||
const auto info = data.document->sticker();
|
||||
if (info
|
||||
&& info->setType == Data::StickersType::Emoji
|
||||
&& !allowWithoutPremium(data.document)
|
||||
&& !controller->session().premium()) {
|
||||
ShowPremiumPreviewBox(controller, premiumFeature);
|
||||
} else {
|
||||
Data::InsertCustomEmoji(field, data.document);
|
||||
}
|
||||
}, field->lifetime());
|
||||
|
||||
const auto emojiButton = Ui::AddEmojiToggleToField(
|
||||
field,
|
||||
box,
|
||||
controller,
|
||||
emojiPanel,
|
||||
st::sendGifWithCaptionEmojiPosition);
|
||||
emojiButton->show();
|
||||
|
||||
const auto session = &controller->session();
|
||||
const auto checkCharsLimitation = [=](auto repeat) -> void {
|
||||
const auto remove = Ui::ComputeFieldCharacterCount(field)
|
||||
- Data::PremiumLimits(session).captionLengthCurrent();
|
||||
if (remove > 0) {
|
||||
if (!state->charsLimitation) {
|
||||
state->charsLimitation = base::make_unique_q<Limit>(
|
||||
field,
|
||||
emojiButton,
|
||||
style::al_top);
|
||||
state->charsLimitation->show();
|
||||
Data::AmPremiumValue(session) | rpl::on_next([=] {
|
||||
repeat(repeat);
|
||||
}, state->charsLimitation->lifetime());
|
||||
}
|
||||
state->charsLimitation->setLeft(remove);
|
||||
state->charsLimitation->show();
|
||||
} else {
|
||||
state->charsLimitation = nullptr;
|
||||
}
|
||||
};
|
||||
field->changes() | rpl::on_next([=] {
|
||||
checkCharsLimitation(checkCharsLimitation);
|
||||
}, field->lifetime());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct State final {
|
||||
@@ -205,8 +288,6 @@ struct State final {
|
||||
[[nodiscard]] not_null<Ui::InputField*> AddInputField(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionController*> controller) {
|
||||
using Limit = HistoryView::Controls::CharactersLimitLabel;
|
||||
|
||||
const auto bottomContainer = box->setPinnedToBottomContent(
|
||||
object_ptr<Ui::VerticalLayout>(box));
|
||||
const auto wrap = bottomContainer->add(
|
||||
@@ -218,83 +299,15 @@ struct State final {
|
||||
Ui::InputField::Mode::MultiLine,
|
||||
tr::lng_photo_caption());
|
||||
Ui::ResizeFitChild(wrap, input);
|
||||
|
||||
struct State final {
|
||||
base::unique_qptr<ChatHelpers::TabbedPanel> emojiPanel;
|
||||
base::unique_qptr<Limit> charsLimitation;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
|
||||
{
|
||||
const auto container = box->getDelegate()->outerContainer();
|
||||
using Selector = ChatHelpers::TabbedSelector;
|
||||
state->emojiPanel = base::make_unique_q<ChatHelpers::TabbedPanel>(
|
||||
container,
|
||||
controller,
|
||||
object_ptr<Selector>(
|
||||
nullptr,
|
||||
controller->uiShow(),
|
||||
Window::GifPauseReason::Layer,
|
||||
Selector::Mode::EmojiOnly));
|
||||
const auto emojiPanel = state->emojiPanel.get();
|
||||
emojiPanel->setDesiredHeightValues(
|
||||
1.,
|
||||
st::emojiPanMinHeight / 2,
|
||||
st::emojiPanMinHeight);
|
||||
emojiPanel->hide();
|
||||
emojiPanel->selector()->setCurrentPeer(controller->session().user());
|
||||
emojiPanel->selector()->emojiChosen(
|
||||
) | rpl::on_next([=](ChatHelpers::EmojiChosen data) {
|
||||
Ui::InsertEmojiAtCursor(input->textCursor(), data.emoji);
|
||||
}, input->lifetime());
|
||||
emojiPanel->selector()->customEmojiChosen(
|
||||
) | rpl::on_next([=](ChatHelpers::FileChosen data) {
|
||||
const auto info = data.document->sticker();
|
||||
if (info
|
||||
&& info->setType == Data::StickersType::Emoji
|
||||
&& !controller->session().premium()) {
|
||||
ShowPremiumPreviewBox(
|
||||
controller,
|
||||
PremiumFeature::AnimatedEmoji);
|
||||
} else {
|
||||
Data::InsertCustomEmoji(input, data.document);
|
||||
}
|
||||
}, input->lifetime());
|
||||
}
|
||||
|
||||
const auto emojiButton = Ui::AddEmojiToggleToField(
|
||||
input,
|
||||
SetupCaptionFieldInBox(
|
||||
box,
|
||||
controller,
|
||||
state->emojiPanel.get(),
|
||||
st::sendGifWithCaptionEmojiPosition);
|
||||
emojiButton->show();
|
||||
|
||||
const auto session = &controller->session();
|
||||
const auto checkCharsLimitation = [=](auto repeat) -> void {
|
||||
const auto remove = Ui::ComputeFieldCharacterCount(input)
|
||||
- Data::PremiumLimits(session).captionLengthCurrent();
|
||||
if (remove > 0) {
|
||||
if (!state->charsLimitation) {
|
||||
state->charsLimitation = base::make_unique_q<Limit>(
|
||||
input,
|
||||
emojiButton,
|
||||
style::al_top);
|
||||
state->charsLimitation->show();
|
||||
Data::AmPremiumValue(session) | rpl::on_next([=] {
|
||||
repeat(repeat);
|
||||
}, state->charsLimitation->lifetime());
|
||||
}
|
||||
state->charsLimitation->setLeft(remove);
|
||||
state->charsLimitation->show();
|
||||
} else {
|
||||
state->charsLimitation = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
input->changes() | rpl::on_next([=] {
|
||||
checkCharsLimitation(checkCharsLimitation);
|
||||
}, input->lifetime());
|
||||
input,
|
||||
controller->session().user(),
|
||||
[](not_null<DocumentData*>) {
|
||||
return false;
|
||||
},
|
||||
PremiumFeature::AnimatedEmoji);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
class PeerData;
|
||||
class DocumentData;
|
||||
enum class PremiumFeature;
|
||||
|
||||
namespace Api {
|
||||
struct SendOptions;
|
||||
@@ -22,9 +23,22 @@ namespace HistoryView {
|
||||
class Element;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class GenericBox;
|
||||
class InputField;
|
||||
|
||||
void SetupCaptionFieldInBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::InputField*> field,
|
||||
PeerData *panelPeer,
|
||||
Fn<bool(not_null<DocumentData*>)> allowWithoutPremium,
|
||||
PremiumFeature premiumFeature);
|
||||
|
||||
void EditCaptionBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
|
||||
Reference in New Issue
Block a user