Allow to send scheduled messages instantly.

This commit is contained in:
John Preston 2019-08-09 18:58:58 +01:00
parent 956bb876f6
commit 694f771131
17 changed files with 256 additions and 51 deletions

View File

@ -1388,6 +1388,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_reply_msg" = "Reply"; "lng_context_reply_msg" = "Reply";
"lng_context_edit_msg" = "Edit"; "lng_context_edit_msg" = "Edit";
"lng_context_forward_msg" = "Forward Message"; "lng_context_forward_msg" = "Forward Message";
"lng_context_send_now_msg" = "Send now";
"lng_context_delete_msg" = "Delete Message"; "lng_context_delete_msg" = "Delete Message";
"lng_context_select_msg" = "Select Message"; "lng_context_select_msg" = "Select Message";
"lng_context_report_msg" = "Report Message"; "lng_context_report_msg" = "Report Message";
@ -1397,6 +1398,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_copy_selected" = "Copy Selected Text"; "lng_context_copy_selected" = "Copy Selected Text";
"lng_context_copy_selected_items" = "Copy Selected as Text"; "lng_context_copy_selected_items" = "Copy Selected as Text";
"lng_context_forward_selected" = "Forward Selected"; "lng_context_forward_selected" = "Forward Selected";
"lng_context_send_now_selected" = "Send selected now";
"lng_context_delete_selected" = "Delete Selected"; "lng_context_delete_selected" = "Delete Selected";
"lng_context_clear_selection" = "Clear Selection"; "lng_context_clear_selection" = "Clear Selection";
"lng_send_image_empty" = "Could not send an empty file: {name}"; "lng_send_image_empty" = "Could not send an empty file: {name}";
@ -1474,6 +1476,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_selected_clear" = "Cancel"; "lng_selected_clear" = "Cancel";
"lng_selected_delete" = "Delete"; "lng_selected_delete" = "Delete";
"lng_selected_forward" = "Forward"; "lng_selected_forward" = "Forward";
"lng_selected_send_now" = "Send now";
"lng_selected_cancel_sure_this" = "Cancel uploading?"; "lng_selected_cancel_sure_this" = "Cancel uploading?";
"lng_selected_upload_stop" = "Stop"; "lng_selected_upload_stop" = "Stop";
"lng_selected_delete_sure_this" = "Do you want to delete this message?"; "lng_selected_delete_sure_this" = "Do you want to delete this message?";

View File

@ -9,24 +9,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Api { namespace Api {
uint32 HashInit() { [[nodiscard]] inline uint32 HashInit() {
return 0; return 0;
} }
template < inline void HashUpdate(uint32 &already, uint32 value) {
typename Int, already = (already * 20261) + uint32(value);
typename = std::enable_if_t<
std::is_same_v<Int, int32> || std::is_same_v<Int, uint32>>>
void HashUpdate(uint32 &already, Int value) {
already += (already * 20261) + uint32(value);
} }
int32 HashFinalize(uint32 already) { inline void HashUpdate(uint32 &already, int32 value) {
HashUpdate(already, uint32(value));
}
inline void HashUpdate(uint32 &already, uint64 value) {
HashUpdate(already, uint32(value >> 32));
HashUpdate(already, uint32(value & 0xFFFFFFFFULL));
}
[[nodiscard]] inline int32 HashFinalize(uint32 already) {
return int32(already & 0x7FFFFFFF); return int32(already & 0x7FFFFFFF);
} }
template <typename IntRange> template <typename IntRange>
inline int32 CountHash(IntRange &&range) { [[nodiscard]] inline int32 CountHash(IntRange &&range) {
auto result = HashInit(); auto result = HashInit();
for (const auto value : range) { for (const auto value : range) {
HashUpdate(result, value); HashUpdate(result, value);

View File

@ -78,13 +78,14 @@ ScheduledMessages::~ScheduledMessages() {
} }
MsgId ScheduledMessages::lookupId(not_null<HistoryItem*> item) const { MsgId ScheduledMessages::lookupId(not_null<HistoryItem*> item) const {
if (const auto i = _data.find(item->history()); i != end(_data)) { Expects(item->isScheduled());
const auto &list = i->second.idByItem;
if (const auto j = list.find(item); j != end(list)) { const auto i = _data.find(item->history());
return j->second; Assert(i != end(_data));
} const auto &list = i->second;
} const auto j = list.idByItem.find(item);
return MsgId(0); Assert(j != end(list.idByItem));
return j->second;
} }
int ScheduledMessages::count(not_null<History*> history) const { int ScheduledMessages::count(not_null<History*> history) const {

View File

@ -475,6 +475,10 @@ bool HistoryItem::canPin() const {
return _history->peer->canPinMessages(); return _history->peer->canPinMessages();
} }
bool HistoryItem::allowsSendNow() const {
return false;
}
bool HistoryItem::allowsForward() const { bool HistoryItem::allowsForward() const {
return false; return false;
} }

View File

@ -266,6 +266,7 @@ public:
bool isPinned() const; bool isPinned() const;
bool canPin() const; bool canPin() const;
bool canStopPoll() const; bool canStopPoll() const;
virtual bool allowsSendNow() const;
virtual bool allowsForward() const; virtual bool allowsForward() const;
virtual bool allowsEdit(TimeId now) const; virtual bool allowsEdit(TimeId now) const;
bool canDelete() const; bool canDelete() const;

View File

@ -742,6 +742,10 @@ bool HistoryMessage::allowsForward() const {
return !_media || _media->allowsForward(); return !_media || _media->allowsForward();
} }
bool HistoryMessage::allowsSendNow() const {
return isScheduled();
}
bool HistoryMessage::isTooOldForEdit(TimeId now) const { bool HistoryMessage::isTooOldForEdit(TimeId now) const {
const auto peer = _history->peer; const auto peer = _history->peer;
if (peer->isSelf()) { if (peer->isSelf()) {

View File

@ -108,6 +108,7 @@ public:
const MTPMessageMedia &media); const MTPMessageMedia &media);
[[nodiscard]] bool allowsForward() const override; [[nodiscard]] bool allowsForward() const override;
[[nodiscard]] bool allowsSendNow() const override;
[[nodiscard]] bool allowsEdit(TimeId now) const override; [[nodiscard]] bool allowsEdit(TimeId now) const override;
[[nodiscard]] bool uploading() const; [[nodiscard]] bool uploading() const;

View File

@ -291,6 +291,95 @@ void AddForwardAction(
AddForwardMessageAction(menu, request, list); AddForwardMessageAction(menu, request, list);
} }
bool AddSendNowSelectedAction(
not_null<Ui::PopupMenu*> menu,
const ContextMenuRequest &request,
not_null<ListWidget*> list) {
if (!request.overSelection || request.selectedItems.empty()) {
return false;
}
if (ranges::find_if(request.selectedItems, [](const auto &item) {
return !item.canSendNow;
}) != end(request.selectedItems)) {
return false;
}
const auto session = &request.navigation->session();
auto histories = ranges::view::all(
request.selectedItems
) | ranges::view::transform([&](const SelectedItem &item) {
return session->data().message(item.msgId);
}) | ranges::view::filter([](HistoryItem *item) {
return item != nullptr;
}) | ranges::view::transform([](not_null<HistoryItem*> item) {
return item->history();
});
if (histories.begin() == histories.end()) {
return false;
}
const auto history = *histories.begin();
menu->addAction(tr::lng_context_send_now_selected(tr::now), [=] {
const auto weak = make_weak(list);
const auto callback = [=] {
request.navigation->showBackFromStack();
};
Window::ShowSendNowMessagesBox(
request.navigation,
history,
ExtractIdsList(request.selectedItems),
callback);
});
return true;
}
bool AddSendNowMessageAction(
not_null<Ui::PopupMenu*> menu,
const ContextMenuRequest &request,
not_null<ListWidget*> list) {
const auto item = request.item;
if (!request.selectedItems.empty()) {
return false;
} else if (!item || !item->allowsSendNow()) {
return false;
}
const auto owner = &item->history()->owner();
const auto asGroup = (request.pointState != PointState::GroupPart);
if (asGroup) {
if (const auto group = owner->groups().find(item)) {
if (ranges::find_if(group->items, [](auto item) {
return !item->allowsSendNow();
}) != end(group->items)) {
return false;
}
}
}
const auto itemId = item->fullId();
menu->addAction(tr::lng_context_send_now_msg(tr::now), [=] {
if (const auto item = owner->message(itemId)) {
const auto callback = [=] {
request.navigation->showBackFromStack();
};
Window::ShowSendNowMessagesBox(
request.navigation,
item->history(),
(asGroup
? owner->itemOrItsGroup(item)
: MessageIdsList{ 1, itemId }),
callback);
}
});
return true;
}
void AddSendNowAction(
not_null<Ui::PopupMenu*> menu,
const ContextMenuRequest &request,
not_null<ListWidget*> list) {
AddSendNowSelectedAction(menu, request, list);
AddSendNowMessageAction(menu, request, list);
}
bool AddDeleteSelectedAction( bool AddDeleteSelectedAction(
not_null<Ui::PopupMenu*> menu, not_null<Ui::PopupMenu*> menu,
const ContextMenuRequest &request, const ContextMenuRequest &request,
@ -426,6 +515,7 @@ void AddMessageActions(
not_null<ListWidget*> list) { not_null<ListWidget*> list) {
AddPostLinkAction(menu, request); AddPostLinkAction(menu, request);
AddForwardAction(menu, request, list); AddForwardAction(menu, request, list);
AddSendNowAction(menu, request, list);
AddDeleteAction(menu, request, list); AddDeleteAction(menu, request, list);
AddSelectionAction(menu, request, list); AddSelectionAction(menu, request, list);
} }

View File

@ -669,6 +669,7 @@ auto ListWidget::collectSelectedItems() const -> SelectedItems {
auto result = SelectedItem(itemId); auto result = SelectedItem(itemId);
result.canDelete = selection.canDelete; result.canDelete = selection.canDelete;
result.canForward = selection.canForward; result.canForward = selection.canForward;
result.canSendNow = selection.canSendNow;
return result; return result;
}; };
auto items = SelectedItems(); auto items = SelectedItems();
@ -770,6 +771,7 @@ bool ListWidget::addToSelection(
} }
iterator->second.canDelete = item->canDelete(); iterator->second.canDelete = item->canDelete();
iterator->second.canForward = item->allowsForward(); iterator->second.canForward = item->allowsForward();
iterator->second.canSendNow = item->allowsSendNow();
return true; return true;
} }

View File

@ -46,6 +46,7 @@ struct SelectedItem {
FullMsgId msgId; FullMsgId msgId;
bool canDelete = false; bool canDelete = false;
bool canForward = false; bool canForward = false;
bool canSendNow = false;
}; };
@ -78,6 +79,7 @@ public:
struct SelectionData { struct SelectionData {
bool canDelete = false; bool canDelete = false;
bool canForward = false; bool canForward = false;
bool canSendNow = false;
}; };

View File

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/special_buttons.h" #include "ui/special_buttons.h"
#include "boxes/confirm_box.h" #include "boxes/confirm_box.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "window/window_peer_menu.h"
#include "core/event_filter.h" #include "core/event_filter.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "data/data_session.h" #include "data/data_session.h"
@ -56,6 +57,10 @@ ScheduledWidget::ScheduledWidget(
_topBar->resizeToWidth(width()); _topBar->resizeToWidth(width());
_topBar->show(); _topBar->show();
_topBar->sendNowSelectionRequest(
) | rpl::start_with_next([=] {
confirmSendNowSelected();
}, _topBar->lifetime());
_topBar->deleteSelectionRequest( _topBar->deleteSelectionRequest(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
confirmDeleteSelected(); confirmDeleteSelected();
@ -386,12 +391,12 @@ void ScheduledWidget::listSelectionChanged(SelectedItems &&items) {
HistoryView::TopBarWidget::SelectedState state; HistoryView::TopBarWidget::SelectedState state;
state.count = items.size(); state.count = items.size();
for (const auto item : items) { for (const auto item : items) {
if (item.canForward) {
++state.canForwardCount;
}
if (item.canDelete) { if (item.canDelete) {
++state.canDeleteCount; ++state.canDeleteCount;
} }
if (item.canSendNow) {
++state.canSendNowCount;
}
} }
_topBar->showSelected(state); _topBar->showSelected(state);
} }
@ -411,6 +416,19 @@ ClickHandlerPtr ScheduledWidget::listDateLink(not_null<Element*> view) {
return nullptr; return nullptr;
} }
void ScheduledWidget::confirmSendNowSelected() {
auto items = _inner->getSelectedItems();
if (items.empty()) {
return;
}
const auto navigation = controller();
Window::ShowSendNowMessagesBox(
navigation,
_history,
std::move(items),
[=] { navigation->showBackFromStack(); });
}
void ScheduledWidget::confirmDeleteSelected() { void ScheduledWidget::confirmDeleteSelected() {
auto items = _inner->getSelectedItems(); auto items = _inner->getSelectedItems();
if (items.empty()) { if (items.empty()) {

View File

@ -112,6 +112,7 @@ private:
void updateScrollDownVisibility(); void updateScrollDownVisibility();
void updateScrollDownPosition(); void updateScrollDownPosition();
void confirmSendNowSelected();
void confirmDeleteSelected(); void confirmDeleteSelected();
void clearSelected(); void clearSelected();

View File

@ -52,6 +52,7 @@ TopBarWidget::TopBarWidget(
, _controller(controller) , _controller(controller)
, _clear(this, tr::lng_selected_clear(), st::topBarClearButton) , _clear(this, tr::lng_selected_clear(), st::topBarClearButton)
, _forward(this, tr::lng_selected_forward(), st::defaultActiveButton) , _forward(this, tr::lng_selected_forward(), st::defaultActiveButton)
, _sendNow(this, tr::lng_selected_send_now(), st::defaultActiveButton)
, _delete(this, tr::lng_selected_delete(), st::defaultActiveButton) , _delete(this, tr::lng_selected_delete(), st::defaultActiveButton)
, _back(this, st::historyTopBarBack) , _back(this, st::historyTopBarBack)
, _call(this, st::topBarCall) , _call(this, st::topBarCall)
@ -60,19 +61,21 @@ TopBarWidget::TopBarWidget(
, _menuToggle(this, st::topBarMenuToggle) , _menuToggle(this, st::topBarMenuToggle)
, _titlePeerText(st::windowMinWidth / 3) , _titlePeerText(st::windowMinWidth / 3)
, _onlineUpdater([=] { updateOnlineDisplay(); }) { , _onlineUpdater([=] { updateOnlineDisplay(); }) {
subscribe(Lang::Current().updated(), [this] { refreshLang(); }); subscribe(Lang::Current().updated(), [=] { refreshLang(); });
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
_forward->setClickedCallback([this] { _forwardSelection.fire({}); }); _forward->setClickedCallback([=] { _forwardSelection.fire({}); });
_forward->setWidthChangedCallback([this] { updateControlsGeometry(); }); _forward->setWidthChangedCallback([=] { updateControlsGeometry(); });
_delete->setClickedCallback([this] { _deleteSelection.fire({}); }); _sendNow->setClickedCallback([=] { _sendNowSelection.fire({}); });
_delete->setWidthChangedCallback([this] { updateControlsGeometry(); }); _sendNow->setWidthChangedCallback([=] { updateControlsGeometry(); });
_clear->setClickedCallback([this] { _clearSelection.fire({}); }); _delete->setClickedCallback([=] { _deleteSelection.fire({}); });
_call->setClickedCallback([this] { onCall(); }); _delete->setWidthChangedCallback([=] { updateControlsGeometry(); });
_search->setClickedCallback([this] { onSearch(); }); _clear->setClickedCallback([=] { _clearSelection.fire({}); });
_menuToggle->setClickedCallback([this] { showMenu(); }); _call->setClickedCallback([=] { onCall(); });
_infoToggle->setClickedCallback([this] { toggleInfoSection(); }); _search->setClickedCallback([=] { onSearch(); });
_back->addClickHandler([this] { backClicked(); }); _menuToggle->setClickedCallback([=] { showMenu(); });
_infoToggle->setClickedCallback([=] { toggleInfoSection(); });
_back->addClickHandler([=] { backClicked(); });
rpl::combine( rpl::combine(
_controller->activeChatValue(), _controller->activeChatValue(),
@ -522,12 +525,16 @@ void TopBarWidget::updateControlsGeometry() {
auto selectedButtonsTop = countSelectedButtonsTop(_selectedShown.value(hasSelected ? 1. : 0.)); auto selectedButtonsTop = countSelectedButtonsTop(_selectedShown.value(hasSelected ? 1. : 0.));
auto otherButtonsTop = selectedButtonsTop + st::topBarHeight; auto otherButtonsTop = selectedButtonsTop + st::topBarHeight;
auto buttonsLeft = st::topBarActionSkip + (Adaptive::OneColumn() ? 0 : st::lineWidth); auto buttonsLeft = st::topBarActionSkip + (Adaptive::OneColumn() ? 0 : st::lineWidth);
auto buttonsWidth = _forward->contentWidth() + _delete->contentWidth() + _clear->width(); auto buttonsWidth = (_forward->isHidden() ? 0 : _forward->contentWidth())
+ (_sendNow->isHidden() ? 0 : _sendNow->contentWidth())
+ (_delete->isHidden() ? 0 : _delete->contentWidth())
+ _clear->width();
buttonsWidth += buttonsLeft + st::topBarActionSkip * 3; buttonsWidth += buttonsLeft + st::topBarActionSkip * 3;
auto widthLeft = qMin(width() - buttonsWidth, -2 * st::defaultActiveButton.width); auto widthLeft = qMin(width() - buttonsWidth, -2 * st::defaultActiveButton.width);
auto buttonFullWidth = qMin(-(widthLeft / 2), 0); auto buttonFullWidth = qMin(-(widthLeft / 2), 0);
_forward->setFullWidth(buttonFullWidth); _forward->setFullWidth(buttonFullWidth);
_sendNow->setFullWidth(buttonFullWidth);
_delete->setFullWidth(buttonFullWidth); _delete->setFullWidth(buttonFullWidth);
selectedButtonsTop += (height() - _forward->height()) / 2; selectedButtonsTop += (height() - _forward->height()) / 2;
@ -537,6 +544,11 @@ void TopBarWidget::updateControlsGeometry() {
buttonsLeft += _forward->width() + st::topBarActionSkip; buttonsLeft += _forward->width() + st::topBarActionSkip;
} }
_sendNow->moveToLeft(buttonsLeft, selectedButtonsTop);
if (!_sendNow->isHidden()) {
buttonsLeft += _sendNow->width() + st::topBarActionSkip;
}
_delete->moveToLeft(buttonsLeft, selectedButtonsTop); _delete->moveToLeft(buttonsLeft, selectedButtonsTop);
_clear->moveToRight(st::topBarActionSkip, selectedButtonsTop); _clear->moveToRight(st::topBarActionSkip, selectedButtonsTop);
@ -595,6 +607,7 @@ void TopBarWidget::updateControlsVisibility() {
_clear->show(); _clear->show();
_delete->setVisible(_canDelete); _delete->setVisible(_canDelete);
_forward->setVisible(_canForward); _forward->setVisible(_canForward);
_sendNow->setVisible(_canSendNow);
auto backVisible = Adaptive::OneColumn() auto backVisible = Adaptive::OneColumn()
|| (App::main() && !App::main()->stackIsEmpty()) || (App::main() && !App::main()->stackIsEmpty())
@ -665,29 +678,34 @@ void TopBarWidget::updateMembersShowArea() {
void TopBarWidget::showSelected(SelectedState state) { void TopBarWidget::showSelected(SelectedState state) {
auto canDelete = (state.count > 0 && state.count == state.canDeleteCount); auto canDelete = (state.count > 0 && state.count == state.canDeleteCount);
auto canForward = (state.count > 0 && state.count == state.canForwardCount); auto canForward = (state.count > 0 && state.count == state.canForwardCount);
if (_selectedCount == state.count && _canDelete == canDelete && _canForward == canForward) { auto canSendNow = (state.count > 0 && state.count == state.canSendNowCount);
if (_selectedCount == state.count && _canDelete == canDelete && _canForward == canForward && _canSendNow == canSendNow) {
return; return;
} }
if (state.count == 0) { if (state.count == 0) {
// Don't change the visible buttons if the selection is cancelled. // Don't change the visible buttons if the selection is cancelled.
canDelete = _canDelete; canDelete = _canDelete;
canForward = _canForward; canForward = _canForward;
canSendNow = _canSendNow;
} }
auto wasSelected = (_selectedCount > 0); auto wasSelected = (_selectedCount > 0);
_selectedCount = state.count; _selectedCount = state.count;
if (_selectedCount > 0) { if (_selectedCount > 0) {
_forward->setNumbersText(_selectedCount); _forward->setNumbersText(_selectedCount);
_sendNow->setNumbersText(_selectedCount);
_delete->setNumbersText(_selectedCount); _delete->setNumbersText(_selectedCount);
if (!wasSelected) { if (!wasSelected) {
_forward->finishNumbersAnimation(); _forward->finishNumbersAnimation();
_sendNow->finishNumbersAnimation();
_delete->finishNumbersAnimation(); _delete->finishNumbersAnimation();
} }
} }
auto hasSelected = (_selectedCount > 0); auto hasSelected = (_selectedCount > 0);
if (_canDelete != canDelete || _canForward != canForward) { if (_canDelete != canDelete || _canForward != canForward || _canSendNow != canSendNow) {
_canDelete = canDelete; _canDelete = canDelete;
_canForward = canForward; _canForward = canForward;
_canSendNow = canSendNow;
updateControlsVisibility(); updateControlsVisibility();
} }
if (wasSelected != hasSelected) { if (wasSelected != hasSelected) {

View File

@ -38,6 +38,7 @@ public:
int count = 0; int count = 0;
int canDeleteCount = 0; int canDeleteCount = 0;
int canForwardCount = 0; int canForwardCount = 0;
int canSendNowCount = 0;
}; };
enum class Section { enum class Section {
History, History,
@ -64,6 +65,9 @@ public:
rpl::producer<> forwardSelectionRequest() const { rpl::producer<> forwardSelectionRequest() const {
return _forwardSelection.events(); return _forwardSelection.events();
} }
rpl::producer<> sendNowSelectionRequest() const {
return _sendNowSelection.events();
}
rpl::producer<> deleteSelectionRequest() const { rpl::producer<> deleteSelectionRequest() const {
return _deleteSelection.events(); return _deleteSelection.events();
} }
@ -123,11 +127,12 @@ private:
int _selectedCount = 0; int _selectedCount = 0;
bool _canDelete = false; bool _canDelete = false;
bool _canForward = false; bool _canForward = false;
bool _canSendNow = false;
Ui::Animations::Simple _selectedShown; Ui::Animations::Simple _selectedShown;
object_ptr<Ui::RoundButton> _clear; object_ptr<Ui::RoundButton> _clear;
object_ptr<Ui::RoundButton> _forward, _delete; object_ptr<Ui::RoundButton> _forward, _sendNow, _delete;
object_ptr<Ui::IconButton> _back; object_ptr<Ui::IconButton> _back;
object_ptr<Ui::UnreadBadge> _unreadBadge = { nullptr }; object_ptr<Ui::UnreadBadge> _unreadBadge = { nullptr };
@ -153,6 +158,7 @@ private:
base::Timer _onlineUpdater; base::Timer _onlineUpdater;
rpl::event_stream<> _forwardSelection; rpl::event_stream<> _forwardSelection;
rpl::event_stream<> _sendNowSelection;
rpl::event_stream<> _deleteSelection; rpl::event_stream<> _deleteSelection;
rpl::event_stream<> _clearSelection; rpl::event_stream<> _clearSelection;

View File

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/input_fields.h" #include "ui/widgets/input_fields.h"
#include "ui/emoji_config.h" #include "ui/emoji_config.h"
#include "export/export_settings.h" #include "export/export_settings.h"
#include "api/api_hash.h"
#include "core/crash_reports.h" #include "core/crash_reports.h"
#include "core/update_checker.h" #include "core/update_checker.h"
#include "observer_peer.h" #include "observer_peer.h"
@ -3854,13 +3855,11 @@ void readArchivedStickers() {
} }
int32 countDocumentVectorHash(const QVector<DocumentData*> vector) { int32 countDocumentVectorHash(const QVector<DocumentData*> vector) {
uint32 acc = 0; auto result = Api::HashInit();
for_const (auto doc, vector) { for (const auto document : vector) {
auto docId = doc->id; Api::HashUpdate(result, document->id);
acc = (acc * 20261) + uint32(docId >> 32);
acc = (acc * 20261) + uint32(docId & 0xFFFFFFFF);
} }
return int32(acc & 0x7FFFFFFF); return Api::HashFinalize(result);
} }
int32 countSpecialStickerSetHash(uint64 setId) { int32 countSpecialStickerSetHash(uint64 setId) {
@ -3873,7 +3872,7 @@ int32 countSpecialStickerSetHash(uint64 setId) {
} }
int32 countStickersHash(bool checkOutdatedInfo) { int32 countStickersHash(bool checkOutdatedInfo) {
uint32 acc = 0; auto result = Api::HashInit();
bool foundOutdated = false; bool foundOutdated = false;
auto &sets = Auth().data().stickerSets(); auto &sets = Auth().data().stickerSets();
auto &order = Auth().data().stickerSetsOrder(); auto &order = Auth().data().stickerSetsOrder();
@ -3884,11 +3883,13 @@ int32 countStickersHash(bool checkOutdatedInfo) {
foundOutdated = true; foundOutdated = true;
} else if (!(j->flags & MTPDstickerSet_ClientFlag::f_special) } else if (!(j->flags & MTPDstickerSet_ClientFlag::f_special)
&& !(j->flags & MTPDstickerSet::Flag::f_archived)) { && !(j->flags & MTPDstickerSet::Flag::f_archived)) {
acc = (acc * 20261) + j->hash; Api::HashUpdate(result, j->hash);
} }
} }
} }
return (!checkOutdatedInfo || !foundOutdated) ? int32(acc & 0x7FFFFFFF) : 0; return (!checkOutdatedInfo || !foundOutdated)
? Api::HashFinalize(result)
: 0;
} }
int32 countRecentStickersHash() { int32 countRecentStickersHash() {
@ -3900,19 +3901,18 @@ int32 countFavedStickersHash() {
} }
int32 countFeaturedStickersHash() { int32 countFeaturedStickersHash() {
uint32 acc = 0; auto result = Api::HashInit();
auto &sets = Auth().data().stickerSets(); const auto &sets = Auth().data().stickerSets();
auto &featured = Auth().data().featuredStickerSetsOrder(); const auto &featured = Auth().data().featuredStickerSetsOrder();
for_const (auto setId, featured) { for (const auto setId : featured) {
acc = (acc * 20261) + uint32(setId >> 32); Api::HashUpdate(result, setId);
acc = (acc * 20261) + uint32(setId & 0xFFFFFFFF);
auto it = sets.constFind(setId); auto it = sets.constFind(setId);
if (it != sets.cend() && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { if (it != sets.cend() && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) {
acc = (acc * 20261) + 1U; Api::HashUpdate(result, 1);
} }
} }
return int32(acc & 0x7FFFFFFF); return Api::HashFinalize(result);
} }
int32 countSavedGifsHash() { int32 countSavedGifsHash() {

View File

@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwindow.h" #include "mainwindow.h"
#include "observer_peer.h" #include "observer_peer.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "window/window_controller.h" #include "window/window_controller.h"
#include "support/support_helper.h" #include "support/support_helper.h"
@ -40,6 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat.h" #include "data/data_chat.h"
#include "data/data_drafts.h" #include "data/data_drafts.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_scheduled_messages.h"
#include "dialogs/dialogs_key.h" #include "dialogs/dialogs_key.h"
#include "boxes/peers/edit_peer_info_box.h" #include "boxes/peers/edit_peer_info_box.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
@ -849,6 +851,47 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
return weak->data(); return weak->data();
} }
QPointer<Ui::RpWidget> ShowSendNowMessagesBox(
not_null<Window::SessionNavigation*> navigation,
not_null<History*> history,
MessageIdsList &&items,
FnMut<void()> &&successCallback) {
const auto session = &navigation->session();
const auto text = "Send now?";
const auto box = std::make_shared<QPointer<BoxContent>>();
auto done = [
=,
list = std::move(items),
callback = std::move(successCallback)
]() mutable {
if (*box) {
(*box)->closeBox();
}
auto ids = QVector<MTPint>();
for (const auto &itemId : list) {
if (const auto item = session->data().message(itemId)) {
if (item->allowsSendNow()) {
ids.push_back(MTP_int(
session->data().scheduledMessages().lookupId(item)));
}
}
}
session->api().request(MTPmessages_SendScheduledMessages(
history->peer->input,
MTP_vector<MTPint>(ids)
)).done([=](const MTPUpdates &result) {
session->api().applyUpdates(result);
}).send();
if (callback) {
callback();
}
};
*box = Ui::show(
Box<ConfirmBox>(text, tr::lng_send_button(tr::now), std::move(done)),
LayerOption::KeepOther);
return box->data();
}
void PeerMenuAddChannelMembers( void PeerMenuAddChannelMembers(
not_null<Window::SessionNavigation*> navigation, not_null<Window::SessionNavigation*> navigation,
not_null<ChannelData*> channel) { not_null<ChannelData*> channel) {

View File

@ -74,4 +74,10 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
MessageIdsList &&items, MessageIdsList &&items,
FnMut<void()> &&successCallback = nullptr); FnMut<void()> &&successCallback = nullptr);
QPointer<Ui::RpWidget> ShowSendNowMessagesBox(
not_null<Window::SessionNavigation*> navigation,
not_null<History*> history,
MessageIdsList &&items,
FnMut<void()> &&successCallback = nullptr);
} // namespace Window } // namespace Window