mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Add sending paid stories replies.
This commit is contained in:
parent
fe2df96953
commit
1684465e04
14 changed files with 442 additions and 156 deletions
|
@ -2167,14 +2167,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_action_set_chat_intro" = "{from} added the message below for all empty chats. How?";
|
"lng_action_set_chat_intro" = "{from} added the message below for all empty chats. How?";
|
||||||
"lng_action_payment_refunded" = "{peer} refunded {amount}";
|
"lng_action_payment_refunded" = "{peer} refunded {amount}";
|
||||||
"lng_action_paid_message_sent#one" = "You paid {count} Star to {action}";
|
"lng_action_paid_message_sent#one" = "You paid {count} Star to {action}";
|
||||||
"lng_action_paid_message_sent#other" = "You paid {count} Star to {action}";
|
"lng_action_paid_message_sent#other" = "You paid {count} Stars to {action}";
|
||||||
"lng_action_paid_message_group#one" = "{from} paid {count} Star to {action}";
|
|
||||||
"lng_action_paid_message_group#other" = "{from} paid {count} Star to {action}";
|
|
||||||
"lng_action_paid_message_one" = "send a message";
|
"lng_action_paid_message_one" = "send a message";
|
||||||
"lng_action_paid_message_some#one" = "send {count} message";
|
"lng_action_paid_message_some#one" = "send {count} message";
|
||||||
"lng_action_paid_message_some#other" = "send {count} messages";
|
"lng_action_paid_message_some#other" = "send {count} messages";
|
||||||
"lng_action_paid_message_got#one" = "You received {count} Star from {name}";
|
"lng_action_paid_message_got#one" = "You received {count} Star from {name}";
|
||||||
"lng_action_paid_message_got#other" = "You received {count} Stars from {name}";
|
"lng_action_paid_message_got#other" = "You received {count} Stars from {name}";
|
||||||
|
"lng_you_paid_stars#one" = "You paid {count} Star.";
|
||||||
|
"lng_you_paid_stars#other" = "You paid {count} Stars.";
|
||||||
|
|
||||||
"lng_similar_channels_title" = "Similar channels";
|
"lng_similar_channels_title" = "Similar channels";
|
||||||
"lng_similar_channels_view_all" = "View all";
|
"lng_similar_channels_view_all" = "View all";
|
||||||
|
|
|
@ -382,13 +382,15 @@ bool SendPaymentHelper::check(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
int messagesCount,
|
int messagesCount,
|
||||||
int starsApproved,
|
int starsApproved,
|
||||||
Fn<void(int)> resend) {
|
Fn<void(int)> resend,
|
||||||
|
PaidConfirmStyles styles) {
|
||||||
return check(
|
return check(
|
||||||
navigation->uiShow(),
|
navigation->uiShow(),
|
||||||
peer,
|
peer,
|
||||||
messagesCount,
|
messagesCount,
|
||||||
starsApproved,
|
starsApproved,
|
||||||
std::move(resend));
|
std::move(resend),
|
||||||
|
styles);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SendPaymentHelper::check(
|
bool SendPaymentHelper::check(
|
||||||
|
@ -396,8 +398,10 @@ bool SendPaymentHelper::check(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
int messagesCount,
|
int messagesCount,
|
||||||
int starsApproved,
|
int starsApproved,
|
||||||
Fn<void(int)> resend) {
|
Fn<void(int)> resend,
|
||||||
_lifetime.destroy();
|
PaidConfirmStyles styles) {
|
||||||
|
clear();
|
||||||
|
|
||||||
const auto details = ComputePaymentDetails(peer, messagesCount);
|
const auto details = ComputePaymentDetails(peer, messagesCount);
|
||||||
if (!details) {
|
if (!details) {
|
||||||
_resend = [=] { resend(starsApproved); };
|
_resend = [=] { resend(starsApproved); };
|
||||||
|
@ -426,12 +430,17 @@ bool SendPaymentHelper::check(
|
||||||
} else if (const auto stars = details->stars; stars > starsApproved) {
|
} else if (const auto stars = details->stars; stars > starsApproved) {
|
||||||
ShowSendPaidConfirm(show, peer, *details, [=] {
|
ShowSendPaidConfirm(show, peer, *details, [=] {
|
||||||
resend(stars);
|
resend(stars);
|
||||||
});
|
}, styles);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SendPaymentHelper::clear() {
|
||||||
|
_lifetime.destroy();
|
||||||
|
_resend = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void RequestDependentMessageItem(
|
void RequestDependentMessageItem(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
PeerId peerId,
|
PeerId peerId,
|
||||||
|
|
|
@ -179,13 +179,17 @@ public:
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
int messagesCount,
|
int messagesCount,
|
||||||
int starsApproved,
|
int starsApproved,
|
||||||
Fn<void(int)> resend);
|
Fn<void(int)> resend,
|
||||||
|
PaidConfirmStyles styles = {});
|
||||||
[[nodiscard]] bool check(
|
[[nodiscard]] bool check(
|
||||||
std::shared_ptr<Main::SessionShow> show,
|
std::shared_ptr<Main::SessionShow> show,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
int messagesCount,
|
int messagesCount,
|
||||||
int starsApproved,
|
int starsApproved,
|
||||||
Fn<void(int)> resend);
|
Fn<void(int)> resend,
|
||||||
|
PaidConfirmStyles styles = {});
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Fn<void()> _resend;
|
Fn<void()> _resend;
|
||||||
|
|
|
@ -225,16 +225,6 @@ const auto kPsaAboutPrefix = "cloud_lng_about_psa_";
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
struct HistoryWidget::SendingFiles {
|
|
||||||
std::vector<Ui::PreparedGroup> groups;
|
|
||||||
Ui::SendFilesWay way;
|
|
||||||
TextWithTags caption;
|
|
||||||
Api::SendOptions options;
|
|
||||||
int totalCount = 0;
|
|
||||||
bool sendComment = false;
|
|
||||||
bool ctrlShiftEnter = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
HistoryWidget::HistoryWidget(
|
HistoryWidget::HistoryWidget(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<Window::SessionController*> controller)
|
not_null<Window::SessionController*> controller)
|
||||||
|
@ -898,17 +888,6 @@ HistoryWidget::HistoryWidget(
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
if (!session().credits().loaded()) {
|
|
||||||
session().credits().loadedValue(
|
|
||||||
) | rpl::filter(
|
|
||||||
rpl::mappers::_1
|
|
||||||
) | rpl::take(1) | rpl::start_with_next([=] {
|
|
||||||
if (const auto callback = base::take(_resendOnFullUpdated)) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}, lifetime());
|
|
||||||
}
|
|
||||||
|
|
||||||
using Type = Data::DefaultNotify;
|
using Type = Data::DefaultNotify;
|
||||||
rpl::merge(
|
rpl::merge(
|
||||||
session().data().notifySettings().defaultUpdates(Type::User),
|
session().data().notifySettings().defaultUpdates(Type::User),
|
||||||
|
@ -2400,7 +2379,7 @@ void HistoryWidget::showHistory(
|
||||||
setHistory(nullptr);
|
setHistory(nullptr);
|
||||||
_list = nullptr;
|
_list = nullptr;
|
||||||
_peer = nullptr;
|
_peer = nullptr;
|
||||||
_resendOnFullUpdated = nullptr;
|
_sendPayment.clear();
|
||||||
_topicsRequested.clear();
|
_topicsRequested.clear();
|
||||||
_canSendMessages = false;
|
_canSendMessages = false;
|
||||||
_canSendTexts = false;
|
_canSendTexts = false;
|
||||||
|
@ -4412,7 +4391,7 @@ void HistoryWidget::send(Api::SendOptions options) {
|
||||||
if (showSendMessageError(
|
if (showSendMessageError(
|
||||||
message.textWithTags,
|
message.textWithTags,
|
||||||
ignoreSlowmodeCountdown,
|
ignoreSlowmodeCountdown,
|
||||||
crl::guard(this, withPaymentApproved),
|
withPaymentApproved,
|
||||||
options.starsApproved)) {
|
options.starsApproved)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4735,6 +4714,19 @@ FullMsgId HistoryWidget::cornerButtonsCurrentId() {
|
||||||
: FullMsgId();
|
: FullMsgId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryWidget::checkSendPayment(
|
||||||
|
int messagesCount,
|
||||||
|
int starsApproved,
|
||||||
|
Fn<void(int)> withPaymentApproved) {
|
||||||
|
return _peer
|
||||||
|
&& _sendPayment.check(
|
||||||
|
controller(),
|
||||||
|
_peer,
|
||||||
|
messagesCount,
|
||||||
|
starsApproved,
|
||||||
|
std::move(withPaymentApproved));
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryWidget::checkSuggestToGigagroup() {
|
void HistoryWidget::checkSuggestToGigagroup() {
|
||||||
const auto group = _peer ? _peer->asMegagroup() : nullptr;
|
const auto group = _peer ? _peer->asMegagroup() : nullptr;
|
||||||
if (!group || !group->owner().suggestToGigagroup(group)) {
|
if (!group || !group->owner().suggestToGigagroup(group)) {
|
||||||
|
@ -5890,7 +5882,7 @@ Data::ForumTopic *HistoryWidget::resolveReplyToTopic() {
|
||||||
bool HistoryWidget::showSendMessageError(
|
bool HistoryWidget::showSendMessageError(
|
||||||
const TextWithTags &textWithTags,
|
const TextWithTags &textWithTags,
|
||||||
bool ignoreSlowmodeCountdown,
|
bool ignoreSlowmodeCountdown,
|
||||||
Fn<void(int starsApproved)> resend,
|
Fn<void(int starsApproved)> withPaymentApproved,
|
||||||
int starsApproved) {
|
int starsApproved) {
|
||||||
if (!_canSendMessages) {
|
if (!_canSendMessages) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -5908,25 +5900,12 @@ bool HistoryWidget::showSendMessageError(
|
||||||
Data::ShowSendErrorToast(controller(), _peer, error);
|
Data::ShowSendErrorToast(controller(), _peer, error);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return resend
|
|
||||||
&& !checkSendPayment(request.messagesCount, starsApproved, resend);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HistoryWidget::checkSendPayment(
|
return withPaymentApproved
|
||||||
int messagesCount,
|
&& !checkSendPayment(
|
||||||
int starsApproved,
|
request.messagesCount,
|
||||||
Fn<void(int starsApproved)> resend) {
|
starsApproved,
|
||||||
const auto details = ComputePaymentDetails(_peer, messagesCount);
|
withPaymentApproved);
|
||||||
if (!details) {
|
|
||||||
_resendOnFullUpdated = [=] { resend(starsApproved); };
|
|
||||||
return false;
|
|
||||||
} else if (const auto stars = details->stars; stars > starsApproved) {
|
|
||||||
ShowSendPaidConfirm(controller(), _peer, *details, [=] {
|
|
||||||
resend(stars);
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryWidget::confirmSendingFiles(const QStringList &files) {
|
bool HistoryWidget::confirmSendingFiles(const QStringList &files) {
|
||||||
|
@ -6012,11 +5991,11 @@ bool HistoryWidget::confirmSendingFiles(
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::sendingFilesConfirmed(
|
void HistoryWidget::sendingFilesConfirmed(
|
||||||
Ui::PreparedList &&list,
|
Ui::PreparedList &&list,
|
||||||
Ui::SendFilesWay way,
|
Ui::SendFilesWay way,
|
||||||
TextWithTags &&caption,
|
TextWithTags &&caption,
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
bool ctrlShiftEnter) {
|
bool ctrlShiftEnter) {
|
||||||
Expects(list.filesToProcess.empty());
|
Expects(list.filesToProcess.empty());
|
||||||
|
|
||||||
const auto compress = way.sendImagesAsPhotos();
|
const auto compress = way.sendImagesAsPhotos();
|
||||||
|
@ -6024,55 +6003,51 @@ void HistoryWidget::sendingFilesConfirmed(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto filesCount = int(list.files.size());
|
|
||||||
auto groups = DivideByGroups(
|
auto groups = DivideByGroups(
|
||||||
std::move(list),
|
std::move(list),
|
||||||
way,
|
way,
|
||||||
_peer->slowmodeApplied());
|
_peer->slowmodeApplied());
|
||||||
const auto sendComment = !caption.text.isEmpty()
|
auto bundle = PrepareFilesBundle(
|
||||||
&& (groups.size() != 1 || !groups.front().sentWithCaption());
|
std::move(groups),
|
||||||
sendingFilesConfirmed(std::make_shared<SendingFiles>(SendingFiles{
|
way,
|
||||||
.groups = std::move(groups),
|
std::move(caption),
|
||||||
.way = way,
|
ctrlShiftEnter);
|
||||||
.caption = std::move(caption),
|
sendingFilesConfirmed(std::move(bundle), options);
|
||||||
.options = options,
|
|
||||||
.totalCount = filesCount + (sendComment ? 1 : 0),
|
|
||||||
.sendComment = sendComment,
|
|
||||||
.ctrlShiftEnter = ctrlShiftEnter,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::sendingFilesConfirmed(
|
void HistoryWidget::sendingFilesConfirmed(
|
||||||
std::shared_ptr<SendingFiles> args) {
|
std::shared_ptr<Ui::PreparedBundle> bundle,
|
||||||
|
Api::SendOptions options) {
|
||||||
const auto withPaymentApproved = [=](int approved) {
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
args->options.starsApproved = approved;
|
auto copy = options;
|
||||||
sendingFilesConfirmed(args);
|
copy.starsApproved = approved;
|
||||||
|
sendingFilesConfirmed(bundle, copy);
|
||||||
};
|
};
|
||||||
const auto checked = checkSendPayment(
|
const auto checked = checkSendPayment(
|
||||||
args->totalCount,
|
bundle->totalCount,
|
||||||
args->options.starsApproved,
|
options.starsApproved,
|
||||||
withPaymentApproved);
|
withPaymentApproved);
|
||||||
if (!checked) {
|
if (!checked) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto compress = args->way.sendImagesAsPhotos();
|
const auto compress = bundle->way.sendImagesAsPhotos();
|
||||||
const auto type = compress ? SendMediaType::Photo : SendMediaType::File;
|
const auto type = compress ? SendMediaType::Photo : SendMediaType::File;
|
||||||
auto action = prepareSendAction(args->options);
|
auto action = prepareSendAction(options);
|
||||||
action.clearDraft = false;
|
action.clearDraft = false;
|
||||||
if (args->sendComment) {
|
if (bundle->sendComment) {
|
||||||
auto message = Api::MessageToSend(action);
|
auto message = Api::MessageToSend(action);
|
||||||
message.textWithTags = base::take(args->caption);
|
message.textWithTags = base::take(bundle->caption);
|
||||||
session().api().sendMessage(std::move(message));
|
session().api().sendMessage(std::move(message));
|
||||||
}
|
}
|
||||||
for (auto &group : args->groups) {
|
for (auto &group : bundle->groups) {
|
||||||
const auto album = (group.type != Ui::AlbumType::None)
|
const auto album = (group.type != Ui::AlbumType::None)
|
||||||
? std::make_shared<SendingAlbum>()
|
? std::make_shared<SendingAlbum>()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
session().api().sendFiles(
|
session().api().sendFiles(
|
||||||
std::move(group.list),
|
std::move(group.list),
|
||||||
type,
|
type,
|
||||||
base::take(args->caption),
|
base::take(bundle->caption),
|
||||||
album,
|
album,
|
||||||
action);
|
action);
|
||||||
}
|
}
|
||||||
|
@ -8545,9 +8520,6 @@ void HistoryWidget::fullInfoUpdated() {
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
}
|
}
|
||||||
if (const auto callback = base::take(_resendOnFullUpdated)) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::handlePeerUpdate() {
|
void HistoryWidget::handlePeerUpdate() {
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/view/controls/history_view_compose_media_edit_manager.h"
|
#include "history/view/controls/history_view_compose_media_edit_manager.h"
|
||||||
#include "history/view/history_view_corner_buttons.h"
|
#include "history/view/history_view_corner_buttons.h"
|
||||||
#include "history/history_drag_area.h"
|
#include "history/history_drag_area.h"
|
||||||
|
#include "history/history_item_helpers.h"
|
||||||
#include "history/history_view_highlight_manager.h"
|
#include "history/history_view_highlight_manager.h"
|
||||||
#include "history/history_view_top_toast.h"
|
#include "history/history_view_top_toast.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -69,6 +70,7 @@ class PinnedBar;
|
||||||
class GroupCallBar;
|
class GroupCallBar;
|
||||||
class RequestsBar;
|
class RequestsBar;
|
||||||
struct PreparedList;
|
struct PreparedList;
|
||||||
|
struct PreparedBundle;
|
||||||
class SendFilesWay;
|
class SendFilesWay;
|
||||||
class SendAsButton;
|
class SendAsButton;
|
||||||
class SpoilerAnimation;
|
class SpoilerAnimation;
|
||||||
|
@ -320,7 +322,6 @@ private:
|
||||||
using TabbedPanel = ChatHelpers::TabbedPanel;
|
using TabbedPanel = ChatHelpers::TabbedPanel;
|
||||||
using TabbedSelector = ChatHelpers::TabbedSelector;
|
using TabbedSelector = ChatHelpers::TabbedSelector;
|
||||||
using VoiceToSend = HistoryView::Controls::VoiceToSend;
|
using VoiceToSend = HistoryView::Controls::VoiceToSend;
|
||||||
struct SendingFiles;
|
|
||||||
enum ScrollChangeType {
|
enum ScrollChangeType {
|
||||||
ScrollChangeNone,
|
ScrollChangeNone,
|
||||||
|
|
||||||
|
@ -359,6 +360,11 @@ private:
|
||||||
bool cornerButtonsUnreadMayBeShown() override;
|
bool cornerButtonsUnreadMayBeShown() override;
|
||||||
bool cornerButtonsHas(HistoryView::CornerButtonType type) override;
|
bool cornerButtonsHas(HistoryView::CornerButtonType type) override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool checkSendPayment(
|
||||||
|
int messagesCount,
|
||||||
|
int starsApproved,
|
||||||
|
Fn<void(int)> withPaymentApproved);
|
||||||
|
|
||||||
void checkSuggestToGigagroup();
|
void checkSuggestToGigagroup();
|
||||||
void processReply();
|
void processReply();
|
||||||
void setReplyFieldsFromProcessing();
|
void setReplyFieldsFromProcessing();
|
||||||
|
@ -471,12 +477,8 @@ private:
|
||||||
bool showSendMessageError(
|
bool showSendMessageError(
|
||||||
const TextWithTags &textWithTags,
|
const TextWithTags &textWithTags,
|
||||||
bool ignoreSlowmodeCountdown,
|
bool ignoreSlowmodeCountdown,
|
||||||
Fn<void(int starsApproved)> resend = nullptr,
|
Fn<void(int starsApproved)> withPaymentApproved = nullptr,
|
||||||
int starsApproved = 0);
|
int starsApproved = 0);
|
||||||
bool checkSendPayment(
|
|
||||||
int messagesCount,
|
|
||||||
int starsApproved,
|
|
||||||
Fn<void(int starsApproved)> resend);
|
|
||||||
|
|
||||||
void sendingFilesConfirmed(
|
void sendingFilesConfirmed(
|
||||||
Ui::PreparedList &&list,
|
Ui::PreparedList &&list,
|
||||||
|
@ -484,7 +486,9 @@ private:
|
||||||
TextWithTags &&caption,
|
TextWithTags &&caption,
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
bool ctrlShiftEnter);
|
bool ctrlShiftEnter);
|
||||||
void sendingFilesConfirmed(std::shared_ptr<SendingFiles> args);
|
void sendingFilesConfirmed(
|
||||||
|
std::shared_ptr<Ui::PreparedBundle> bundle,
|
||||||
|
Api::SendOptions options);
|
||||||
|
|
||||||
void uploadFile(const QByteArray &fileContent, SendMediaType type);
|
void uploadFile(const QByteArray &fileContent, SendMediaType type);
|
||||||
void itemRemoved(not_null<const HistoryItem*> item);
|
void itemRemoved(not_null<const HistoryItem*> item);
|
||||||
|
@ -769,7 +773,6 @@ private:
|
||||||
std::unique_ptr<ChatHelpers::FieldAutocomplete> _autocomplete;
|
std::unique_ptr<ChatHelpers::FieldAutocomplete> _autocomplete;
|
||||||
std::unique_ptr<Ui::Emoji::SuggestionsController> _emojiSuggestions;
|
std::unique_ptr<Ui::Emoji::SuggestionsController> _emojiSuggestions;
|
||||||
object_ptr<Support::Autocomplete> _supportAutocomplete;
|
object_ptr<Support::Autocomplete> _supportAutocomplete;
|
||||||
Fn<void()> _resendOnFullUpdated;
|
|
||||||
|
|
||||||
UserData *_inlineBot = nullptr;
|
UserData *_inlineBot = nullptr;
|
||||||
QString _inlineBotUsername;
|
QString _inlineBotUsername;
|
||||||
|
@ -874,6 +877,8 @@ private:
|
||||||
|
|
||||||
int _topDelta = 0;
|
int _topDelta = 0;
|
||||||
|
|
||||||
|
SendPaymentHelper _sendPayment;
|
||||||
|
|
||||||
rpl::event_stream<> _cancelRequests;
|
rpl::event_stream<> _cancelRequests;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1722,13 +1722,20 @@ void ComposeControls::updateFieldPlaceholder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_field->setPlaceholder([&] {
|
_field->setPlaceholder([&] {
|
||||||
|
const auto peer = _history ? _history->peer.get() : nullptr;
|
||||||
if (_fieldCustomPlaceholder) {
|
if (_fieldCustomPlaceholder) {
|
||||||
return rpl::duplicate(_fieldCustomPlaceholder);
|
return rpl::duplicate(_fieldCustomPlaceholder);
|
||||||
} else if (isEditingMessage()) {
|
} else if (isEditingMessage()) {
|
||||||
return tr::lng_edit_message_text();
|
return tr::lng_edit_message_text();
|
||||||
} else if (!_history) {
|
} else if (!peer) {
|
||||||
return tr::lng_message_ph();
|
return tr::lng_message_ph();
|
||||||
} else if (const auto channel = _history->peer->asChannel()) {
|
} else if (const auto stars = peer->starsPerMessageChecked()) {
|
||||||
|
return tr::lng_message_paid_ph(
|
||||||
|
lt_amount,
|
||||||
|
tr::lng_prize_credits_amount(
|
||||||
|
lt_count,
|
||||||
|
rpl::single(stars * 1.)));
|
||||||
|
} else if (const auto channel = peer->asChannel()) {
|
||||||
if (channel->isBroadcast()) {
|
if (channel->isBroadcast()) {
|
||||||
return session().data().notifySettings().silentPosts(channel)
|
return session().data().notifySettings().silentPosts(channel)
|
||||||
? tr::lng_broadcast_silent_ph()
|
? tr::lng_broadcast_silent_ph()
|
||||||
|
@ -3120,6 +3127,7 @@ void ComposeControls::initWebpageProcess() {
|
||||||
| Data::PeerUpdate::Flag::Notifications
|
| Data::PeerUpdate::Flag::Notifications
|
||||||
| Data::PeerUpdate::Flag::MessagesTTL
|
| Data::PeerUpdate::Flag::MessagesTTL
|
||||||
| Data::PeerUpdate::Flag::FullInfo
|
| Data::PeerUpdate::Flag::FullInfo
|
||||||
|
| Data::PeerUpdate::Flag::StarsPerMessage
|
||||||
) | rpl::filter([peer = _history->peer](const Data::PeerUpdate &update) {
|
) | rpl::filter([peer = _history->peer](const Data::PeerUpdate &update) {
|
||||||
return (update.peer.get() == peer);
|
return (update.peer.get() == peer);
|
||||||
}) | rpl::map([](const Data::PeerUpdate &update) {
|
}) | rpl::map([](const Data::PeerUpdate &update) {
|
||||||
|
@ -3135,6 +3143,9 @@ void ComposeControls::initWebpageProcess() {
|
||||||
if (flags & Data::PeerUpdate::Flag::MessagesTTL) {
|
if (flags & Data::PeerUpdate::Flag::MessagesTTL) {
|
||||||
updateMessagesTTLShown();
|
updateMessagesTTLShown();
|
||||||
}
|
}
|
||||||
|
if (flags & Data::PeerUpdate::Flag::StarsPerMessage) {
|
||||||
|
updateFieldPlaceholder();
|
||||||
|
}
|
||||||
if (flags & Data::PeerUpdate::Flag::FullInfo) {
|
if (flags & Data::PeerUpdate::Flag::FullInfo) {
|
||||||
if (updateBotCommandShown()) {
|
if (updateBotCommandShown()) {
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
|
|
|
@ -384,6 +384,9 @@ QString DateTooltipText(not_null<Element*> view) {
|
||||||
if (item->isScheduled() && item->isSilent()) {
|
if (item->isScheduled() && item->isSilent()) {
|
||||||
dateText += '\n' + QChar(0xD83D) + QChar(0xDD15);
|
dateText += '\n' + QChar(0xD83D) + QChar(0xDD15);
|
||||||
}
|
}
|
||||||
|
if (const auto stars = item->out() ? item->starsPaid() : 0) {
|
||||||
|
dateText += '\n' + tr::lng_you_paid_stars(tr::now, lt_count, stars);
|
||||||
|
}
|
||||||
return dateText;
|
return dateText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -476,22 +476,12 @@ void Message::initPaidInformation() {
|
||||||
lt_action,
|
lt_action,
|
||||||
action(),
|
action(),
|
||||||
Ui::Text::WithEntities)
|
Ui::Text::WithEntities)
|
||||||
: history()->peer->isUser()
|
: tr::lng_action_paid_message_got(
|
||||||
? tr::lng_action_paid_message_got(
|
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_count,
|
lt_count,
|
||||||
info.stars,
|
info.stars,
|
||||||
lt_name,
|
lt_name,
|
||||||
Ui::Text::Link(item->from()->shortName(), 1),
|
Ui::Text::Link(item->from()->shortName(), 1),
|
||||||
Ui::Text::WithEntities)
|
|
||||||
: tr::lng_action_paid_message_group(
|
|
||||||
tr::now,
|
|
||||||
lt_count,
|
|
||||||
info.stars,
|
|
||||||
lt_from,
|
|
||||||
Ui::Text::Link(item->from()->shortName(), 1),
|
|
||||||
lt_action,
|
|
||||||
action(),
|
|
||||||
Ui::Text::WithEntities),
|
Ui::Text::WithEntities),
|
||||||
};
|
};
|
||||||
if (!item->out()) {
|
if (!item->out()) {
|
||||||
|
|
|
@ -733,8 +733,8 @@ void RepliesWidget::setupComposeControls() {
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_composeControls->sendVoiceRequests(
|
_composeControls->sendVoiceRequests(
|
||||||
) | rpl::start_with_next([=](ComposeControls::VoiceToSend &&data) {
|
) | rpl::start_with_next([=](const ComposeControls::VoiceToSend &data) {
|
||||||
sendVoice(std::move(data));
|
sendVoice(data);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_composeControls->sendCommandRequests(
|
_composeControls->sendCommandRequests(
|
||||||
|
@ -1070,25 +1070,59 @@ void RepliesWidget::sendingFilesConfirmed(
|
||||||
std::move(list),
|
std::move(list),
|
||||||
way,
|
way,
|
||||||
_history->peer->slowmodeApplied());
|
_history->peer->slowmodeApplied());
|
||||||
const auto type = way.sendImagesAsPhotos()
|
auto bundle = PrepareFilesBundle(
|
||||||
? SendMediaType::Photo
|
std::move(groups),
|
||||||
: SendMediaType::File;
|
way,
|
||||||
|
std::move(caption),
|
||||||
|
ctrlShiftEnter);
|
||||||
|
sendingFilesConfirmed(std::move(bundle), options);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepliesWidget::checkSendPayment(
|
||||||
|
int messagesCount,
|
||||||
|
int starsApproved,
|
||||||
|
Fn<void(int)> withPaymentApproved) {
|
||||||
|
return _sendPayment.check(
|
||||||
|
controller(),
|
||||||
|
_history->peer,
|
||||||
|
messagesCount,
|
||||||
|
starsApproved,
|
||||||
|
std::move(withPaymentApproved));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepliesWidget::sendingFilesConfirmed(
|
||||||
|
std::shared_ptr<Ui::PreparedBundle> bundle,
|
||||||
|
Api::SendOptions options) {
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = options;
|
||||||
|
copy.starsApproved = approved;
|
||||||
|
sendingFilesConfirmed(bundle, copy);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
bundle->totalCount,
|
||||||
|
options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto compress = bundle->way.sendImagesAsPhotos();
|
||||||
|
const auto type = compress ? SendMediaType::Photo : SendMediaType::File;
|
||||||
auto action = prepareSendAction(options);
|
auto action = prepareSendAction(options);
|
||||||
action.clearDraft = false;
|
action.clearDraft = false;
|
||||||
if ((groups.size() != 1 || !groups.front().sentWithCaption())
|
if (bundle->sendComment) {
|
||||||
&& !caption.text.isEmpty()) {
|
|
||||||
auto message = Api::MessageToSend(action);
|
auto message = Api::MessageToSend(action);
|
||||||
message.textWithTags = base::take(caption);
|
message.textWithTags = base::take(bundle->caption);
|
||||||
session().api().sendMessage(std::move(message));
|
session().api().sendMessage(std::move(message));
|
||||||
}
|
}
|
||||||
for (auto &group : groups) {
|
for (auto &group : bundle->groups) {
|
||||||
const auto album = (group.type != Ui::AlbumType::None)
|
const auto album = (group.type != Ui::AlbumType::None)
|
||||||
? std::make_shared<SendingAlbum>()
|
? std::make_shared<SendingAlbum>()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
session().api().sendFiles(
|
session().api().sendFiles(
|
||||||
std::move(group.list),
|
std::move(group.list),
|
||||||
type,
|
type,
|
||||||
base::take(caption),
|
base::take(bundle->caption),
|
||||||
album,
|
album,
|
||||||
action);
|
action);
|
||||||
}
|
}
|
||||||
|
@ -1227,7 +1261,20 @@ void RepliesWidget::send() {
|
||||||
send({});
|
send({});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RepliesWidget::sendVoice(ComposeControls::VoiceToSend &&data) {
|
void RepliesWidget::sendVoice(const ComposeControls::VoiceToSend &data) {
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = data;
|
||||||
|
copy.options.starsApproved = approved;
|
||||||
|
sendVoice(copy);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
1,
|
||||||
|
data.options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto action = prepareSendAction(data.options);
|
auto action = prepareSendAction(data.options);
|
||||||
session().api().sendVoiceMessage(
|
session().api().sendVoiceMessage(
|
||||||
data.bytes,
|
data.bytes,
|
||||||
|
@ -1254,19 +1301,32 @@ void RepliesWidget::send(Api::SendOptions options) {
|
||||||
message.textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
message.textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
||||||
message.webPage = _composeControls->webPageDraft();
|
message.webPage = _composeControls->webPageDraft();
|
||||||
|
|
||||||
const auto error = GetErrorForSending(
|
auto request = SendingErrorRequest{
|
||||||
_history->peer,
|
.topicRootId = _topic ? _topic->rootId() : MsgId(0),
|
||||||
{
|
.forward = &_composeControls->forwardItems(),
|
||||||
.topicRootId = _topic ? _topic->rootId() : MsgId(0),
|
.text = &message.textWithTags,
|
||||||
.forward = &_composeControls->forwardItems(),
|
.ignoreSlowmodeCountdown = (options.scheduled != 0),
|
||||||
.text = &message.textWithTags,
|
};
|
||||||
.ignoreSlowmodeCountdown = (options.scheduled != 0),
|
request.messagesCount = ComputeSendingMessagesCount(_history, request);
|
||||||
});
|
const auto error = GetErrorForSending(_history->peer, request);
|
||||||
if (error) {
|
if (error) {
|
||||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!options.scheduled) {
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = options;
|
||||||
|
copy.starsApproved = approved;
|
||||||
|
send(copy);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
request.messagesCount,
|
||||||
|
options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
session().api().sendMessage(std::move(message));
|
session().api().sendMessage(std::move(message));
|
||||||
|
|
||||||
_composeControls->clear();
|
_composeControls->clear();
|
||||||
|
@ -1420,6 +1480,18 @@ bool RepliesWidget::sendExistingDocument(
|
||||||
|| ShowSendPremiumError(controller(), document)) {
|
|| ShowSendPremiumError(controller(), document)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = messageToSend;
|
||||||
|
copy.action.options.starsApproved = approved;
|
||||||
|
sendExistingDocument(document, std::move(copy), localId);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
1,
|
||||||
|
messageToSend.action.options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Api::SendExistingDocument(
|
Api::SendExistingDocument(
|
||||||
std::move(messageToSend),
|
std::move(messageToSend),
|
||||||
|
@ -1448,6 +1520,19 @@ bool RepliesWidget::sendExistingPhoto(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = options;
|
||||||
|
copy.starsApproved = approved;
|
||||||
|
sendExistingPhoto(photo, copy);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
1,
|
||||||
|
options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Api::SendExistingPhoto(
|
Api::SendExistingPhoto(
|
||||||
Api::MessageToSend(prepareSendAction(options)),
|
Api::MessageToSend(prepareSendAction(options)),
|
||||||
photo);
|
photo);
|
||||||
|
@ -1478,6 +1563,19 @@ void RepliesWidget::sendInlineResult(
|
||||||
not_null<UserData*> bot,
|
not_null<UserData*> bot,
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
std::optional<MsgId> localMessageId) {
|
std::optional<MsgId> localMessageId) {
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = options;
|
||||||
|
copy.starsApproved = approved;
|
||||||
|
sendInlineResult(result, bot, copy, localMessageId);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
1,
|
||||||
|
options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto action = prepareSendAction(options);
|
auto action = prepareSendAction(options);
|
||||||
action.generateLocal = true;
|
action.generateLocal = true;
|
||||||
session().api().sendInlineResult(
|
session().api().sendInlineResult(
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "window/section_memento.h"
|
#include "window/section_memento.h"
|
||||||
#include "history/view/history_view_corner_buttons.h"
|
#include "history/view/history_view_corner_buttons.h"
|
||||||
#include "history/view/history_view_list_widget.h"
|
#include "history/view/history_view_list_widget.h"
|
||||||
|
#include "history/history_item_helpers.h"
|
||||||
#include "history/history_view_swipe_data.h"
|
#include "history/history_view_swipe_data.h"
|
||||||
#include "data/data_messages.h"
|
#include "data/data_messages.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
|
@ -38,6 +39,7 @@ class PlainShadow;
|
||||||
class FlatButton;
|
class FlatButton;
|
||||||
class PinnedBar;
|
class PinnedBar;
|
||||||
struct PreparedList;
|
struct PreparedList;
|
||||||
|
struct PreparedBundle;
|
||||||
class SendFilesWay;
|
class SendFilesWay;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
@ -207,6 +209,11 @@ private:
|
||||||
void checkActivation() override;
|
void checkActivation() override;
|
||||||
void doSetInnerFocus() override;
|
void doSetInnerFocus() override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool checkSendPayment(
|
||||||
|
int messagesCount,
|
||||||
|
int starsApproved,
|
||||||
|
Fn<void(int)> withPaymentApproved);
|
||||||
|
|
||||||
void onScroll();
|
void onScroll();
|
||||||
void updateInnerVisibleArea();
|
void updateInnerVisibleArea();
|
||||||
void updateControlsGeometry();
|
void updateControlsGeometry();
|
||||||
|
@ -251,7 +258,7 @@ private:
|
||||||
Api::SendOptions options) const;
|
Api::SendOptions options) const;
|
||||||
void send();
|
void send();
|
||||||
void send(Api::SendOptions options);
|
void send(Api::SendOptions options);
|
||||||
void sendVoice(Controls::VoiceToSend &&data);
|
void sendVoice(const Controls::VoiceToSend &data);
|
||||||
void edit(
|
void edit(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
|
@ -308,6 +315,9 @@ private:
|
||||||
TextWithTags &&caption,
|
TextWithTags &&caption,
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
bool ctrlShiftEnter);
|
bool ctrlShiftEnter);
|
||||||
|
void sendingFilesConfirmed(
|
||||||
|
std::shared_ptr<Ui::PreparedBundle> bundle,
|
||||||
|
Api::SendOptions options);
|
||||||
|
|
||||||
bool sendExistingDocument(
|
bool sendExistingDocument(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
|
@ -380,6 +390,8 @@ private:
|
||||||
|
|
||||||
HistoryView::ChatPaintGestureHorizontalData _gestureHorizontal;
|
HistoryView::ChatPaintGestureHorizontalData _gestureHorizontal;
|
||||||
|
|
||||||
|
SendPaymentHelper _sendPayment;
|
||||||
|
|
||||||
int _lastScrollTop = 0;
|
int _lastScrollTop = 0;
|
||||||
int _topicReopenBarHeight = 0;
|
int _topicReopenBarHeight = 0;
|
||||||
int _scrollTopDelta = 0;
|
int _scrollTopDelta = 0;
|
||||||
|
|
|
@ -15,11 +15,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "boxes/premium_limits_box.h"
|
#include "boxes/premium_limits_box.h"
|
||||||
#include "boxes/send_files_box.h"
|
#include "boxes/send_files_box.h"
|
||||||
|
#include "boxes/share_box.h" // ShareBoxStyleOverrides
|
||||||
#include "chat_helpers/compose/compose_show.h"
|
#include "chat_helpers/compose/compose_show.h"
|
||||||
#include "chat_helpers/tabbed_selector.h"
|
#include "chat_helpers/tabbed_selector.h"
|
||||||
#include "core/file_utilities.h"
|
#include "core/file_utilities.h"
|
||||||
#include "core/mime_type.h"
|
#include "core/mime_type.h"
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
|
#include "data/data_changes.h"
|
||||||
#include "data/data_chat_participant_status.h"
|
#include "data/data_chat_participant_status.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_message_reaction_id.h"
|
#include "data/data_message_reaction_id.h"
|
||||||
|
@ -28,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "history/view/controls/compose_controls_common.h"
|
#include "history/view/controls/compose_controls_common.h"
|
||||||
#include "history/view/controls/history_view_compose_controls.h"
|
#include "history/view/controls/history_view_compose_controls.h"
|
||||||
|
#include "history/view/history_view_schedule_box.h" // ScheduleBoxStyleArgs
|
||||||
#include "history/history_item_helpers.h"
|
#include "history/history_item_helpers.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "inline_bots/inline_bot_result.h"
|
#include "inline_bots/inline_bot_result.h"
|
||||||
|
@ -36,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "media/stories/media_stories_controller.h"
|
#include "media/stories/media_stories_controller.h"
|
||||||
#include "media/stories/media_stories_stealth.h"
|
#include "media/stories/media_stories_stealth.h"
|
||||||
#include "menu/menu_send.h"
|
#include "menu/menu_send.h"
|
||||||
|
#include "settings/settings_credits_graphics.h" // DarkCreditsEntryBoxStyle
|
||||||
#include "storage/localimageloader.h"
|
#include "storage/localimageloader.h"
|
||||||
#include "storage/storage_account.h"
|
#include "storage/storage_account.h"
|
||||||
#include "storage/storage_media_prepare.h"
|
#include "storage/storage_media_prepare.h"
|
||||||
|
@ -52,14 +56,19 @@ namespace {
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<QString> PlaceholderText(
|
[[nodiscard]] rpl::producer<QString> PlaceholderText(
|
||||||
const std::shared_ptr<ChatHelpers::Show> &show,
|
const std::shared_ptr<ChatHelpers::Show> &show,
|
||||||
rpl::producer<bool> isComment) {
|
rpl::producer<bool> isComment,
|
||||||
|
rpl::producer<int> starsPerMessage) {
|
||||||
return rpl::combine(
|
return rpl::combine(
|
||||||
show->session().data().stories().stealthModeValue(),
|
show->session().data().stories().stealthModeValue(),
|
||||||
std::move(isComment)
|
std::move(isComment),
|
||||||
) | rpl::map([](Data::StealthMode value, bool isComment) {
|
std::move(starsPerMessage)
|
||||||
return std::tuple(value.enabledTill, isComment);
|
) | rpl::map([](
|
||||||
|
Data::StealthMode value,
|
||||||
|
bool isComment,
|
||||||
|
int starsPerMessage) {
|
||||||
|
return std::tuple(value.enabledTill, isComment, starsPerMessage);
|
||||||
}) | rpl::distinct_until_changed(
|
}) | rpl::distinct_until_changed(
|
||||||
) | rpl::map([](TimeId till, bool isComment) {
|
) | rpl::map([](TimeId till, bool isComment, int starsPerMessage) {
|
||||||
return rpl::single(
|
return rpl::single(
|
||||||
rpl::empty
|
rpl::empty
|
||||||
) | rpl::then(
|
) | rpl::then(
|
||||||
|
@ -71,7 +80,13 @@ namespace {
|
||||||
}) | rpl::then(
|
}) | rpl::then(
|
||||||
rpl::single(0)
|
rpl::single(0)
|
||||||
) | rpl::map([=](TimeId left) {
|
) | rpl::map([=](TimeId left) {
|
||||||
return left
|
return starsPerMessage
|
||||||
|
? tr::lng_message_paid_ph(
|
||||||
|
lt_amount,
|
||||||
|
tr::lng_prize_credits_amount(
|
||||||
|
lt_count,
|
||||||
|
rpl::single(starsPerMessage * 1.)))
|
||||||
|
: left
|
||||||
? tr::lng_stealth_mode_countdown(
|
? tr::lng_stealth_mode_countdown(
|
||||||
lt_left,
|
lt_left,
|
||||||
rpl::single(TimeLeftText(left)))
|
rpl::single(TimeLeftText(left)))
|
||||||
|
@ -128,7 +143,8 @@ ReplyArea::ReplyArea(not_null<Controller*> controller)
|
||||||
.stickerOrEmojiChosen = _controller->stickerOrEmojiChosen(),
|
.stickerOrEmojiChosen = _controller->stickerOrEmojiChosen(),
|
||||||
.customPlaceholder = PlaceholderText(
|
.customPlaceholder = PlaceholderText(
|
||||||
_controller->uiShow(),
|
_controller->uiShow(),
|
||||||
rpl::deferred([=] { return _isComment.value(); })),
|
rpl::deferred([=] { return _isComment.value(); }),
|
||||||
|
rpl::deferred([=] { return _starsForMessage.value(); })),
|
||||||
.voiceCustomCancelText = tr::lng_record_cancel_stories(tr::now),
|
.voiceCustomCancelText = tr::lng_record_cancel_stories(tr::now),
|
||||||
.voiceLockFromBottom = true,
|
.voiceLockFromBottom = true,
|
||||||
.features = {
|
.features = {
|
||||||
|
@ -199,7 +215,7 @@ bool ReplyArea::sendReaction(const Data::ReactionId &id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !message.textWithTags.empty()
|
return !message.textWithTags.empty()
|
||||||
&& send(std::move(message), {}, true);
|
&& send(std::move(message), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplyArea::send(Api::SendOptions options) {
|
void ReplyArea::send(Api::SendOptions options) {
|
||||||
|
@ -209,29 +225,45 @@ void ReplyArea::send(Api::SendOptions options) {
|
||||||
message.textWithTags = _controls->getTextWithAppliedMarkdown();
|
message.textWithTags = _controls->getTextWithAppliedMarkdown();
|
||||||
message.webPage = webPageDraft;
|
message.webPage = webPageDraft;
|
||||||
|
|
||||||
send(std::move(message), options);
|
send(std::move(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReplyArea::send(
|
bool ReplyArea::send(
|
||||||
Api::MessageToSend message,
|
Api::MessageToSend message,
|
||||||
Api::SendOptions options,
|
|
||||||
bool skipToast) {
|
bool skipToast) {
|
||||||
if (!options.scheduled && showSlowmodeError()) {
|
if (!message.action.options.scheduled && showSlowmodeError()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto error = GetErrorForSending(
|
auto request = SendingErrorRequest{
|
||||||
_data.peer,
|
.topicRootId = MsgId(0),
|
||||||
{
|
.text = &message.textWithTags,
|
||||||
.topicRootId = MsgId(0),
|
.ignoreSlowmodeCountdown = (message.action.options.scheduled != 0),
|
||||||
.text = &message.textWithTags,
|
};
|
||||||
.ignoreSlowmodeCountdown = (options.scheduled != 0),
|
request.messagesCount = ComputeSendingMessagesCount(
|
||||||
});
|
message.action.history,
|
||||||
|
request);
|
||||||
|
const auto error = GetErrorForSending(_data.peer, request);
|
||||||
if (error) {
|
if (error) {
|
||||||
Data::ShowSendErrorToast(_controller->uiShow(), _data.peer, error);
|
Data::ShowSendErrorToast(_controller->uiShow(), _data.peer, error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!message.action.options.scheduled) {
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = message;
|
||||||
|
copy.action.options.starsApproved = approved;
|
||||||
|
send(copy);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
request.messagesCount,
|
||||||
|
message.action.options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
session().api().sendMessage(std::move(message));
|
session().api().sendMessage(std::move(message));
|
||||||
|
|
||||||
finishSending(skipToast);
|
finishSending(skipToast);
|
||||||
|
@ -239,7 +271,40 @@ bool ReplyArea::send(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplyArea::sendVoice(VoiceToSend &&data) {
|
bool ReplyArea::checkSendPayment(
|
||||||
|
int messagesCount,
|
||||||
|
int starsApproved,
|
||||||
|
Fn<void(int)> withPaymentApproved) {
|
||||||
|
const auto st1 = ::Settings::DarkCreditsEntryBoxStyle();
|
||||||
|
const auto st2 = st1.shareBox.get();
|
||||||
|
const auto st3 = st2 ? st2->scheduleBox.get() : nullptr;
|
||||||
|
return _data.peer
|
||||||
|
&& _sendPayment.check(
|
||||||
|
_controller->uiShow(),
|
||||||
|
_data.peer,
|
||||||
|
messagesCount,
|
||||||
|
starsApproved,
|
||||||
|
std::move(withPaymentApproved),
|
||||||
|
{
|
||||||
|
.label = st3 ? st3->chooseDateTimeArgs.labelStyle : nullptr,
|
||||||
|
.checkbox = st2 ? st2->checkbox : nullptr,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplyArea::sendVoice(const VoiceToSend &data) {
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = data;
|
||||||
|
copy.options.starsApproved = approved;
|
||||||
|
sendVoice(copy);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
1,
|
||||||
|
data.options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto action = prepareSendAction(data.options);
|
auto action = prepareSendAction(data.options);
|
||||||
session().api().sendVoiceMessage(
|
session().api().sendVoiceMessage(
|
||||||
data.bytes,
|
data.bytes,
|
||||||
|
@ -269,6 +334,18 @@ bool ReplyArea::sendExistingDocument(
|
||||||
|| Window::ShowSendPremiumError(show, document)) {
|
|| Window::ShowSendPremiumError(show, document)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = messageToSend;
|
||||||
|
copy.action.options.starsApproved = approved;
|
||||||
|
sendExistingDocument(document, std::move(copy), localId);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
1,
|
||||||
|
messageToSend.action.options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Api::SendExistingDocument(std::move(messageToSend), document, localId);
|
Api::SendExistingDocument(std::move(messageToSend), document, localId);
|
||||||
|
|
||||||
|
@ -296,6 +373,18 @@ bool ReplyArea::sendExistingPhoto(
|
||||||
} else if (showSlowmodeError()) {
|
} else if (showSlowmodeError()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = options;
|
||||||
|
copy.starsApproved = approved;
|
||||||
|
sendExistingPhoto(photo, copy);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
1,
|
||||||
|
options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Api::SendExistingPhoto(
|
Api::SendExistingPhoto(
|
||||||
Api::MessageToSend(prepareSendAction(options)),
|
Api::MessageToSend(prepareSendAction(options)),
|
||||||
|
@ -322,6 +411,19 @@ void ReplyArea::sendInlineResult(
|
||||||
not_null<UserData*> bot,
|
not_null<UserData*> bot,
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
std::optional<MsgId> localMessageId) {
|
std::optional<MsgId> localMessageId) {
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = options;
|
||||||
|
copy.starsApproved = approved;
|
||||||
|
sendInlineResult(result, bot, copy, localMessageId);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
1,
|
||||||
|
options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto action = prepareSendAction(options);
|
auto action = prepareSendAction(options);
|
||||||
action.generateLocal = true;
|
action.generateLocal = true;
|
||||||
session().api().sendInlineResult(
|
session().api().sendInlineResult(
|
||||||
|
@ -564,25 +666,47 @@ void ReplyArea::sendingFilesConfirmed(
|
||||||
std::move(list),
|
std::move(list),
|
||||||
way,
|
way,
|
||||||
_data.peer->slowmodeApplied());
|
_data.peer->slowmodeApplied());
|
||||||
const auto type = way.sendImagesAsPhotos()
|
auto bundle = PrepareFilesBundle(
|
||||||
? SendMediaType::Photo
|
std::move(groups),
|
||||||
: SendMediaType::File;
|
way,
|
||||||
|
std::move(caption),
|
||||||
|
ctrlShiftEnter);
|
||||||
|
sendingFilesConfirmed(std::move(bundle), options);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplyArea::sendingFilesConfirmed(
|
||||||
|
std::shared_ptr<Ui::PreparedBundle> bundle,
|
||||||
|
Api::SendOptions options) {
|
||||||
|
const auto withPaymentApproved = [=](int approved) {
|
||||||
|
auto copy = options;
|
||||||
|
copy.starsApproved = approved;
|
||||||
|
sendingFilesConfirmed(bundle, copy);
|
||||||
|
};
|
||||||
|
const auto checked = checkSendPayment(
|
||||||
|
bundle->totalCount,
|
||||||
|
options.starsApproved,
|
||||||
|
withPaymentApproved);
|
||||||
|
if (!checked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto compress = bundle->way.sendImagesAsPhotos();
|
||||||
|
const auto type = compress ? SendMediaType::Photo : SendMediaType::File;
|
||||||
auto action = prepareSendAction(options);
|
auto action = prepareSendAction(options);
|
||||||
action.clearDraft = false;
|
action.clearDraft = false;
|
||||||
if ((groups.size() != 1 || !groups.front().sentWithCaption())
|
if (bundle->sendComment) {
|
||||||
&& !caption.text.isEmpty()) {
|
|
||||||
auto message = Api::MessageToSend(action);
|
auto message = Api::MessageToSend(action);
|
||||||
message.textWithTags = base::take(caption);
|
message.textWithTags = base::take(bundle->caption);
|
||||||
session().api().sendMessage(std::move(message));
|
session().api().sendMessage(std::move(message));
|
||||||
}
|
}
|
||||||
for (auto &group : groups) {
|
for (auto &group : bundle->groups) {
|
||||||
const auto album = (group.type != Ui::AlbumType::None)
|
const auto album = (group.type != Ui::AlbumType::None)
|
||||||
? std::make_shared<SendingAlbum>()
|
? std::make_shared<SendingAlbum>()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
session().api().sendFiles(
|
session().api().sendFiles(
|
||||||
std::move(group.list),
|
std::move(group.list),
|
||||||
type,
|
type,
|
||||||
base::take(caption),
|
base::take(bundle->caption),
|
||||||
album,
|
album,
|
||||||
action);
|
action);
|
||||||
}
|
}
|
||||||
|
@ -618,8 +742,8 @@ void ReplyArea::initActions() {
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
_controls->sendVoiceRequests(
|
_controls->sendVoiceRequests(
|
||||||
) | rpl::start_with_next([=](VoiceToSend &&data) {
|
) | rpl::start_with_next([=](const VoiceToSend &data) {
|
||||||
sendVoice(std::move(data));
|
sendVoice(data);
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
_controls->attachRequests(
|
_controls->attachRequests(
|
||||||
|
@ -697,6 +821,16 @@ void ReplyArea::show(
|
||||||
_controls->clear();
|
_controls->clear();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
} else if (const auto peer = _data.peer) {
|
||||||
|
using Flag = Data::PeerUpdate::Flag;
|
||||||
|
_starsForMessage = peer->session().changes().peerFlagsValue(
|
||||||
|
peer,
|
||||||
|
Flag::StarsPerMessage | Flag::FullInfo
|
||||||
|
) | rpl::map([=] {
|
||||||
|
return peer->starsPerMessageChecked();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
_starsForMessage = 0;
|
||||||
}
|
}
|
||||||
invalidate_weak_ptrs(&_shownPeerGuard);
|
invalidate_weak_ptrs(&_shownPeerGuard);
|
||||||
const auto peer = data.peer;
|
const auto peer = data.peer;
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/weak_ptr.h"
|
#include "base/weak_ptr.h"
|
||||||
|
#include "history/history_item_helpers.h"
|
||||||
|
|
||||||
class History;
|
class History;
|
||||||
enum class SendMediaType;
|
enum class SendMediaType;
|
||||||
|
@ -44,6 +45,7 @@ struct Details;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
struct PreparedList;
|
struct PreparedList;
|
||||||
|
struct PreparedBundle;
|
||||||
class SendFilesWay;
|
class SendFilesWay;
|
||||||
class RpWidget;
|
class RpWidget;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
@ -90,9 +92,13 @@ private:
|
||||||
|
|
||||||
bool send(
|
bool send(
|
||||||
Api::MessageToSend message,
|
Api::MessageToSend message,
|
||||||
Api::SendOptions options,
|
|
||||||
bool skipToast = false);
|
bool skipToast = false);
|
||||||
|
|
||||||
|
[[nodiscard]] bool checkSendPayment(
|
||||||
|
int messagesCount,
|
||||||
|
int starsApproved,
|
||||||
|
Fn<void(int)> withPaymentApproved);
|
||||||
|
|
||||||
void uploadFile(const QByteArray &fileContent, SendMediaType type);
|
void uploadFile(const QByteArray &fileContent, SendMediaType type);
|
||||||
bool confirmSendingFiles(
|
bool confirmSendingFiles(
|
||||||
QImage &&image,
|
QImage &&image,
|
||||||
|
@ -116,6 +122,9 @@ private:
|
||||||
TextWithTags &&caption,
|
TextWithTags &&caption,
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
bool ctrlShiftEnter);
|
bool ctrlShiftEnter);
|
||||||
|
void sendingFilesConfirmed(
|
||||||
|
std::shared_ptr<Ui::PreparedBundle> bundle,
|
||||||
|
Api::SendOptions options);
|
||||||
void finishSending(bool skipToast = false);
|
void finishSending(bool skipToast = false);
|
||||||
|
|
||||||
bool sendExistingDocument(
|
bool sendExistingDocument(
|
||||||
|
@ -141,7 +150,7 @@ private:
|
||||||
[[nodiscard]] Api::SendAction prepareSendAction(
|
[[nodiscard]] Api::SendAction prepareSendAction(
|
||||||
Api::SendOptions options) const;
|
Api::SendOptions options) const;
|
||||||
void send(Api::SendOptions options);
|
void send(Api::SendOptions options);
|
||||||
void sendVoice(VoiceToSend &&data);
|
void sendVoice(const VoiceToSend &data);
|
||||||
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
|
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
|
||||||
|
|
||||||
[[nodiscard]] Fn<SendMenu::Details()> sendMenuDetails() const;
|
[[nodiscard]] Fn<SendMenu::Details()> sendMenuDetails() const;
|
||||||
|
@ -151,6 +160,7 @@ private:
|
||||||
|
|
||||||
const not_null<Controller*> _controller;
|
const not_null<Controller*> _controller;
|
||||||
rpl::variable<bool> _isComment;
|
rpl::variable<bool> _isComment;
|
||||||
|
rpl::variable<int> _starsForMessage;
|
||||||
|
|
||||||
const std::unique_ptr<HistoryView::ComposeControls> _controls;
|
const std::unique_ptr<HistoryView::ComposeControls> _controls;
|
||||||
std::unique_ptr<Cant> _cant;
|
std::unique_ptr<Cant> _cant;
|
||||||
|
@ -160,6 +170,8 @@ private:
|
||||||
bool _chooseAttachRequest = false;
|
bool _chooseAttachRequest = false;
|
||||||
rpl::variable<bool> _choosingAttach;
|
rpl::variable<bool> _choosingAttach;
|
||||||
|
|
||||||
|
SendPaymentHelper _sendPayment;
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -266,6 +266,27 @@ bool PreparedList::hasSpoilerMenu(bool compress) const {
|
||||||
return allAreVideo || (allAreMedia && compress);
|
return allAreVideo || (allAreMedia && compress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<PreparedBundle> PrepareFilesBundle(
|
||||||
|
std::vector<PreparedGroup> groups,
|
||||||
|
SendFilesWay way,
|
||||||
|
TextWithTags caption,
|
||||||
|
bool ctrlShiftEnter) {
|
||||||
|
auto totalCount = 0;
|
||||||
|
for (const auto &group : groups) {
|
||||||
|
totalCount += group.list.files.size();
|
||||||
|
}
|
||||||
|
const auto sendComment = !caption.text.isEmpty()
|
||||||
|
&& (groups.size() != 1 || !groups.front().sentWithCaption());
|
||||||
|
return std::make_shared<PreparedBundle>(PreparedBundle{
|
||||||
|
.groups = std::move(groups),
|
||||||
|
.way = way,
|
||||||
|
.caption = std::move(caption),
|
||||||
|
.totalCount = totalCount + (sendComment ? 1 : 0),
|
||||||
|
.sendComment = sendComment,
|
||||||
|
.ctrlShiftEnter = ctrlShiftEnter,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
int MaxAlbumItems() {
|
int MaxAlbumItems() {
|
||||||
return kMaxAlbumCount;
|
return kMaxAlbumCount;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "editor/photo_editor_common.h"
|
#include "editor/photo_editor_common.h"
|
||||||
|
#include "ui/chat/attach/attach_send_files_way.h"
|
||||||
#include "ui/rect_part.h"
|
#include "ui/rect_part.h"
|
||||||
|
|
||||||
#include <QtCore/QSemaphore>
|
#include <QtCore/QSemaphore>
|
||||||
|
@ -153,6 +154,20 @@ struct PreparedGroup {
|
||||||
SendFilesWay way,
|
SendFilesWay way,
|
||||||
bool slowmode);
|
bool slowmode);
|
||||||
|
|
||||||
|
struct PreparedBundle {
|
||||||
|
std::vector<PreparedGroup> groups;
|
||||||
|
SendFilesWay way;
|
||||||
|
TextWithTags caption;
|
||||||
|
int totalCount = 0;
|
||||||
|
bool sendComment = false;
|
||||||
|
bool ctrlShiftEnter = false;
|
||||||
|
};
|
||||||
|
[[nodiscard]] std::shared_ptr<PreparedBundle> PrepareFilesBundle(
|
||||||
|
std::vector<PreparedGroup> groups,
|
||||||
|
SendFilesWay way,
|
||||||
|
TextWithTags caption,
|
||||||
|
bool ctrlShiftEnter);
|
||||||
|
|
||||||
[[nodiscard]] int MaxAlbumItems();
|
[[nodiscard]] int MaxAlbumItems();
|
||||||
[[nodiscard]] bool ValidateThumbDimensions(int width, int height);
|
[[nodiscard]] bool ValidateThumbDimensions(int width, int height);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue