mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-08-14 23:43:34 +00:00
Send previewed rich drafts from compose
This commit is contained in:
@@ -4206,6 +4206,55 @@ void ApiWrap::sendShortcutMessages(
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::sendRichMessage(
|
||||
std::shared_ptr<const Iv::RichPage> page,
|
||||
const MTPInputRichMessage &richMessage,
|
||||
SendAction action) {
|
||||
Expects(page != nullptr);
|
||||
|
||||
const auto history = action.history;
|
||||
const auto peer = history->peer;
|
||||
const auto newId = FullMsgId(
|
||||
peer->id,
|
||||
_session->data().nextLocalMessageId());
|
||||
auto flags = NewMessageFlags(peer);
|
||||
if (action.replyTo) {
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
}
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (action.options.scheduled) {
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
}
|
||||
if (action.options.shortcutId) {
|
||||
flags |= MessageFlag::ShortcutMessage;
|
||||
}
|
||||
const auto item = history->addNewLocalMessage({
|
||||
.id = newId.msg,
|
||||
.flags = flags,
|
||||
.from = NewMessageFromId(action),
|
||||
.replyTo = action.replyTo,
|
||||
.date = NewMessageDate(action.options),
|
||||
.scheduleRepeatPeriod = action.options.scheduleRepeatPeriod,
|
||||
.shortcutId = action.options.shortcutId,
|
||||
.starsPaid = std::min(
|
||||
peer->starsPerMessageChecked(),
|
||||
action.options.starsApproved),
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
}, TextWithEntities(), MTP_messageMediaEmpty());
|
||||
item->applyLocalRichPage(std::move(page));
|
||||
|
||||
sendRichMessage(item, richMessage, action);
|
||||
|
||||
_session->data().sendHistoryChangeNotifications();
|
||||
_session->changes().historyUpdated(
|
||||
history,
|
||||
(action.options.scheduled
|
||||
? Data::HistoryUpdate::Flag::ScheduledSent
|
||||
: Data::HistoryUpdate::Flag::MessageSent));
|
||||
}
|
||||
|
||||
void ApiWrap::sendRichMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputRichMessage &richMessage,
|
||||
|
||||
@@ -25,6 +25,10 @@ namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Iv {
|
||||
struct RichPage;
|
||||
} // namespace Iv
|
||||
|
||||
namespace Data {
|
||||
struct ReactionId;
|
||||
struct UpdatedFileReferences;
|
||||
@@ -388,6 +392,10 @@ public:
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputRichMessage &richMessage,
|
||||
SendAction action);
|
||||
void sendRichMessage(
|
||||
std::shared_ptr<const Iv::RichPage> page,
|
||||
const MTPInputRichMessage &richMessage,
|
||||
SendAction action);
|
||||
void sendMessage(
|
||||
MessageToSend &&message,
|
||||
std::optional<MsgId> localMessageId = std::nullopt);
|
||||
|
||||
@@ -72,7 +72,9 @@ int ComputeSendingMessagesCount(
|
||||
not_null<History*> history,
|
||||
const SendingErrorRequest &request) {
|
||||
auto result = 0;
|
||||
if (request.text && !request.text->empty()) {
|
||||
if (request.richMessage) {
|
||||
++result;
|
||||
} else if (request.text && !request.text->empty()) {
|
||||
auto sending = TextWithEntities();
|
||||
auto left = TextWithEntities{
|
||||
request.text->text,
|
||||
@@ -123,7 +125,8 @@ Data::SendError GetErrorForSending(
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto hasText = (request.text && !request.text->empty());
|
||||
const auto hasText = request.richMessage
|
||||
|| (request.text && !request.text->empty());
|
||||
if (hasText) {
|
||||
const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
|
||||
@@ -136,6 +136,7 @@ struct SendingErrorRequest {
|
||||
const TextWithTags *text = nullptr;
|
||||
int messagesCount = 0;
|
||||
bool ignoreSlowmodeCountdown = false;
|
||||
bool richMessage = false;
|
||||
};
|
||||
[[nodiscard]] int ComputeSendingMessagesCount(
|
||||
not_null<History*> history,
|
||||
|
||||
@@ -144,6 +144,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/view/history_view_translate_bar.h"
|
||||
#include "history/view/media/history_view_media.h"
|
||||
#include "iv/editor/iv_editor_session.h"
|
||||
#include "iv/iv_rich_message_serializer.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "chat_helpers/field_autocomplete.h"
|
||||
#include "chat_helpers/tabbed_panel.h"
|
||||
@@ -2163,6 +2164,13 @@ Data::Draft *HistoryWidget::cloudDraft() const {
|
||||
return _history ? _history->cloudDraft(MsgId(), PeerId()) : nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<const Iv::RichPage> HistoryWidget::shownRichMessage() const {
|
||||
if (const auto draft = shouldShowRichDraftPreview() ? cloudDraft() : nullptr) {
|
||||
return draft->richMessage;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool HistoryWidget::isComposeBoxOpen() const {
|
||||
return _history
|
||||
&& Iv::Editor::IsComposeBoxOpen(
|
||||
@@ -2592,6 +2600,7 @@ void HistoryWidget::fastShowAtEnd(not_null<History*> history) {
|
||||
|
||||
bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
||||
if (bypassNormalDraftHandling()) {
|
||||
updateCmdStartShown();
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
return true;
|
||||
@@ -2650,6 +2659,7 @@ bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
||||
}
|
||||
_textUpdateEvents = TextUpdateEvent::SaveDraft
|
||||
| TextUpdateEvent::SendTyping;
|
||||
updateCmdStartShown();
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
refreshTopBarActiveChat();
|
||||
@@ -3441,6 +3451,7 @@ void HistoryWidget::registerThreadFieldBridge() {
|
||||
}
|
||||
unregisterDraftSources();
|
||||
registerDraftSource();
|
||||
updateCmdStartShown();
|
||||
updateSendButtonType();
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
@@ -3775,7 +3786,7 @@ bool HistoryWidget::canWriteMessage() const {
|
||||
void HistoryWidget::updateControlsVisibility() {
|
||||
auto fieldDisabledRemoved = (_fieldDisabled != nullptr);
|
||||
auto fieldVisibilityChanged = false;
|
||||
const auto hideExtraButtons = _fieldCharsCountManager.isLimitExceeded();
|
||||
const auto hideExtra = hideExtraButtons();
|
||||
const auto guard = gsl::finally([&] {
|
||||
if (fieldDisabledRemoved) {
|
||||
_fieldDisabled = nullptr;
|
||||
@@ -4014,7 +4025,7 @@ void HistoryWidget::updateControlsVisibility() {
|
||||
auto rightButtonsChanged = false;
|
||||
if (_silent) {
|
||||
const auto was = _silent->isVisible();
|
||||
const auto now = (!_editMsgId) && (!hideExtraButtons);
|
||||
const auto now = (!_editMsgId) && (!hideExtra);
|
||||
if (was != now) {
|
||||
_silent->setVisible(now);
|
||||
rightButtonsChanged = true;
|
||||
@@ -4022,7 +4033,7 @@ void HistoryWidget::updateControlsVisibility() {
|
||||
}
|
||||
if (_scheduled) {
|
||||
const auto was = _scheduled->isVisible();
|
||||
const auto now = (!_editMsgId) && (!hideExtraButtons);
|
||||
const auto now = (!_editMsgId) && (!hideExtra);
|
||||
if (was != now) {
|
||||
_scheduled->setVisible(now);
|
||||
rightButtonsChanged = true;
|
||||
@@ -4038,7 +4049,7 @@ void HistoryWidget::updateControlsVisibility() {
|
||||
}
|
||||
if (_giftToUser) {
|
||||
const auto was = _giftToUser->isVisible();
|
||||
const auto now = (!_editMsgId) && (!hideExtraButtons);
|
||||
const auto now = (!_editMsgId) && (!hideExtra);
|
||||
if (was != now) {
|
||||
_giftToUser->setVisible(now);
|
||||
rightButtonsChanged = true;
|
||||
@@ -4046,7 +4057,7 @@ void HistoryWidget::updateControlsVisibility() {
|
||||
}
|
||||
if (_ttlInfo) {
|
||||
const auto was = _ttlInfo->isVisible();
|
||||
const auto now = (!_editMsgId) && (!hideExtraButtons);
|
||||
const auto now = (!_editMsgId) && (!hideExtra);
|
||||
if (was != now) {
|
||||
_ttlInfo->setVisible(now);
|
||||
rightButtonsChanged = true;
|
||||
@@ -5352,6 +5363,9 @@ void HistoryWidget::send(Api::SendOptions options) {
|
||||
} else if (_editMsgId) {
|
||||
saveEditMessage({});
|
||||
return;
|
||||
} else if (const auto page = shownRichMessage()) {
|
||||
sendRichDraft(page, options);
|
||||
return;
|
||||
} else if (!options.scheduled && showSlowmodeError()) {
|
||||
return;
|
||||
} else if (_voiceRecordBar->isListenState()) {
|
||||
@@ -5366,6 +5380,78 @@ void HistoryWidget::send(Api::SendOptions options) {
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void HistoryWidget::sendRichDraft(
|
||||
std::shared_ptr<const Iv::RichPage> page,
|
||||
Api::SendOptions options) {
|
||||
if (!page) {
|
||||
return;
|
||||
}
|
||||
if (!options.scheduled) {
|
||||
_cornerButtons.clearReplyReturns();
|
||||
if (showSlowmodeError()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto action = prepareSendAction(options);
|
||||
auto withPaymentApproved = Fn<void(int)>();
|
||||
if (!options.scheduled) {
|
||||
withPaymentApproved = [=](int approved) {
|
||||
auto copy = options;
|
||||
copy.starsApproved = approved;
|
||||
sendRichDraft(page, copy);
|
||||
};
|
||||
}
|
||||
if (showSendRichDraftError(
|
||||
options.scheduled != 0,
|
||||
std::move(withPaymentApproved),
|
||||
action.options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto serialized = Iv::SerializeInputRichMessage(
|
||||
&session(),
|
||||
*page,
|
||||
Iv::SerializeInputRichMessageMode::FinalSubmit);
|
||||
if (serialized.status == Iv::SerializeInputRichMessageStatus::EmptyContent) {
|
||||
controller()->showToast(tr::lng_article_submit_empty(tr::now));
|
||||
return;
|
||||
} else if (serialized.status != Iv::SerializeInputRichMessageStatus::Success
|
||||
|| !serialized.value) {
|
||||
controller()->showToast(tr::lng_attach_failed(tr::now));
|
||||
return;
|
||||
}
|
||||
|
||||
session().api().sendRichMessage(
|
||||
page,
|
||||
*serialized.value,
|
||||
action);
|
||||
|
||||
clearFieldText();
|
||||
if (_preview) {
|
||||
_preview->apply({ .removed = true });
|
||||
}
|
||||
saveDraftWithTextNow();
|
||||
if (session().supportMode()) {
|
||||
updateCmdStartShown();
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
} else {
|
||||
applyCloudDraft(_history);
|
||||
}
|
||||
|
||||
hideSelectorControlsAnimated();
|
||||
setInnerFocus();
|
||||
|
||||
if (!_keyboard->hasMarkup() && _keyboard->forceReply() && !_kbReplyTo) {
|
||||
toggleKeyboard();
|
||||
}
|
||||
session().sendProgressManager().update(
|
||||
_history,
|
||||
Api::SendProgressType::Typing,
|
||||
-1);
|
||||
}
|
||||
|
||||
void HistoryWidget::sendTextWithTags(
|
||||
TextWithTags textWithTags,
|
||||
bool useWebPageDraft,
|
||||
@@ -5460,7 +5546,9 @@ void HistoryWidget::sendScheduled(Api::SendOptions initialOptions) {
|
||||
return;
|
||||
}
|
||||
const auto ignoreSlowmodeCountdown = true;
|
||||
if (showSendMessageError(
|
||||
if (shownRichMessage()
|
||||
? showSendRichDraftError(ignoreSlowmodeCountdown)
|
||||
: showSendMessageError(
|
||||
_field->getTextWithAppliedMarkdown(),
|
||||
ignoreSlowmodeCountdown)) {
|
||||
return;
|
||||
@@ -5534,7 +5622,7 @@ SendMenu::Details HistoryWidget::sendButtonMenuDetails() const {
|
||||
|
||||
SendMenu::Details HistoryWidget::sendButtonDefaultDetails() const {
|
||||
auto result = sendMenuDetails();
|
||||
if (!fieldHasSendText() && !_previewDrawPreview) {
|
||||
if (!hasSendableContent() && !_previewDrawPreview) {
|
||||
result.effectAllowed = false;
|
||||
}
|
||||
return result;
|
||||
@@ -6234,7 +6322,7 @@ bool HistoryWidget::showRecordButton() const {
|
||||
return (_recordAvailability != Webrtc::RecordAvailability::None)
|
||||
&& !_voiceRecordBar->isListenState()
|
||||
&& !_voiceRecordBar->isRecordingByAnotherBar()
|
||||
&& !fieldHasSendText()
|
||||
&& !hasSendableContent()
|
||||
&& !_previewDrawPreview
|
||||
&& (_replyTo || !readyToForward())
|
||||
&& !_editMsgId;
|
||||
@@ -6270,13 +6358,15 @@ void HistoryWidget::updateSendButtonType() {
|
||||
: 0;
|
||||
}();
|
||||
const auto perMessage = _peer ? _peer->starsPerMessageChecked() : 0;
|
||||
const auto richMessage = (shownRichMessage() != nullptr);
|
||||
const auto messages = !_peer
|
||||
? 0
|
||||
: _voiceRecordBar->isListenState()
|
||||
? 1
|
||||
: ComputeSendingMessagesCount(_history, {
|
||||
.forward = &_forwardPanel->items(),
|
||||
.text = &_field->getTextWithTags(),
|
||||
.text = richMessage ? nullptr : &_field->getTextWithTags(),
|
||||
.richMessage = richMessage,
|
||||
});
|
||||
const auto stars = perMessage ? (perMessage * messages) : 0;
|
||||
_send->setState({
|
||||
@@ -6314,7 +6404,7 @@ bool HistoryWidget::updateCmdStartShown() {
|
||||
&& !_keyboard->hasMarkup()
|
||||
&& !_keyboard->forceReply()
|
||||
&& !_editMsgId) {
|
||||
if (!fieldHasSendText()) {
|
||||
if (!hasSendableContent()) {
|
||||
cmdStartShown = true;
|
||||
}
|
||||
}
|
||||
@@ -6719,6 +6809,15 @@ bool HistoryWidget::fieldHasSendText() const {
|
||||
return !_field->isHidden() && HasSendText(_field);
|
||||
}
|
||||
|
||||
bool HistoryWidget::hasSendableContent() const {
|
||||
return fieldHasSendText() || shouldShowRichDraftPreview();
|
||||
}
|
||||
|
||||
bool HistoryWidget::hideExtraButtons() const {
|
||||
return _fieldCharsCountManager.isLimitExceeded()
|
||||
|| shouldShowRichDraftPreview();
|
||||
}
|
||||
|
||||
bool HistoryWidget::hasEnoughLinesForAi() const {
|
||||
return _history
|
||||
&& !_voiceRecordBar->isActive()
|
||||
@@ -7119,6 +7218,35 @@ bool HistoryWidget::showSendMessageError(
|
||||
withPaymentApproved);
|
||||
}
|
||||
|
||||
bool HistoryWidget::showSendRichDraftError(
|
||||
bool ignoreSlowmodeCountdown,
|
||||
Fn<void(int starsApproved)> withPaymentApproved,
|
||||
Api::SendOptions options) {
|
||||
if (!_canSendMessages || !_history || !_peer) {
|
||||
return false;
|
||||
}
|
||||
const auto topicRootId = resolveReplyToTopicRootId();
|
||||
auto request = SendingErrorRequest{
|
||||
.topicRootId = topicRootId,
|
||||
.forward = &_forwardPanel->items(),
|
||||
.messagesCount = 1,
|
||||
.ignoreSlowmodeCountdown = ignoreSlowmodeCountdown,
|
||||
.richMessage = true,
|
||||
};
|
||||
request.messagesCount = ComputeSendingMessagesCount(_history, request);
|
||||
const auto error = GetErrorForSending(_peer, request);
|
||||
if (error) {
|
||||
Data::ShowSendErrorToast(controller(), _peer, error);
|
||||
return true;
|
||||
}
|
||||
|
||||
return withPaymentApproved
|
||||
&& !checkSendPayment(
|
||||
request.messagesCount,
|
||||
options,
|
||||
withPaymentApproved);
|
||||
}
|
||||
|
||||
bool HistoryWidget::confirmSendingFiles(const QStringList &files) {
|
||||
return confirmSendingFiles(files, QString());
|
||||
}
|
||||
@@ -8076,7 +8204,7 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
||||
&& _canSendMessages
|
||||
&& (wasVisible
|
||||
|| (_replyTo && _replyEditMsg)
|
||||
|| (!fieldHasSendText() && !kbWasHidden()))) {
|
||||
|| (!hasSendableContent() && !kbWasHidden()))) {
|
||||
if (!_showAnimation) {
|
||||
if (hasMarkup) {
|
||||
_kbScroll->show();
|
||||
|
||||
@@ -54,6 +54,10 @@ class Widget;
|
||||
struct ResultSelected;
|
||||
} // namespace InlineBots
|
||||
|
||||
namespace Iv {
|
||||
struct RichPage;
|
||||
} // namespace Iv
|
||||
|
||||
namespace Support {
|
||||
class Autocomplete;
|
||||
struct Contact;
|
||||
@@ -448,6 +452,9 @@ private:
|
||||
bool useWebPageDraft,
|
||||
Api::SendOptions options,
|
||||
Fn<void()> done);
|
||||
void sendRichDraft(
|
||||
std::shared_ptr<const Iv::RichPage> page,
|
||||
Api::SendOptions options);
|
||||
void sendVoice(const VoiceToSend &data);
|
||||
void sendWithTextOverride(
|
||||
TextWithEntities text,
|
||||
@@ -521,6 +528,10 @@ private:
|
||||
bool ignoreSlowmodeCountdown,
|
||||
Fn<void(int starsApproved)> withPaymentApproved = nullptr,
|
||||
Api::SendOptions options = {});
|
||||
bool showSendRichDraftError(
|
||||
bool ignoreSlowmodeCountdown,
|
||||
Fn<void(int starsApproved)> withPaymentApproved = nullptr,
|
||||
Api::SendOptions options = {});
|
||||
|
||||
void sendingFilesConfirmed(
|
||||
std::shared_ptr<Ui::PreparedBundle> bundle,
|
||||
@@ -674,12 +685,15 @@ private:
|
||||
[[nodiscard]] int fieldHeight() const;
|
||||
[[nodiscard]] bool fieldOrDisabledShown() const;
|
||||
[[nodiscard]] bool fieldHasSendText() const;
|
||||
[[nodiscard]] bool hasSendableContent() const;
|
||||
[[nodiscard]] bool hideExtraButtons() const;
|
||||
|
||||
void unregisterDraftSources();
|
||||
void registerDraftSource();
|
||||
void unregisterThreadFieldBridge();
|
||||
void registerThreadFieldBridge();
|
||||
[[nodiscard]] Data::Draft *cloudDraft() const;
|
||||
[[nodiscard]] std::shared_ptr<const Iv::RichPage> shownRichMessage() const;
|
||||
[[nodiscard]] bool isComposeBoxOpen() const;
|
||||
[[nodiscard]] bool bypassNormalDraftHandling() const;
|
||||
[[nodiscard]] bool shouldShowRichDraftPreview() const;
|
||||
|
||||
@@ -2087,6 +2087,13 @@ Data::Draft *ComposeControls::cloudDraft() const {
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<const Iv::RichPage> ComposeControls::shownRichMessage() const {
|
||||
if (const auto draft = shouldShowRichDraftPreview() ? cloudDraft() : nullptr) {
|
||||
return draft->richMessage;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ComposeControls::isComposeBoxOpen() const {
|
||||
return _history
|
||||
&& hasRichDraftThreadScope()
|
||||
|
||||
@@ -84,6 +84,10 @@ class Session;
|
||||
struct SendAsKey;
|
||||
} // namespace Main
|
||||
|
||||
namespace Iv {
|
||||
struct RichPage;
|
||||
} // namespace Iv
|
||||
|
||||
namespace Webrtc {
|
||||
enum class RecordAvailability : uchar;
|
||||
} // namespace Webrtc
|
||||
@@ -259,6 +263,7 @@ public:
|
||||
|
||||
[[nodiscard]] TextWithTags getTextWithAppliedMarkdown() const;
|
||||
[[nodiscard]] Data::WebPageDraft webPageDraft() const;
|
||||
[[nodiscard]] std::shared_ptr<const Iv::RichPage> shownRichMessage() const;
|
||||
void setText(const TextWithTags &text);
|
||||
void clear();
|
||||
void hidePanelsAnimated();
|
||||
|
||||
@@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorForSending.
|
||||
#include "iv/iv_rich_message_serializer.h"
|
||||
#include "ui/chat/pinned_bar.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/controls/swipe_handler.h"
|
||||
@@ -1392,6 +1393,9 @@ Api::SendAction ChatWidget::prepareSendAction(
|
||||
|
||||
void ChatWidget::send() {
|
||||
if (_composeControls->getTextWithAppliedMarkdown().text.isEmpty()) {
|
||||
if (const auto page = _composeControls->shownRichMessage()) {
|
||||
sendRichDraft(page, {});
|
||||
}
|
||||
return;
|
||||
}
|
||||
send({});
|
||||
@@ -1425,6 +1429,10 @@ void ChatWidget::sendVoice(const ComposeControls::VoiceToSend &data) {
|
||||
}
|
||||
|
||||
void ChatWidget::send(Api::SendOptions options) {
|
||||
if (const auto page = _composeControls->shownRichMessage()) {
|
||||
sendRichDraft(page, options);
|
||||
return;
|
||||
}
|
||||
if (!options.scheduled && showSlowmodeError()) {
|
||||
return;
|
||||
}
|
||||
@@ -1436,6 +1444,76 @@ void ChatWidget::send(Api::SendOptions options) {
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void ChatWidget::sendRichDraft(
|
||||
std::shared_ptr<const Iv::RichPage> page,
|
||||
Api::SendOptions options) {
|
||||
if (!page) {
|
||||
return;
|
||||
}
|
||||
if (!options.scheduled) {
|
||||
_cornerButtons.clearReplyReturns();
|
||||
if (showSlowmodeError()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto request = SendingErrorRequest{
|
||||
.topicRootId = _topic ? _topic->rootId() : MsgId(0),
|
||||
.forward = &_composeControls->forwardItems(),
|
||||
.messagesCount = 1,
|
||||
.ignoreSlowmodeCountdown = (options.scheduled != 0),
|
||||
.richMessage = true,
|
||||
};
|
||||
const auto error = GetErrorForSending(_peer, request);
|
||||
if (error) {
|
||||
Data::ShowSendErrorToast(controller(), _peer, error);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto serialized = Iv::SerializeInputRichMessage(
|
||||
&session(),
|
||||
*page,
|
||||
Iv::SerializeInputRichMessageMode::FinalSubmit);
|
||||
if (serialized.status == Iv::SerializeInputRichMessageStatus::EmptyContent) {
|
||||
controller()->showToast(tr::lng_article_submit_empty(tr::now));
|
||||
return;
|
||||
} else if (serialized.status != Iv::SerializeInputRichMessageStatus::Success
|
||||
|| !serialized.value) {
|
||||
controller()->showToast(tr::lng_attach_failed(tr::now));
|
||||
return;
|
||||
}
|
||||
if (!options.scheduled) {
|
||||
const auto withPaymentApproved = [=](int approved) {
|
||||
auto copy = options;
|
||||
copy.starsApproved = approved;
|
||||
sendRichDraft(page, copy);
|
||||
};
|
||||
const auto checked = checkSendPayment(
|
||||
1,
|
||||
options,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
session().api().sendRichMessage(
|
||||
page,
|
||||
*serialized.value,
|
||||
prepareSendAction(options));
|
||||
|
||||
_composeControls->clear();
|
||||
_composeControls->applyCloudDraft();
|
||||
if (_repliesRootId) {
|
||||
session().sendProgressManager().update(
|
||||
_history,
|
||||
_repliesRootId,
|
||||
Api::SendProgressType::Typing,
|
||||
-1);
|
||||
}
|
||||
finishSending();
|
||||
}
|
||||
|
||||
void ChatWidget::sendTextWithTags(
|
||||
TextWithTags textWithTags,
|
||||
bool useCurrentWebPageDraft,
|
||||
|
||||
@@ -51,6 +51,10 @@ namespace InlineBots {
|
||||
class Result;
|
||||
} // namespace InlineBots
|
||||
|
||||
namespace Iv {
|
||||
struct RichPage;
|
||||
} // namespace Iv
|
||||
|
||||
namespace Data {
|
||||
class RepliesList;
|
||||
class ForumTopic;
|
||||
@@ -300,6 +304,9 @@ private:
|
||||
bool useCurrentWebPageDraft,
|
||||
Api::SendOptions options,
|
||||
Fn<void()> done);
|
||||
void sendRichDraft(
|
||||
std::shared_ptr<const Iv::RichPage> page,
|
||||
Api::SendOptions options);
|
||||
void sendWithTextOverride(
|
||||
TextWithEntities text,
|
||||
Api::SendOptions options,
|
||||
|
||||
@@ -1387,6 +1387,30 @@ void PaintTableCaption(
|
||||
&& (block.horizontalScrollLeft < block.horizontalScrollMax);
|
||||
}
|
||||
|
||||
[[nodiscard]] QRect HorizontalOverflowContentClip(
|
||||
const LaidOutBlock &block,
|
||||
const style::Markdown &st,
|
||||
QRect viewport) {
|
||||
if (block.horizontalScrollMax <= 0 || viewport.isEmpty()) {
|
||||
return viewport;
|
||||
}
|
||||
const auto indicatorWidth = std::min(
|
||||
std::max(OverflowIndicatorWidth(block, st), 1),
|
||||
viewport.width());
|
||||
const auto left = (block.horizontalScrollLeft > 0)
|
||||
? indicatorWidth
|
||||
: 0;
|
||||
const auto right = HorizontalRightEdgeHidden(block)
|
||||
? indicatorWidth
|
||||
: 0;
|
||||
const auto width = std::max(viewport.width() - left - right, 0);
|
||||
return QRect(
|
||||
viewport.x() + left,
|
||||
viewport.y(),
|
||||
width,
|
||||
viewport.height());
|
||||
}
|
||||
|
||||
[[nodiscard]] QRect HorizontalScrollLogicalPaintRect(
|
||||
const LaidOutBlock &block) {
|
||||
if (block.insideHorizontalScroll) {
|
||||
@@ -1509,7 +1533,9 @@ void PaintWholeTable(
|
||||
if (tableClip.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const auto tableContext = ClippedContext(context, tableClip);
|
||||
const auto textClip = tableClip.intersected(
|
||||
HorizontalOverflowContentClip(block, st, block.visibleTableRect));
|
||||
const auto tableContext = ClippedContext(context, textClip);
|
||||
|
||||
const auto border = TableBorder(block, st);
|
||||
const auto radius = st.table.radius;
|
||||
@@ -1630,7 +1656,8 @@ void PaintTableRowBand(
|
||||
const auto cells = TableCellsForRowBand(ownership, rowIndex, rowBand);
|
||||
const auto rowContext = ClippedContext(
|
||||
RevealSuppressedContext(context),
|
||||
rowClip);
|
||||
rowClip.intersected(
|
||||
HorizontalOverflowContentClip(block, st, block.visibleTableRect)));
|
||||
|
||||
p.save();
|
||||
p.setClipRect(rowClip, Qt::IntersectClip);
|
||||
|
||||
Reference in New Issue
Block a user