Support slowmode restrictions in Replies section.

This commit is contained in:
John Preston 2020-09-30 14:06:08 +03:00
parent 719bed6e85
commit 94c2969f8b
11 changed files with 174 additions and 27 deletions

View file

@ -836,6 +836,31 @@ bool PeerData::slowmodeApplied() const {
return false;
}
rpl::producer<bool> PeerData::slowmodeAppliedValue() const {
using namespace rpl::mappers;
const auto channel = asChannel();
if (!channel) {
return rpl::single(false);
}
auto hasAdminRights = channel->adminRightsValue(
) | rpl::map([=] {
return channel->hasAdminRights();
}) | rpl::distinct_until_changed();
auto slowmodeEnabled = channel->flagsValue(
) | rpl::filter([=](const ChannelData::Flags::Change &change) {
return (change.diff & MTPDchannel::Flag::f_slowmode_enabled) != 0;
}) | rpl::map([=](const ChannelData::Flags::Change &change) {
return (change.value & MTPDchannel::Flag::f_slowmode_enabled) != 0;
}) | rpl::distinct_until_changed();
return rpl::combine(
std::move(hasAdminRights),
std::move(slowmodeEnabled),
!_1 && _2);
}
int PeerData::slowmodeSecondsLeft() const {
if (const auto channel = asChannel()) {
if (const auto seconds = channel->slowmodeSeconds()) {

View file

@ -199,6 +199,7 @@ public:
[[nodiscard]] bool amAnonymous() const;
[[nodiscard]] bool canRevokeFullHistory() const;
[[nodiscard]] bool slowmodeApplied() const;
[[nodiscard]] rpl::producer<bool> slowmodeAppliedValue() const;
[[nodiscard]] int slowmodeSecondsLeft() const;
[[nodiscard]] bool canSendPolls() const;

View file

@ -3675,15 +3675,18 @@ void HistoryWidget::updateSendButtonType() {
const auto type = computeSendButtonType();
_send->setType(type);
// This logic is duplicated in RepliesWidget.
const auto disabledBySlowmode = _peer
&& _peer->slowmodeApplied()
&& (_history->latestSendingMessage() != nullptr);
const auto delay = [&] {
return (type != Type::Cancel && type != Type::Save && _peer)
? _peer->slowmodeSecondsLeft()
: 0;
}();
_send->setSlowmodeDelay(delay);
_send->setDisabled(_peer
&& _peer->slowmodeApplied()
&& (_history->latestSendingMessage() != nullptr)
_send->setDisabled(disabledBySlowmode
&& (type == Type::Send || type == Type::Record));
if (delay != 0) {

View file

@ -528,7 +528,13 @@ Main::Session &ComposeControls::session() const {
return _window->session();
}
void ComposeControls::setHistory(History *history) {
void ComposeControls::setHistory(SetHistoryArgs &&args) {
_showSlowmodeError = std::move(args.showSlowmodeError);
_slowmodeSecondsLeft = rpl::single(0)
| rpl::then(std::move(args.slowmodeSecondsLeft));
_sendDisabledBySlowmode = rpl::single(false)
| rpl::then(std::move(args.sendDisabledBySlowmode));
const auto history = *args.history;
if (_history == history) {
return;
}
@ -878,8 +884,8 @@ void ComposeControls::recordStartCallback() {
if (error) {
Ui::show(Box<InformBox>(*error));
return;
//} else if (showSlowmodeError()) { // #TODO slowmode
// return;
} else if (_showSlowmodeError && _showSlowmodeError()) {
return;
} else if (!::Media::Capture::instance()->available()) {
return;
}
@ -1034,7 +1040,13 @@ void ComposeControls::initTabbedSelector() {
}
void ComposeControls::initSendButton() {
updateSendButtonType();
rpl::combine(
_slowmodeSecondsLeft.value(),
_sendDisabledBySlowmode.value()
) | rpl::start_with_next([=] {
updateSendButtonType();
}, _send->lifetime());
_send->finishAnimating();
}
@ -1053,22 +1065,13 @@ void ComposeControls::updateSendButtonType() {
_send->setType(type);
const auto delay = [&] {
return /*(type != Type::Cancel && type != Type::Save && _peer)
? _peer->slowmodeSecondsLeft()
: */0;
return (type != Type::Cancel && type != Type::Save)
? _slowmodeSecondsLeft.current()
: 0;
}();
_send->setSlowmodeDelay(delay);
//_send->setDisabled(_peer
// && _peer->slowmodeApplied()
// && (_history->latestSendingMessage() != nullptr)
// && (type == Type::Send || type == Type::Record));
//if (delay != 0) {
// base::call_delayed(
// kRefreshSlowmodeLabelTimeout,
// this,
// [=] { updateSendButtonType(); });
//}
_send->setDisabled(_sendDisabledBySlowmode.current()
&& (type == Type::Send || type == Type::Record));
_send->setRecordStartCallback([=] { recordStartCallback(); });
_send->setRecordStopCallback([=](bool active) { recordStopCallback(active); });
@ -1076,6 +1079,11 @@ void ComposeControls::updateSendButtonType() {
_send->setRecordAnimationCallback([=] { _wrap->update(); });
}
void ComposeControls::finishAnimating() {
_send->finishAnimating();
_recordingAnimation.stop();
}
void ComposeControls::updateControlsGeometry(QSize size) {
// _attachToggle -- _inlineResults ------ _tabbedPanel -- _fieldBarCancel
// (_attachDocument|_attachPhoto) _field _tabbedSelectorToggle _send

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/required.h"
#include "api/api_common.h"
#include "base/unique_qptr.h"
#include "ui/rp_widget.h"
@ -88,7 +89,14 @@ public:
[[nodiscard]] Main::Session &session() const;
void setHistory(History *history);
struct SetHistoryArgs {
required<History*> history;
Fn<bool()> showSlowmodeError;
rpl::producer<int> slowmodeSecondsLeft;
rpl::producer<bool> sendDisabledBySlowmode;
};
void setHistory(SetHistoryArgs &&args);
void finishAnimating();
void move(int x, int y);
void resizeToWidth(int width);
@ -184,6 +192,9 @@ private:
const not_null<QWidget*> _parent;
const not_null<Window::SessionController*> _window;
History *_history = nullptr;
Fn<bool()> _showSlowmodeError;
rpl::variable<int> _slowmodeSecondsLeft;
rpl::variable<bool> _sendDisabledBySlowmode;
Mode _mode = Mode::Normal;
const std::unique_ptr<Ui::RpWidget> _wrap;

View file

@ -746,6 +746,8 @@ void Message::paintCommentsButton(
QImage::Format_ARGB32_Premultiplied);
}
_comments->cachedUserpics.fill(Qt::transparent);
_comments->cachedUserpics.setDevicePixelRatio(cRetinaFactor());
auto q = Painter(&_comments->cachedUserpics);
auto hq = PainterHighQualityEnabler(q);
auto pen = QPen(Qt::transparent);

View file

@ -22,9 +22,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/layers/generic_box.h"
#include "ui/text_options.h"
#include "ui/toast/toast.h"
#include "ui/text/format_values.h"
#include "ui/special_buttons.h"
#include "ui/ui_utility.h"
#include "ui/toasts/common_toasts.h"
#include "base/timer_rpl.h"
#include "api/api_common.h"
#include "api/api_editing.h"
#include "api/api_sending.h"
@ -62,6 +64,7 @@ namespace HistoryView {
namespace {
constexpr auto kReadRequestTimeout = 3 * crl::time(1000);
constexpr auto kRefreshSlowmodeLabelTimeout = crl::time(200);
bool CanSendFiles(not_null<const QMimeData*> data) {
if (data->hasImage()) {
@ -135,6 +138,8 @@ RepliesWidget::RepliesWidget(
setupRoot();
setupRootView();
session().api().requestFullPeer(_history->peer);
_topBar->setActiveChat(
_history,
TopBarWidget::Section::Replies,
@ -396,7 +401,51 @@ bool RepliesWidget::computeAreComments() const {
}
void RepliesWidget::setupComposeControls() {
_composeControls->setHistory(_history);
auto slowmodeSecondsLeft = session().changes().peerFlagsValue(
_history->peer,
Data::PeerUpdate::Flag::Slowmode
) | rpl::map([=] {
return _history->peer->slowmodeSecondsLeft();
}) | rpl::map([=](int delay) -> rpl::producer<int> {
auto start = rpl::single(delay);
if (!delay) {
return start;
}
return std::move(
start
) | rpl::then(base::timer_each(
kRefreshSlowmodeLabelTimeout
) | rpl::map([=] {
return _history->peer->slowmodeSecondsLeft();
}) | rpl::take_while([=](int delay) {
return delay > 0;
})) | rpl::then(rpl::single(0));
}) | rpl::flatten_latest();
const auto channel = _history->peer->asChannel();
Assert(channel != nullptr);
auto hasSendingMessage = session().changes().historyFlagsValue(
_history,
Data::HistoryUpdate::Flag::LocalMessages
) | rpl::map([=] {
return _history->latestSendingMessage() != nullptr;
}) | rpl::distinct_until_changed();
using namespace rpl::mappers;
auto sendDisabledBySlowmode = (!channel || channel->amCreator())
? (rpl::single(false) | rpl::type_erased())
: rpl::combine(
channel->slowmodeAppliedValue(),
std::move(hasSendingMessage),
_1 && _2);
_composeControls->setHistory({
.history = _history.get(),
.showSlowmodeError = [=] { return showSlowmodeError(); },
.slowmodeSecondsLeft = std::move(slowmodeSecondsLeft),
.sendDisabledBySlowmode = std::move(sendDisabledBySlowmode),
});
_composeControls->height(
) | rpl::start_with_next([=] {
@ -497,6 +546,8 @@ void RepliesWidget::setupComposeControls() {
}
Unexpected("action in MimeData hook.");
});
_composeControls->finishAnimating();
}
void RepliesWidget::chooseAttach() {
@ -507,6 +558,8 @@ void RepliesWidget::chooseAttach() {
.text = { *error },
});
return;
} else if (showSlowmodeError()) {
return;
}
const auto filter = FileDialog::AllFilesFilter()
@ -684,6 +737,30 @@ bool RepliesWidget::confirmSendingFiles(
insertTextOnCancel);
}
bool RepliesWidget::showSlowmodeError() {
const auto text = [&] {
if (const auto left = _history->peer->slowmodeSecondsLeft()) {
return tr::lng_slowmode_enabled(
tr::now,
lt_left,
Ui::FormatDurationWords(left));
} else if (_history->peer->slowmodeApplied()) {
if (const auto item = _history->latestSendingMessage()) {
showAtPositionNow(item->position(), nullptr);
return tr::lng_slowmode_no_many(tr::now);
}
}
return QString();
}();
if (text.isEmpty()) {
return false;
}
Ui::ShowMultilineToast({
.text = { text },
});
return true;
}
void RepliesWidget::uploadFilesAfterConfirmation(
Storage::PreparedList &&list,
SendMediaType type,
@ -783,6 +860,16 @@ bool RepliesWidget::showSendingFilesError(
if (error) {
return *error;
}
if (list.files.size() > 1
&& _history->peer->slowmodeApplied()
&& !list.albumIsPossible) {
return tr::lng_slowmode_no_many(tr::now);
} else if (const auto left = _history->peer->slowmodeSecondsLeft()) {
return tr::lng_slowmode_enabled(
tr::now,
lt_left,
Ui::FormatDurationWords(left));
}
using Error = Storage::PreparedList::Error;
switch (list.error) {
case Error::None: return QString();
@ -831,6 +918,10 @@ void RepliesWidget::sendVoice(
}
void RepliesWidget::send(Api::SendOptions options) {
if (!options.scheduled && showSlowmodeError()) {
return;
}
const auto webPageId = _composeControls->webPageId();/* _previewCancelled
? CancelledWebPageId
: ((_previewData && _previewData->pendingTill >= 0)
@ -964,6 +1055,8 @@ bool RepliesWidget::sendExistingDocument(
if (error) {
Ui::show(Box<InformBox>(*error), Ui::LayerOption::KeepOther);
return false;
} else if (showSlowmodeError()) {
return false;
}
auto message = Api::MessageToSend(_history);
@ -1004,6 +1097,8 @@ bool RepliesWidget::sendExistingPhoto(
if (error) {
Ui::show(Box<InformBox>(*error), Ui::LayerOption::KeepOther);
return false;
} else if (showSlowmodeError()) {
return false;
}
auto message = Api::MessageToSend(_history);

View file

@ -152,7 +152,7 @@ ScheduledWidget::ScheduledWidget(
ScheduledWidget::~ScheduledWidget() = default;
void ScheduledWidget::setupComposeControls() {
_composeControls->setHistory(_history);
_composeControls->setHistory({ .history = _history });
_composeControls->height(
) | rpl::start_with_next([=] {

View file

@ -234,7 +234,6 @@ void SessionNavigation::showPeerByLinkResolved(
showPeerHistory(peer->id, params, msgId);
});
}
}
void SessionNavigation::showRepliesForMessage(
@ -246,6 +245,9 @@ void SessionNavigation::showRepliesForMessage(
&& _showingRepliesHistory == history.get()
&& _showingRepliesRootId == rootId) {
return;
} else if (!history->peer->asChannel()) {
// HistoryView::RepliesWidget right now handles only channels.
return;
}
_session->api().request(base::take(_showingRepliesRequestId)).cancel();

@ -1 +1 @@
Subproject commit c28f55ab25c9ee7aee7e960c6a4127b008742bdd
Subproject commit 4f03dbd9a0c3dce0268fa208bf1e3ffff4c95c72

@ -1 +1 @@
Subproject commit e654c5ee98199b47a426aaaf6a1f7331aca0ebcd
Subproject commit 86b9b80fae7a41e7c6ad85f14659883533ab84e8