mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Edit media captions in message field.
This commit is contained in:
parent
e3f2dcec22
commit
42c96b4c7f
11 changed files with 355 additions and 130 deletions
BIN
Telegram/Resources/icons/chat/input_draw.png
Normal file
BIN
Telegram/Resources/icons/chat/input_draw.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 953 B |
BIN
Telegram/Resources/icons/chat/input_draw@2x.png
Normal file
BIN
Telegram/Resources/icons/chat/input_draw@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/chat/input_draw@3x.png
Normal file
BIN
Telegram/Resources/icons/chat/input_draw@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
Telegram/Resources/icons/chat/input_replace.png
Normal file
BIN
Telegram/Resources/icons/chat/input_replace.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 749 B |
BIN
Telegram/Resources/icons/chat/input_replace@2x.png
Normal file
BIN
Telegram/Resources/icons/chat/input_replace@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/chat/input_replace@3x.png
Normal file
BIN
Telegram/Resources/icons/chat/input_replace@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
|
@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_session_settings.h"
|
#include "main/main_session_settings.h"
|
||||||
|
#include "mainwidget.h" // controller->content() -> QWidget*
|
||||||
#include "mtproto/mtproto_config.h"
|
#include "mtproto/mtproto_config.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
#include "storage/localimageloader.h" // SendMediaType
|
#include "storage/localimageloader.h" // SendMediaType
|
||||||
|
@ -69,7 +70,9 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kChangesDebounceTimeout = crl::time(1000);
|
constexpr auto kChangesDebounceTimeout = crl::time(1000);
|
||||||
|
|
||||||
auto ListFromMimeData(not_null<const QMimeData*> data, bool premium) {
|
[[nodiscard]] Ui::PreparedList ListFromMimeData(
|
||||||
|
not_null<const QMimeData*> data,
|
||||||
|
bool premium) {
|
||||||
using Error = Ui::PreparedList::Error;
|
using Error = Ui::PreparedList::Error;
|
||||||
const auto list = Core::ReadMimeUrls(data);
|
const auto list = Core::ReadMimeUrls(data);
|
||||||
auto result = !list.isEmpty()
|
auto result = !list.isEmpty()
|
||||||
|
@ -89,7 +92,7 @@ auto ListFromMimeData(not_null<const QMimeData*> data, bool premium) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ui::AlbumType ComputeAlbumType(not_null<HistoryItem*> item) {
|
[[nodiscard]] Ui::AlbumType ComputeAlbumType(not_null<HistoryItem*> item) {
|
||||||
if (item->groupId().empty()) {
|
if (item->groupId().empty()) {
|
||||||
return Ui::AlbumType();
|
return Ui::AlbumType();
|
||||||
}
|
}
|
||||||
|
@ -109,17 +112,130 @@ Ui::AlbumType ComputeAlbumType(not_null<HistoryItem*> item) {
|
||||||
return Ui::AlbumType();
|
return Ui::AlbumType();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanBeCompressed(Ui::AlbumType type) {
|
[[nodiscard]] bool CanBeCompressed(Ui::AlbumType type) {
|
||||||
return (type == Ui::AlbumType::None)
|
return (type == Ui::AlbumType::None)
|
||||||
|| (type == Ui::AlbumType::PhotoVideo);
|
|| (type == Ui::AlbumType::PhotoVideo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChooseReplacement(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
Ui::AlbumType type,
|
||||||
|
Fn<void(Ui::PreparedList&&)> chosen) {
|
||||||
|
const auto weak = base::make_weak(controller);
|
||||||
|
const auto callback = [=](FileDialog::OpenResult &&result) {
|
||||||
|
const auto strong = weak.get();
|
||||||
|
if (!strong) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto showError = [=](tr::phrase<> t) {
|
||||||
|
if (const auto strong = weak.get()) {
|
||||||
|
strong->showToast({ t(tr::now) });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto checkResult = [=](const Ui::PreparedList &list) {
|
||||||
|
if (list.files.size() != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto &file = list.files.front();
|
||||||
|
const auto mime = file.information->filemime;
|
||||||
|
if (Core::IsMimeSticker(mime)) {
|
||||||
|
showError(tr::lng_edit_media_invalid_file);
|
||||||
|
return false;
|
||||||
|
} else if (type != Ui::AlbumType::None
|
||||||
|
&& !file.canBeInAlbumType(type)) {
|
||||||
|
showError(tr::lng_edit_media_album_error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
const auto premium = strong->session().premium();
|
||||||
|
auto list = Storage::PreparedFileFromFilesDialog(
|
||||||
|
std::move(result),
|
||||||
|
checkResult,
|
||||||
|
showError,
|
||||||
|
st::sendMediaPreviewSize,
|
||||||
|
premium);
|
||||||
|
|
||||||
|
if (list) {
|
||||||
|
chosen(std::move(*list));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto filters = (type == Ui::AlbumType::PhotoVideo)
|
||||||
|
? FileDialog::PhotoVideoFilesFilter()
|
||||||
|
: FileDialog::AllFilesFilter();
|
||||||
|
FileDialog::GetOpenPath(
|
||||||
|
controller->content().get(),
|
||||||
|
tr::lng_choose_file(tr::now),
|
||||||
|
filters,
|
||||||
|
crl::guard(controller, callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditPhotoImage(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
std::shared_ptr<Data::PhotoMedia> media,
|
||||||
|
bool wasSpoiler,
|
||||||
|
Fn<void(Ui::PreparedList)> done) {
|
||||||
|
const auto large = media
|
||||||
|
? media->image(Data::PhotoSize::Large)
|
||||||
|
: nullptr;
|
||||||
|
const auto parent = controller->content();
|
||||||
|
const auto previewWidth = st::sendMediaPreviewSize;
|
||||||
|
auto callback = [=](const Editor::PhotoModifications &mods) {
|
||||||
|
if (!mods) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto large = media->image(Data::PhotoSize::Large);
|
||||||
|
if (!large) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto copy = large->original();
|
||||||
|
auto list = Storage::PrepareMediaFromImage(
|
||||||
|
std::move(copy),
|
||||||
|
QByteArray(),
|
||||||
|
previewWidth);
|
||||||
|
|
||||||
|
using ImageInfo = Ui::PreparedFileInformation::Image;
|
||||||
|
auto &file = list.files.front();
|
||||||
|
file.spoiler = wasSpoiler;
|
||||||
|
const auto image = std::get_if<ImageInfo>(&file.information->media);
|
||||||
|
|
||||||
|
image->modifications = mods;
|
||||||
|
const auto sideLimit = PhotoSideLimit();
|
||||||
|
Storage::UpdateImageDetails(file, previewWidth, sideLimit);
|
||||||
|
done(std::move(list));
|
||||||
|
};
|
||||||
|
const auto fileImage = std::make_shared<Image>(*large);
|
||||||
|
auto editor = base::make_unique_q<Editor::PhotoEditor>(
|
||||||
|
parent,
|
||||||
|
&controller->window(),
|
||||||
|
fileImage,
|
||||||
|
Editor::PhotoModifications());
|
||||||
|
const auto raw = editor.get();
|
||||||
|
auto layer = std::make_unique<Editor::LayerWidget>(
|
||||||
|
parent,
|
||||||
|
std::move(editor));
|
||||||
|
Editor::InitEditorLayer(layer.get(), raw, std::move(callback));
|
||||||
|
controller->showLayer(std::move(layer), Ui::LayerOption::KeepOther);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
EditCaptionBox::EditCaptionBox(
|
EditCaptionBox::EditCaptionBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<HistoryItem*> item)
|
not_null<HistoryItem*> item)
|
||||||
|
: EditCaptionBox({}, controller, item, PrepareEditText(item), {}, {}) {
|
||||||
|
}
|
||||||
|
|
||||||
|
EditCaptionBox::EditCaptionBox(
|
||||||
|
QWidget*,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
TextWithTags &&text,
|
||||||
|
Ui::PreparedList &&list,
|
||||||
|
Fn<void()> saved)
|
||||||
: _controller(controller)
|
: _controller(controller)
|
||||||
, _historyItem(item)
|
, _historyItem(item)
|
||||||
, _isAllowedEditMedia(item->media()
|
, _isAllowedEditMedia(item->media()
|
||||||
|
@ -135,7 +251,10 @@ EditCaptionBox::EditCaptionBox(
|
||||||
tr::lng_photo_caption()))
|
tr::lng_photo_caption()))
|
||||||
, _emojiToggle(base::make_unique_q<Ui::EmojiButton>(
|
, _emojiToggle(base::make_unique_q<Ui::EmojiButton>(
|
||||||
this,
|
this,
|
||||||
st::boxAttachEmoji)) {
|
st::boxAttachEmoji))
|
||||||
|
, _initialText(std::move(text))
|
||||||
|
, _initialList(std::move(list))
|
||||||
|
, _saved(std::move(saved)) {
|
||||||
Expects(item->media() != nullptr);
|
Expects(item->media() != nullptr);
|
||||||
Expects(item->media()->allowsEditCaption());
|
Expects(item->media()->allowsEditCaption());
|
||||||
|
|
||||||
|
@ -148,6 +267,57 @@ EditCaptionBox::EditCaptionBox(
|
||||||
|
|
||||||
EditCaptionBox::~EditCaptionBox() = default;
|
EditCaptionBox::~EditCaptionBox() = default;
|
||||||
|
|
||||||
|
void EditCaptionBox::StartMediaReplace(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
FullMsgId itemId,
|
||||||
|
TextWithTags text,
|
||||||
|
Fn<void()> saved) {
|
||||||
|
const auto session = &controller->session();
|
||||||
|
const auto item = session->data().message(itemId);
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto show = [=](Ui::PreparedList &&list) mutable {
|
||||||
|
controller->show(Box<EditCaptionBox>(
|
||||||
|
controller,
|
||||||
|
item,
|
||||||
|
std::move(text),
|
||||||
|
std::move(list),
|
||||||
|
std::move(saved)));
|
||||||
|
};
|
||||||
|
ChooseReplacement(
|
||||||
|
controller,
|
||||||
|
ComputeAlbumType(item),
|
||||||
|
crl::guard(controller, show));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditCaptionBox::StartPhotoEdit(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
std::shared_ptr<Data::PhotoMedia> media,
|
||||||
|
FullMsgId itemId,
|
||||||
|
TextWithTags text,
|
||||||
|
Fn<void()> saved) {
|
||||||
|
const auto session = &controller->session();
|
||||||
|
const auto item = session->data().message(itemId);
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto hasSpoiler = item->media() && item->media()->hasSpoiler();
|
||||||
|
EditPhotoImage(controller, media, hasSpoiler, [=](
|
||||||
|
Ui::PreparedList &&list) mutable {
|
||||||
|
const auto item = session->data().message(itemId);
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
controller->show(Box<EditCaptionBox>(
|
||||||
|
controller,
|
||||||
|
item,
|
||||||
|
std::move(text),
|
||||||
|
std::move(list),
|
||||||
|
std::move(saved)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void EditCaptionBox::prepare() {
|
void EditCaptionBox::prepare() {
|
||||||
addButton(tr::lng_settings_save(), [=] { save(); });
|
addButton(tr::lng_settings_save(), [=] { save(); });
|
||||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||||
|
@ -158,7 +328,9 @@ void EditCaptionBox::prepare() {
|
||||||
setupEmojiPanel();
|
setupEmojiPanel();
|
||||||
setInitialText();
|
setInitialText();
|
||||||
|
|
||||||
rebuildPreview();
|
if (!setPreparedList(std::move(_initialList))) {
|
||||||
|
rebuildPreview();
|
||||||
|
}
|
||||||
setupEditEventHandler();
|
setupEditEventHandler();
|
||||||
SetupShadowsToScrollContent(this, _scroll, _contentHeight.events());
|
SetupShadowsToScrollContent(this, _scroll, _contentHeight.events());
|
||||||
|
|
||||||
|
@ -290,16 +462,15 @@ void EditCaptionBox::setupField() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditCaptionBox::setInitialText() {
|
void EditCaptionBox::setInitialText() {
|
||||||
const auto initial = PrepareEditText(_historyItem);
|
|
||||||
_field->setTextWithTags(
|
_field->setTextWithTags(
|
||||||
initial,
|
_initialText,
|
||||||
Ui::InputField::HistoryAction::Clear);
|
Ui::InputField::HistoryAction::Clear);
|
||||||
auto cursor = _field->textCursor();
|
auto cursor = _field->textCursor();
|
||||||
cursor.movePosition(QTextCursor::End);
|
cursor.movePosition(QTextCursor::End);
|
||||||
_field->setTextCursor(cursor);
|
_field->setTextCursor(cursor);
|
||||||
|
|
||||||
_checkChangedTimer.setCallback([=] {
|
_checkChangedTimer.setCallback([=] {
|
||||||
if (_field->getTextWithAppliedMarkdown() == initial) {
|
if (_field->getTextWithAppliedMarkdown() == _initialText) {
|
||||||
setCloseByOutsideClick(true);
|
setCloseByOutsideClick(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -353,132 +524,44 @@ void EditCaptionBox::setupControls() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditCaptionBox::setupEditEventHandler() {
|
void EditCaptionBox::setupEditEventHandler() {
|
||||||
const auto toastParent = Ui::BoxShow(this).toastParent();
|
|
||||||
const auto callback = [=](FileDialog::OpenResult &&result) {
|
|
||||||
auto showError = [toastParent](tr::phrase<> t) {
|
|
||||||
Ui::Toast::Show(toastParent, t(tr::now));
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto checkResult = [=](const Ui::PreparedList &list) {
|
|
||||||
if (list.files.size() != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto &file = list.files.front();
|
|
||||||
const auto mime = file.information->filemime;
|
|
||||||
if (Core::IsMimeSticker(mime)) {
|
|
||||||
showError(tr::lng_edit_media_invalid_file);
|
|
||||||
return false;
|
|
||||||
} else if (_albumType != Ui::AlbumType::None
|
|
||||||
&& !file.canBeInAlbumType(_albumType)) {
|
|
||||||
showError(tr::lng_edit_media_album_error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
const auto premium = _controller->session().premium();
|
|
||||||
auto list = Storage::PreparedFileFromFilesDialog(
|
|
||||||
std::move(result),
|
|
||||||
checkResult,
|
|
||||||
showError,
|
|
||||||
st::sendMediaPreviewSize,
|
|
||||||
premium);
|
|
||||||
|
|
||||||
if (list) {
|
|
||||||
setPreparedList(std::move(*list));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto buttonCallback = [=] {
|
|
||||||
const auto filters = (_albumType == Ui::AlbumType::PhotoVideo)
|
|
||||||
? FileDialog::PhotoVideoFilesFilter()
|
|
||||||
: FileDialog::AllFilesFilter();
|
|
||||||
FileDialog::GetOpenPath(
|
|
||||||
this,
|
|
||||||
tr::lng_choose_file(tr::now),
|
|
||||||
filters,
|
|
||||||
crl::guard(this, callback));
|
|
||||||
};
|
|
||||||
|
|
||||||
_editMediaClicks.events(
|
_editMediaClicks.events(
|
||||||
) | rpl::start_with_next(
|
) | rpl::start_with_next([=] {
|
||||||
buttonCallback,
|
ChooseReplacement(_controller, _albumType, crl::guard(this, [=](
|
||||||
lifetime());
|
Ui::PreparedList &&list) {
|
||||||
|
setPreparedList(std::move(list));
|
||||||
|
}));
|
||||||
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditCaptionBox::setupPhotoEditorEventHandler() {
|
void EditCaptionBox::setupPhotoEditorEventHandler() {
|
||||||
const auto openedOnce = lifetime().make_state<bool>(false);
|
const auto openedOnce = lifetime().make_state<bool>(false);
|
||||||
_photoEditorOpens.events(
|
_photoEditorOpens.events(
|
||||||
) | rpl::start_with_next([=, controller = _controller] {
|
) | rpl::start_with_next([=, controller = _controller] {
|
||||||
const auto increment = [=] {
|
if (_preparedList.files.empty()
|
||||||
if (*openedOnce) {
|
&& (!_photoMedia
|
||||||
return;
|
|| !_photoMedia->image(Data::PhotoSize::Large))) {
|
||||||
}
|
return;
|
||||||
|
} else if (!*openedOnce) {
|
||||||
*openedOnce = true;
|
*openedOnce = true;
|
||||||
controller->session().settings().incrementPhotoEditorHintShown();
|
controller->session().settings().incrementPhotoEditorHintShown();
|
||||||
controller->session().saveSettings();
|
controller->session().saveSettings();
|
||||||
};
|
}
|
||||||
const auto clearError = [=] {
|
if (!_error.isEmpty()) {
|
||||||
_error = QString();
|
_error = QString();
|
||||||
update();
|
update();
|
||||||
};
|
}
|
||||||
const auto previewWidth = st::sendMediaPreviewSize;
|
|
||||||
if (!_preparedList.files.empty()) {
|
if (!_preparedList.files.empty()) {
|
||||||
increment();
|
|
||||||
clearError();
|
|
||||||
Editor::OpenWithPreparedFile(
|
Editor::OpenWithPreparedFile(
|
||||||
this,
|
this,
|
||||||
controller,
|
controller,
|
||||||
&_preparedList.files.front(),
|
&_preparedList.files.front(),
|
||||||
previewWidth,
|
st::sendMediaPreviewSize,
|
||||||
[=] { rebuildPreview(); });
|
[=] { rebuildPreview(); });
|
||||||
} else if (_photoMedia) {
|
} else {
|
||||||
const auto large = _photoMedia->image(Data::PhotoSize::Large);
|
EditPhotoImage(_controller, _photoMedia, hasSpoiler(), [=](
|
||||||
if (!large) {
|
Ui::PreparedList &&list) {
|
||||||
return;
|
setPreparedList(std::move(list));
|
||||||
}
|
});
|
||||||
increment();
|
|
||||||
clearError();
|
|
||||||
auto callback = [=](const Editor::PhotoModifications &mods) {
|
|
||||||
if (!mods || !_photoMedia) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto large = _photoMedia->image(Data::PhotoSize::Large);
|
|
||||||
if (!large) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto copy = large->original();
|
|
||||||
const auto wasSpoiler = hasSpoiler();
|
|
||||||
|
|
||||||
_preparedList = Storage::PrepareMediaFromImage(
|
|
||||||
std::move(copy),
|
|
||||||
QByteArray(),
|
|
||||||
previewWidth);
|
|
||||||
|
|
||||||
using ImageInfo = Ui::PreparedFileInformation::Image;
|
|
||||||
auto &file = _preparedList.files.front();
|
|
||||||
file.spoiler = wasSpoiler;
|
|
||||||
const auto image = std::get_if<ImageInfo>(
|
|
||||||
&file.information->media);
|
|
||||||
|
|
||||||
image->modifications = mods;
|
|
||||||
const auto sideLimit = PhotoSideLimit();
|
|
||||||
Storage::UpdateImageDetails(file, previewWidth, sideLimit);
|
|
||||||
rebuildPreview();
|
|
||||||
};
|
|
||||||
const auto fileImage = std::make_shared<Image>(*large);
|
|
||||||
auto editor = base::make_unique_q<Editor::PhotoEditor>(
|
|
||||||
this,
|
|
||||||
&controller->window(),
|
|
||||||
fileImage,
|
|
||||||
Editor::PhotoModifications());
|
|
||||||
const auto raw = editor.get();
|
|
||||||
auto layer = std::make_unique<Editor::LayerWidget>(
|
|
||||||
this,
|
|
||||||
std::move(editor));
|
|
||||||
Editor::InitEditorLayer(layer.get(), raw, std::move(callback));
|
|
||||||
controller->showLayer(
|
|
||||||
std::move(layer),
|
|
||||||
Ui::LayerOption::KeepOther);
|
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
@ -780,13 +863,13 @@ void EditCaptionBox::save() {
|
||||||
: SendMediaType::File,
|
: SendMediaType::File,
|
||||||
_field->getTextWithAppliedMarkdown(),
|
_field->getTextWithAppliedMarkdown(),
|
||||||
action);
|
action);
|
||||||
closeBox();
|
closeAfterSave();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto done = crl::guard(this, [=] {
|
const auto done = crl::guard(this, [=] {
|
||||||
_saveRequestId = 0;
|
_saveRequestId = 0;
|
||||||
closeBox();
|
closeAfterSave();
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto fail = crl::guard(this, [=](const QString &error) {
|
const auto fail = crl::guard(this, [=](const QString &error) {
|
||||||
|
@ -795,7 +878,7 @@ void EditCaptionBox::save() {
|
||||||
_error = tr::lng_edit_error(tr::now);
|
_error = tr::lng_edit_error(tr::now);
|
||||||
update();
|
update();
|
||||||
} else if (error == u"MESSAGE_NOT_MODIFIED"_q) {
|
} else if (error == u"MESSAGE_NOT_MODIFIED"_q) {
|
||||||
closeBox();
|
closeAfterSave();
|
||||||
} else if (error == u"MESSAGE_EMPTY"_q) {
|
} else if (error == u"MESSAGE_EMPTY"_q) {
|
||||||
_field->setFocus();
|
_field->setFocus();
|
||||||
_field->showError();
|
_field->showError();
|
||||||
|
@ -816,6 +899,16 @@ void EditCaptionBox::save() {
|
||||||
_saveRequestId = Api::EditCaption(item, sending, options, done, fail);
|
_saveRequestId = Api::EditCaption(item, sending, options, done, fail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditCaptionBox::closeAfterSave() {
|
||||||
|
const auto weak = MakeWeak(this);
|
||||||
|
if (_saved) {
|
||||||
|
_saved();
|
||||||
|
}
|
||||||
|
if (weak) {
|
||||||
|
closeBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditCaptionBox::keyPressEvent(QKeyEvent *e) {
|
void EditCaptionBox::keyPressEvent(QKeyEvent *e) {
|
||||||
const auto ctrl = e->modifiers().testFlag(Qt::ControlModifier);
|
const auto ctrl = e->modifiers().testFlag(Qt::ControlModifier);
|
||||||
if ((e->key() == Qt::Key_E) && ctrl) {
|
if ((e->key() == Qt::Key_E) && ctrl) {
|
||||||
|
|
|
@ -36,8 +36,27 @@ public:
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<HistoryItem*> item);
|
not_null<HistoryItem*> item);
|
||||||
|
EditCaptionBox(
|
||||||
|
QWidget*,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
TextWithTags &&text,
|
||||||
|
Ui::PreparedList &&list,
|
||||||
|
Fn<void()> saved);
|
||||||
~EditCaptionBox();
|
~EditCaptionBox();
|
||||||
|
|
||||||
|
static void StartMediaReplace(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
FullMsgId itemId,
|
||||||
|
TextWithTags text,
|
||||||
|
Fn<void()> saved);
|
||||||
|
static void StartPhotoEdit(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
std::shared_ptr<Data::PhotoMedia> media,
|
||||||
|
FullMsgId itemId,
|
||||||
|
TextWithTags text,
|
||||||
|
Fn<void()> saved);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
void setInnerFocus() override;
|
void setInnerFocus() override;
|
||||||
|
@ -66,6 +85,7 @@ private:
|
||||||
bool validateLength(const QString &text) const;
|
bool validateLength(const QString &text) const;
|
||||||
void applyChanges();
|
void applyChanges();
|
||||||
void save();
|
void save();
|
||||||
|
void closeAfterSave();
|
||||||
|
|
||||||
bool fileFromClipboard(not_null<const QMimeData*> data);
|
bool fileFromClipboard(not_null<const QMimeData*> data);
|
||||||
|
|
||||||
|
@ -89,6 +109,10 @@ private:
|
||||||
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
|
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
|
||||||
base::unique_qptr<QObject> _emojiFilter;
|
base::unique_qptr<QObject> _emojiFilter;
|
||||||
|
|
||||||
|
const TextWithTags _initialText;
|
||||||
|
Ui::PreparedList _initialList;
|
||||||
|
Fn<void()> _saved;
|
||||||
|
|
||||||
std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||||
|
|
||||||
Ui::PreparedList _preparedList;
|
Ui::PreparedList _preparedList;
|
||||||
|
|
|
@ -61,6 +61,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_web_page.h"
|
#include "data/data_web_page.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_chat.h"
|
#include "data/data_chat.h"
|
||||||
|
@ -2121,6 +2122,8 @@ void HistoryWidget::showHistory(
|
||||||
_saveEditMsgRequestId = 0;
|
_saveEditMsgRequestId = 0;
|
||||||
_processingReplyItem = _replyEditMsg = nullptr;
|
_processingReplyItem = _replyEditMsg = nullptr;
|
||||||
_processingReplyId = _editMsgId = _replyToId = 0;
|
_processingReplyId = _editMsgId = _replyToId = 0;
|
||||||
|
_photoEditMedia = nullptr;
|
||||||
|
updateReplaceMediaButton();
|
||||||
_previewData = nullptr;
|
_previewData = nullptr;
|
||||||
_previewCache.clear();
|
_previewCache.clear();
|
||||||
_fieldBarCancel->hide();
|
_fieldBarCancel->hide();
|
||||||
|
@ -2504,6 +2507,25 @@ void HistoryWidget::clearAllLoadRequests() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryWidget::updateReplaceMediaButton() {
|
||||||
|
if (!_canReplaceMedia) {
|
||||||
|
const auto result = (_replaceMedia != nullptr);
|
||||||
|
_replaceMedia.destroy();
|
||||||
|
return result;
|
||||||
|
} else if (_replaceMedia) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_replaceMedia.create(this, st::historyReplaceMedia);
|
||||||
|
_replaceMedia->setClickedCallback([=] {
|
||||||
|
EditCaptionBox::StartMediaReplace(
|
||||||
|
controller(),
|
||||||
|
{ _history->peer->id, _editMsgId },
|
||||||
|
_field->getTextWithTags(),
|
||||||
|
crl::guard(_list, [=] { cancelEdit(); }));
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateFieldSubmitSettings() {
|
void HistoryWidget::updateFieldSubmitSettings() {
|
||||||
const auto settings = _isInlineBot
|
const auto settings = _isInlineBot
|
||||||
? Ui::InputField::SubmitSettings::None
|
? Ui::InputField::SubmitSettings::None
|
||||||
|
@ -2731,6 +2753,9 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_kbScroll->hide();
|
_kbScroll->hide();
|
||||||
_fieldBarCancel->hide();
|
_fieldBarCancel->hide();
|
||||||
_attachToggle->hide();
|
_attachToggle->hide();
|
||||||
|
if (_replaceMedia) {
|
||||||
|
_replaceMedia->hide();
|
||||||
|
}
|
||||||
_tabbedSelectorToggle->hide();
|
_tabbedSelectorToggle->hide();
|
||||||
_botKeyboardShow->hide();
|
_botKeyboardShow->hide();
|
||||||
_botKeyboardHide->hide();
|
_botKeyboardHide->hide();
|
||||||
|
@ -2795,7 +2820,12 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_botCommandStart->setVisible(_cmdStartShown);
|
_botCommandStart->setVisible(_cmdStartShown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_attachToggle->show();
|
if (_replaceMedia) {
|
||||||
|
_replaceMedia->show();
|
||||||
|
_attachToggle->hide();
|
||||||
|
} else {
|
||||||
|
_attachToggle->show();
|
||||||
|
}
|
||||||
if (_botMenuButton) {
|
if (_botMenuButton) {
|
||||||
_botMenuButton->show();
|
_botMenuButton->show();
|
||||||
}
|
}
|
||||||
|
@ -3685,7 +3715,8 @@ void HistoryWidget::saveEditMsg() {
|
||||||
TextUtilities::ConvertTextTagsToEntities(textWithTags.tags) };
|
TextUtilities::ConvertTextTagsToEntities(textWithTags.tags) };
|
||||||
TextUtilities::PrepareForSending(left, prepareFlags);
|
TextUtilities::PrepareForSending(left, prepareFlags);
|
||||||
|
|
||||||
if (!TextUtilities::CutPart(sending, left, MaxMessageSize)) {
|
if (!TextUtilities::CutPart(sending, left, MaxMessageSize)
|
||||||
|
&& (!item->media() || !item->media()->allowsEditCaption())) {
|
||||||
const auto suggestModerateActions = false;
|
const auto suggestModerateActions = false;
|
||||||
controller()->show(
|
controller()->show(
|
||||||
Box<DeleteMessagesBox>(item, suggestModerateActions));
|
Box<DeleteMessagesBox>(item, suggestModerateActions));
|
||||||
|
@ -4239,9 +4270,34 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateOverStates(QPoint pos) {
|
void HistoryWidget::updateOverStates(QPoint pos) {
|
||||||
auto inReplyEditForward = QRect(st::historyReplySkip, _field->y() - st::historySendPadding - st::historyReplyHeight, width() - st::historyReplySkip - _fieldBarCancel->width(), st::historyReplyHeight).contains(pos) && (_editMsgId || replyToId() || readyToForward());
|
const auto replyEditForwardInfoRect = QRect(
|
||||||
|
st::historyReplySkip,
|
||||||
|
_field->y() - st::historySendPadding - st::historyReplyHeight,
|
||||||
|
width() - st::historyReplySkip - _fieldBarCancel->width(),
|
||||||
|
st::historyReplyHeight);
|
||||||
|
auto inReplyEditForward = (_editMsgId || replyToId() || readyToForward())
|
||||||
|
&& replyEditForwardInfoRect.contains(pos);
|
||||||
|
auto inPhotoEdit = inReplyEditForward
|
||||||
|
&& _photoEditMedia
|
||||||
|
&& QRect(
|
||||||
|
replyEditForwardInfoRect.x(),
|
||||||
|
replyEditForwardInfoRect.y() + st::msgReplyPadding.top(),
|
||||||
|
st::msgReplyBarSize.height(),
|
||||||
|
st::msgReplyBarSize.height()).contains(pos);
|
||||||
auto inClickable = inReplyEditForward;
|
auto inClickable = inReplyEditForward;
|
||||||
_inReplyEditForward = inReplyEditForward;
|
if (_inPhotoEdit != inPhotoEdit) {
|
||||||
|
_inPhotoEdit = inPhotoEdit;
|
||||||
|
if (_photoEditMedia) {
|
||||||
|
_inPhotoEditOver.start(
|
||||||
|
[=] { updateField(); },
|
||||||
|
_inPhotoEdit ? 0. : 1.,
|
||||||
|
_inPhotoEdit ? 1. : 0.,
|
||||||
|
st::defaultMessageBar.duration);
|
||||||
|
} else {
|
||||||
|
_inPhotoEditOver.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_inReplyEditForward = inReplyEditForward && !inPhotoEdit;
|
||||||
if (inClickable != _inClickable) {
|
if (inClickable != _inClickable) {
|
||||||
_inClickable = inClickable;
|
_inClickable = inClickable;
|
||||||
setCursor(_inClickable ? style::cur_pointer : style::cur_default);
|
setCursor(_inClickable ? style::cur_pointer : style::cur_default);
|
||||||
|
@ -4862,7 +4918,7 @@ void HistoryWidget::moveFieldControls() {
|
||||||
_kbScroll->setGeometryToLeft(0, bottom, width(), keyboardHeight);
|
_kbScroll->setGeometryToLeft(0, bottom, width(), keyboardHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// (_botMenuButton) _attachToggle (_sendAs) ---- _inlineResults ------------------------------ _tabbedPanel ------ _fieldBarCancel
|
// (_botMenuButton) (_attachToggle|_replaceMedia) (_sendAs) ---- _inlineResults ------------------------------ _tabbedPanel ------ _fieldBarCancel
|
||||||
// (_attachDocument|_attachPhoto) _field (_ttlInfo) (_scheduled) (_silent|_cmdStart|_kbShow) (_kbHide|_tabbedSelectorToggle) _send
|
// (_attachDocument|_attachPhoto) _field (_ttlInfo) (_scheduled) (_silent|_cmdStart|_kbShow) (_kbHide|_tabbedSelectorToggle) _send
|
||||||
// (_botStart|_unblock|_joinChannel|_muteUnmute|_reportMessages)
|
// (_botStart|_unblock|_joinChannel|_muteUnmute|_reportMessages)
|
||||||
|
|
||||||
|
@ -4872,6 +4928,9 @@ void HistoryWidget::moveFieldControls() {
|
||||||
const auto skip = st::historyBotMenuSkip;
|
const auto skip = st::historyBotMenuSkip;
|
||||||
_botMenuButton->moveToLeft(left + skip, buttonsBottom + skip); left += skip + _botMenuButton->width();
|
_botMenuButton->moveToLeft(left + skip, buttonsBottom + skip); left += skip + _botMenuButton->width();
|
||||||
}
|
}
|
||||||
|
if (_replaceMedia) {
|
||||||
|
_replaceMedia->moveToLeft(left, buttonsBottom);
|
||||||
|
}
|
||||||
_attachToggle->moveToLeft(left, buttonsBottom); left += _attachToggle->width();
|
_attachToggle->moveToLeft(left, buttonsBottom); left += _attachToggle->width();
|
||||||
if (_sendAs) {
|
if (_sendAs) {
|
||||||
_sendAs->moveToLeft(left, buttonsBottom); left += _sendAs->width();
|
_sendAs->moveToLeft(left, buttonsBottom); left += _sendAs->width();
|
||||||
|
@ -6038,6 +6097,13 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
st::historyReplyHeight).contains(e->pos());
|
st::historyReplyHeight).contains(e->pos());
|
||||||
if (_replyForwardPressed && !_fieldBarCancel->isHidden()) {
|
if (_replyForwardPressed && !_fieldBarCancel->isHidden()) {
|
||||||
updateField();
|
updateField();
|
||||||
|
} else if (_inPhotoEdit && _photoEditMedia) {
|
||||||
|
EditCaptionBox::StartPhotoEdit(
|
||||||
|
controller(),
|
||||||
|
_photoEditMedia,
|
||||||
|
{ _history->peer->id, _editMsgId },
|
||||||
|
_field->getTextWithTags(),
|
||||||
|
crl::guard(_list, [=] { cancelEdit(); }));
|
||||||
} else if (_inReplyEditForward) {
|
} else if (_inReplyEditForward) {
|
||||||
if (readyToForward()) {
|
if (readyToForward()) {
|
||||||
_forwardPanel->editOptions(controller());
|
_forwardPanel->editOptions(controller());
|
||||||
|
@ -6957,12 +7023,7 @@ void HistoryWidget::editMessage(FullMsgId itemId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
|
void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
|
||||||
if (const auto media = item->media()) {
|
if (_chooseTheme) {
|
||||||
if (media->allowsEditCaption()) {
|
|
||||||
controller()->show(Box<EditCaptionBox>(controller(), item));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (_chooseTheme) {
|
|
||||||
toggleChooseChatTheme(_peer);
|
toggleChooseChatTheme(_peer);
|
||||||
} else if (_voiceRecordBar->isActive()) {
|
} else if (_voiceRecordBar->isActive()) {
|
||||||
controller()->showToast({ tr::lng_edit_caption_voice(tr::now) });
|
controller()->showToast({ tr::lng_edit_caption_voice(tr::now) });
|
||||||
|
@ -7132,6 +7193,9 @@ void HistoryWidget::cancelEdit() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_canReplaceMedia = false;
|
||||||
|
_photoEditMedia = nullptr;
|
||||||
|
updateReplaceMediaButton();
|
||||||
_replyEditMsg = nullptr;
|
_replyEditMsg = nullptr;
|
||||||
setEditMsgId(0);
|
setEditMsgId(0);
|
||||||
_history->clearLocalEditDraft({});
|
_history->clearLocalEditDraft({});
|
||||||
|
@ -7588,6 +7652,22 @@ void HistoryWidget::updateReplyEditTexts(bool force) {
|
||||||
_editMsgId ? _editMsgId : _replyToId);
|
_editMsgId ? _editMsgId : _replyToId);
|
||||||
}
|
}
|
||||||
if (_replyEditMsg) {
|
if (_replyEditMsg) {
|
||||||
|
const auto media = _replyEditMsg->media();
|
||||||
|
_canReplaceMedia = media && media->allowsEditMedia();
|
||||||
|
_photoEditMedia = (_canReplaceMedia
|
||||||
|
&& media->photo()
|
||||||
|
&& !media->photo()->isNull())
|
||||||
|
? media->photo()->createMediaView()
|
||||||
|
: nullptr;
|
||||||
|
if (_photoEditMedia) {
|
||||||
|
_photoEditMedia->wanted(
|
||||||
|
Data::PhotoSize::Large,
|
||||||
|
_replyEditMsg->fullId());
|
||||||
|
}
|
||||||
|
if (updateReplaceMediaButton()) {
|
||||||
|
updateControlsVisibility();
|
||||||
|
updateControlsGeometry();
|
||||||
|
}
|
||||||
updateReplyEditText(_replyEditMsg);
|
updateReplyEditText(_replyEditMsg);
|
||||||
updateBotKeyboard();
|
updateBotKeyboard();
|
||||||
updateReplyToName();
|
updateReplyToName();
|
||||||
|
@ -7695,6 +7775,9 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
if (drawMsgText) {
|
if (drawMsgText) {
|
||||||
if (hasPreview) {
|
if (hasPreview) {
|
||||||
if (preview) {
|
if (preview) {
|
||||||
|
const auto overEdit = _photoEditMedia
|
||||||
|
? _inPhotoEditOver.value(_inPhotoEdit ? 1. : 0.)
|
||||||
|
: 0.;
|
||||||
auto to = QRect(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height());
|
auto to = QRect(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height());
|
||||||
p.drawPixmap(to.x(), to.y(), preview->pixSingle(
|
p.drawPixmap(to.x(), to.y(), preview->pixSingle(
|
||||||
preview->size() / style::DevicePixelRatio(),
|
preview->size() / style::DevicePixelRatio(),
|
||||||
|
@ -7703,12 +7786,21 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
.outer = to.size(),
|
.outer = to.size(),
|
||||||
}));
|
}));
|
||||||
if (_replySpoiler) {
|
if (_replySpoiler) {
|
||||||
|
if (overEdit > 0.) {
|
||||||
|
p.setOpacity(1. - overEdit);
|
||||||
|
}
|
||||||
Ui::FillSpoilerRect(
|
Ui::FillSpoilerRect(
|
||||||
p,
|
p,
|
||||||
to,
|
to,
|
||||||
Ui::DefaultImageSpoiler().frame(
|
Ui::DefaultImageSpoiler().frame(
|
||||||
_replySpoiler->index(now, pausedSpoiler)));
|
_replySpoiler->index(now, pausedSpoiler)));
|
||||||
}
|
}
|
||||||
|
if (overEdit > 0.) {
|
||||||
|
p.setOpacity(overEdit);
|
||||||
|
p.fillRect(to, st::historyEditMediaBg);
|
||||||
|
st::historyEditMedia.paintInCenter(p, to);
|
||||||
|
p.setOpacity(1.);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
|
replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ class Error;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
enum class PreviewState : char;
|
enum class PreviewState : char;
|
||||||
|
class PhotoMedia;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
namespace SendMenu {
|
namespace SendMenu {
|
||||||
|
@ -145,6 +146,7 @@ public:
|
||||||
void firstLoadMessages();
|
void firstLoadMessages();
|
||||||
void delayedShowAt(MsgId showAtMsgId);
|
void delayedShowAt(MsgId showAtMsgId);
|
||||||
|
|
||||||
|
bool updateReplaceMediaButton();
|
||||||
void updateFieldPlaceholder();
|
void updateFieldPlaceholder();
|
||||||
bool updateStickersByEmoji();
|
bool updateStickersByEmoji();
|
||||||
|
|
||||||
|
@ -634,6 +636,8 @@ private:
|
||||||
HistoryItem *_processingReplyItem = nullptr;
|
HistoryItem *_processingReplyItem = nullptr;
|
||||||
|
|
||||||
MsgId _editMsgId = 0;
|
MsgId _editMsgId = 0;
|
||||||
|
std::shared_ptr<Data::PhotoMedia> _photoEditMedia;
|
||||||
|
bool _canReplaceMedia = false;
|
||||||
|
|
||||||
HistoryItem *_replyEditMsg = nullptr;
|
HistoryItem *_replyEditMsg = nullptr;
|
||||||
Ui::Text::String _replyEditMsgText;
|
Ui::Text::String _replyEditMsgText;
|
||||||
|
@ -732,6 +736,7 @@ private:
|
||||||
object_ptr<Ui::RoundButton> _botMenuButton = { nullptr };
|
object_ptr<Ui::RoundButton> _botMenuButton = { nullptr };
|
||||||
QString _botMenuButtonText;
|
QString _botMenuButtonText;
|
||||||
object_ptr<Ui::IconButton> _attachToggle;
|
object_ptr<Ui::IconButton> _attachToggle;
|
||||||
|
object_ptr<Ui::IconButton> _replaceMedia = { nullptr };
|
||||||
object_ptr<Ui::SendAsButton> _sendAs = { nullptr };
|
object_ptr<Ui::SendAsButton> _sendAs = { nullptr };
|
||||||
object_ptr<Ui::EmojiButton> _tabbedSelectorToggle;
|
object_ptr<Ui::EmojiButton> _tabbedSelectorToggle;
|
||||||
object_ptr<Ui::IconButton> _botKeyboardShow;
|
object_ptr<Ui::IconButton> _botKeyboardShow;
|
||||||
|
@ -746,7 +751,9 @@ private:
|
||||||
bool _cmdStartShown = false;
|
bool _cmdStartShown = false;
|
||||||
object_ptr<Ui::InputField> _field;
|
object_ptr<Ui::InputField> _field;
|
||||||
base::unique_qptr<Ui::RpWidget> _fieldDisabled;
|
base::unique_qptr<Ui::RpWidget> _fieldDisabled;
|
||||||
|
Ui::Animations::Simple _inPhotoEditOver;
|
||||||
bool _inReplyEditForward = false;
|
bool _inReplyEditForward = false;
|
||||||
|
bool _inPhotoEdit = false;
|
||||||
bool _inClickable = false;
|
bool _inClickable = false;
|
||||||
|
|
||||||
bool _kbShown = false;
|
bool _kbShown = false;
|
||||||
|
|
|
@ -482,6 +482,15 @@ historyMessagesTTL: IconButtonWithText {
|
||||||
|
|
||||||
font: font(10px semibold);
|
font: font(10px semibold);
|
||||||
}
|
}
|
||||||
|
historyReplaceMedia: IconButton(historyAttach) {
|
||||||
|
icon: icon {{ "chat/input_replace", windowBgActive }};
|
||||||
|
iconOver: icon {{ "chat/input_replace", windowBgActive }};
|
||||||
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
color: lightButtonBgOver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
historyEditMediaBg: videoPlayIconBg;
|
||||||
|
historyEditMedia: icon{{ "chat/input_draw", videoPlayIconFg }};
|
||||||
historyMessagesTTLPickerHeight: 200px;
|
historyMessagesTTLPickerHeight: 200px;
|
||||||
historyMessagesTTLPickerItemHeight: 40px;
|
historyMessagesTTLPickerItemHeight: 40px;
|
||||||
historyMessagesTTLLabel: FlatLabel(defaultFlatLabel) {
|
historyMessagesTTLLabel: FlatLabel(defaultFlatLabel) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue