mirror of https://github.com/procxx/kepka.git
Add initial scheduled list implementation.
This commit is contained in:
parent
3814b0833d
commit
815a18be94
|
@ -77,7 +77,7 @@ ScheduledMessages::~ScheduledMessages() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MsgId ScheduledMessages::scheduledId(not_null<HistoryItem*> item) {
|
MsgId ScheduledMessages::lookupId(not_null<HistoryItem*> item) const {
|
||||||
if (const auto i = _data.find(item->history()); i != end(_data)) {
|
if (const auto i = _data.find(item->history()); i != end(_data)) {
|
||||||
const auto &list = i->second.idByItem;
|
const auto &list = i->second.idByItem;
|
||||||
if (const auto j = list.find(item); j != end(list)) {
|
if (const auto j = list.find(item); j != end(list)) {
|
||||||
|
@ -87,16 +87,9 @@ MsgId ScheduledMessages::scheduledId(not_null<HistoryItem*> item) {
|
||||||
return MsgId(0);
|
return MsgId(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryItem *ScheduledMessages::scheduledMessage(
|
int ScheduledMessages::count(not_null<History*> history) const {
|
||||||
not_null<History*> history,
|
const auto i = _data.find(history);
|
||||||
MsgId id) {
|
return (i != end(_data)) ? i->second.items.size() : 0;
|
||||||
if (const auto i = _data.find(history); i != end(_data)) {
|
|
||||||
const auto &list = i->second.itemById;
|
|
||||||
if (const auto j = list.find(id); j != end(list)) {
|
|
||||||
return j->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduledMessages::apply(const MTPDupdateNewScheduledMessage &update) {
|
void ScheduledMessages::apply(const MTPDupdateNewScheduledMessage &update) {
|
||||||
|
@ -152,6 +145,28 @@ rpl::producer<> ScheduledMessages::updates(not_null<History*> history) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Data::MessagesSlice ScheduledMessages::list(not_null<History*> history) {
|
||||||
|
auto result = Data::MessagesSlice();
|
||||||
|
const auto i = _data.find(history);
|
||||||
|
if (i == end(_data)) {
|
||||||
|
const auto i = _requests.find(history);
|
||||||
|
if (i == end(_requests)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.fullCount = result.skippedAfter = result.skippedBefore = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const auto &list = i->second.items;
|
||||||
|
result.skippedAfter = result.skippedBefore = 0;
|
||||||
|
result.fullCount = int(list.size());
|
||||||
|
result.ids = ranges::view::all(
|
||||||
|
list
|
||||||
|
) | ranges::view::transform(
|
||||||
|
&HistoryItem::fullId
|
||||||
|
) | ranges::view::reverse | ranges::to_vector;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void ScheduledMessages::request(not_null<History*> history) {
|
void ScheduledMessages::request(not_null<History*> history) {
|
||||||
auto &request = _requests[history];
|
auto &request = _requests[history];
|
||||||
if (request.requestId) {
|
if (request.requestId) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ class Session;
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
|
struct MessagesSlice;
|
||||||
|
|
||||||
class ScheduledMessages final {
|
class ScheduledMessages final {
|
||||||
public:
|
public:
|
||||||
|
@ -26,15 +27,14 @@ public:
|
||||||
ScheduledMessages &operator=(const ScheduledMessages &other) = delete;
|
ScheduledMessages &operator=(const ScheduledMessages &other) = delete;
|
||||||
~ScheduledMessages();
|
~ScheduledMessages();
|
||||||
|
|
||||||
[[nodiscard]] MsgId scheduledId(not_null<HistoryItem*> item);
|
[[nodiscard]] MsgId lookupId(not_null<HistoryItem*> item) const;
|
||||||
[[nodiscard]] HistoryItem *scheduledMessage(
|
[[nodiscard]] int count(not_null<History*> history) const;
|
||||||
not_null<History*> history,
|
|
||||||
MsgId id);
|
|
||||||
|
|
||||||
void apply(const MTPDupdateNewScheduledMessage &update);
|
void apply(const MTPDupdateNewScheduledMessage &update);
|
||||||
void apply(const MTPDupdateDeleteScheduledMessages &update);
|
void apply(const MTPDupdateDeleteScheduledMessages &update);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> updates(not_null<History*> history);
|
[[nodiscard]] rpl::producer<> updates(not_null<History*> history);
|
||||||
|
[[nodiscard]] Data::MessagesSlice list(not_null<History*> history);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using OwnedItem = std::unique_ptr<HistoryItem, HistoryItem::Destroyer>;
|
using OwnedItem = std::unique_ptr<HistoryItem, HistoryItem::Destroyer>;
|
||||||
|
|
|
@ -45,6 +45,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_web_page.h"
|
#include "data/data_web_page.h"
|
||||||
#include "data/data_game.h"
|
#include "data/data_game.h"
|
||||||
#include "data/data_poll.h"
|
#include "data/data_poll.h"
|
||||||
|
#include "data/data_scheduled_messages.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "styles/style_boxes.h" // st::backgroundSize
|
#include "styles/style_boxes.h" // st::backgroundSize
|
||||||
|
|
||||||
|
@ -207,7 +208,7 @@ Session::Session(not_null<Main::Session*> session)
|
||||||
})
|
})
|
||||||
, _unmuteByFinishedTimer([=] { unmuteByFinished(); })
|
, _unmuteByFinishedTimer([=] { unmuteByFinished(); })
|
||||||
, _groups(this)
|
, _groups(this)
|
||||||
, _scheduledMessages(this) {
|
, _scheduledMessages(std::make_unique<ScheduledMessages>(this)) {
|
||||||
_cache->open(Local::cacheKey());
|
_cache->open(Local::cacheKey());
|
||||||
_bigFileCache->open(Local::cacheBigFileKey());
|
_bigFileCache->open(Local::cacheBigFileKey());
|
||||||
|
|
||||||
|
@ -231,6 +232,7 @@ void Session::clear() {
|
||||||
for (const auto &[peerId, history] : _histories) {
|
for (const auto &[peerId, history] : _histories) {
|
||||||
history->clear(History::ClearType::Unload);
|
history->clear(History::ClearType::Unload);
|
||||||
}
|
}
|
||||||
|
_scheduledMessages = nullptr;
|
||||||
_dependentMessages.clear();
|
_dependentMessages.clear();
|
||||||
base::take(_messages);
|
base::take(_messages);
|
||||||
base::take(_channelMessages);
|
base::take(_channelMessages);
|
||||||
|
|
|
@ -14,7 +14,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "dialogs/dialogs_main_list.h"
|
#include "dialogs/dialogs_main_list.h"
|
||||||
#include "data/data_groups.h"
|
#include "data/data_groups.h"
|
||||||
#include "data/data_notify_settings.h"
|
#include "data/data_notify_settings.h"
|
||||||
#include "data/data_scheduled_messages.h"
|
|
||||||
#include "history/history_location_manager.h"
|
#include "history/history_location_manager.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
#include "base/flags.h"
|
#include "base/flags.h"
|
||||||
|
@ -89,11 +88,8 @@ public:
|
||||||
return _groups;
|
return _groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ScheduledMessages &scheduledMessages() {
|
[[nodiscard]] ScheduledMessages &scheduledMessages() const {
|
||||||
return _scheduledMessages;
|
return *_scheduledMessages;
|
||||||
}
|
|
||||||
[[nodiscard]] const ScheduledMessages &scheduledMessages() const {
|
|
||||||
return _scheduledMessages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
@ -989,7 +985,7 @@ private:
|
||||||
int32 _wallpapersHash = 0;
|
int32 _wallpapersHash = 0;
|
||||||
|
|
||||||
Groups _groups;
|
Groups _groups;
|
||||||
ScheduledMessages _scheduledMessages;
|
std::unique_ptr<ScheduledMessages> _scheduledMessages;
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ Widget::Widget(
|
||||||
_topBar->move(0, 0);
|
_topBar->move(0, 0);
|
||||||
_topBar->resizeToWidth(width());
|
_topBar->resizeToWidth(width());
|
||||||
_topBar->show();
|
_topBar->show();
|
||||||
|
|
||||||
_topBar->forwardSelectionRequest(
|
_topBar->forwardSelectionRequest(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
forwardSelected();
|
forwardSelected();
|
||||||
|
|
|
@ -267,6 +267,10 @@ historyBotCommandStart: IconButton(historyAttach) {
|
||||||
icon: icon {{ "send_control_bot_command", historyComposeIconFg }};
|
icon: icon {{ "send_control_bot_command", historyComposeIconFg }};
|
||||||
iconOver: icon {{ "send_control_bot_command", historyComposeIconFgOver }};
|
iconOver: icon {{ "send_control_bot_command", historyComposeIconFgOver }};
|
||||||
}
|
}
|
||||||
|
historyScheduledToggle: IconButton(historyAttach) {
|
||||||
|
icon: icon {{ "dialogs_calendar", historyComposeIconFg }};
|
||||||
|
iconOver: icon {{ "dialogs_calendar", historyComposeIconFgOver }};
|
||||||
|
}
|
||||||
historyRecordVoiceFg: historyComposeIconFg;
|
historyRecordVoiceFg: historyComposeIconFg;
|
||||||
historyRecordVoiceFgOver: historyComposeIconFgOver;
|
historyRecordVoiceFgOver: historyComposeIconFgOver;
|
||||||
historyRecordVoiceFgActive: windowBgActive;
|
historyRecordVoiceFgActive: windowBgActive;
|
||||||
|
|
|
@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_chat.h"
|
#include "data/data_chat.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
#include "data/data_scheduled_messages.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "history/history_message.h"
|
#include "history/history_message.h"
|
||||||
|
@ -46,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
//#include "history/feed/history_feed_section.h" // #feed
|
//#include "history/feed/history_feed_section.h" // #feed
|
||||||
#include "history/view/history_view_service_message.h"
|
#include "history/view/history_view_service_message.h"
|
||||||
#include "history/view/history_view_element.h"
|
#include "history/view/history_view_element.h"
|
||||||
|
#include "history/view/history_view_scheduled_section.h"
|
||||||
#include "profile/profile_block_group_members.h"
|
#include "profile/profile_block_group_members.h"
|
||||||
#include "info/info_memento.h"
|
#include "info/info_memento.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
|
@ -644,6 +646,7 @@ HistoryWidget::HistoryWidget(
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
setupScheduledToggle();
|
||||||
orderWidgets();
|
orderWidgets();
|
||||||
setupShortcuts();
|
setupShortcuts();
|
||||||
}
|
}
|
||||||
|
@ -1766,6 +1769,7 @@ void HistoryWidget::showHistory(
|
||||||
session().data().requestNotifySettings(_peer);
|
session().data().requestNotifySettings(_peer);
|
||||||
refreshSilentToggle();
|
refreshSilentToggle();
|
||||||
}
|
}
|
||||||
|
refreshScheduledToggle();
|
||||||
|
|
||||||
if (_showAtMsgId == ShowAtUnreadMsgId) {
|
if (_showAtMsgId == ShowAtUnreadMsgId) {
|
||||||
if (_history->scrollTopItem) {
|
if (_history->scrollTopItem) {
|
||||||
|
@ -1902,6 +1906,37 @@ void HistoryWidget::refreshSilentToggle() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::setupScheduledToggle() {
|
||||||
|
controller()->activeChatValue(
|
||||||
|
) | rpl::map([=](const Dialogs::Key &key) -> rpl::producer<> {
|
||||||
|
if (const auto history = key.history()) {
|
||||||
|
return session().data().scheduledMessages().updates(history);
|
||||||
|
}
|
||||||
|
return rpl::never<rpl::empty_value>();
|
||||||
|
}) | rpl::flatten_latest(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
refreshScheduledToggle();
|
||||||
|
updateControlsVisibility();
|
||||||
|
updateControlsGeometry();
|
||||||
|
}, lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::refreshScheduledToggle() {
|
||||||
|
const auto has = _history
|
||||||
|
&& _peer->canWrite()
|
||||||
|
&& (session().data().scheduledMessages().count(_history) > 0);
|
||||||
|
if (!_scheduled && has) {
|
||||||
|
_scheduled.create(this, st::historyScheduledToggle);
|
||||||
|
_scheduled->show();
|
||||||
|
_scheduled->addClickHandler([=] {
|
||||||
|
controller()->showSection(
|
||||||
|
HistoryView::ScheduledMemento(_history));
|
||||||
|
});
|
||||||
|
} else if (_scheduled && !has) {
|
||||||
|
_scheduled.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool HistoryWidget::contentOverlapped(const QRect &globalRect) {
|
bool HistoryWidget::contentOverlapped(const QRect &globalRect) {
|
||||||
return (_attachDragDocument->overlaps(globalRect)
|
return (_attachDragDocument->overlaps(globalRect)
|
||||||
|| _attachDragPhoto->overlaps(globalRect)
|
|| _attachDragPhoto->overlaps(globalRect)
|
||||||
|
@ -2004,6 +2039,9 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
if (_silent) {
|
if (_silent) {
|
||||||
_silent->hide();
|
_silent->hide();
|
||||||
}
|
}
|
||||||
|
if (_scheduled) {
|
||||||
|
_scheduled->hide();
|
||||||
|
}
|
||||||
_kbScroll->hide();
|
_kbScroll->hide();
|
||||||
_fieldBarCancel->hide();
|
_fieldBarCancel->hide();
|
||||||
_attachToggle->hide();
|
_attachToggle->hide();
|
||||||
|
@ -2041,6 +2079,9 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
if (_silent) {
|
if (_silent) {
|
||||||
_silent->hide();
|
_silent->hide();
|
||||||
}
|
}
|
||||||
|
if (_scheduled) {
|
||||||
|
_scheduled->hide();
|
||||||
|
}
|
||||||
if (_kbShown) {
|
if (_kbShown) {
|
||||||
_kbScroll->show();
|
_kbScroll->show();
|
||||||
} else {
|
} else {
|
||||||
|
@ -2080,6 +2121,9 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
if (_silent) {
|
if (_silent) {
|
||||||
_silent->show();
|
_silent->show();
|
||||||
}
|
}
|
||||||
|
if (_scheduled) {
|
||||||
|
_scheduled->show();
|
||||||
|
}
|
||||||
updateFieldPlaceholder();
|
updateFieldPlaceholder();
|
||||||
}
|
}
|
||||||
if (_editMsgId || _replyToId || readyToForward() || (_previewData && _previewData->pendingTill >= 0) || _kbReplyTo) {
|
if (_editMsgId || _replyToId || readyToForward() || (_previewData && _previewData->pendingTill >= 0) || _kbReplyTo) {
|
||||||
|
@ -2106,6 +2150,9 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
if (_silent) {
|
if (_silent) {
|
||||||
_silent->hide();
|
_silent->hide();
|
||||||
}
|
}
|
||||||
|
if (_scheduled) {
|
||||||
|
_scheduled->hide();
|
||||||
|
}
|
||||||
_kbScroll->hide();
|
_kbScroll->hide();
|
||||||
_fieldBarCancel->hide();
|
_fieldBarCancel->hide();
|
||||||
_attachToggle->hide();
|
_attachToggle->hide();
|
||||||
|
@ -3841,7 +3888,7 @@ void HistoryWidget::moveFieldControls() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// _attachToggle --------- _inlineResults -------------------------------------- _tabbedPanel --------- _fieldBarCancel
|
// _attachToggle --------- _inlineResults -------------------------------------- _tabbedPanel --------- _fieldBarCancel
|
||||||
// (_attachDocument|_attachPhoto) _field (_silent|_cmdStart|_kbShow) (_kbHide|_tabbedSelectorToggle) [_broadcast] _send
|
// (_attachDocument|_attachPhoto) _field (_scheduled) (_silent|_cmdStart|_kbShow) (_kbHide|_tabbedSelectorToggle) [_broadcast] _send
|
||||||
// (_botStart|_unblock|_joinChannel|{_muteUnmute&_discuss})
|
// (_botStart|_unblock|_joinChannel|{_muteUnmute&_discuss})
|
||||||
|
|
||||||
auto buttonsBottom = bottom - _attachToggle->height();
|
auto buttonsBottom = bottom - _attachToggle->height();
|
||||||
|
@ -3858,6 +3905,13 @@ void HistoryWidget::moveFieldControls() {
|
||||||
if (_silent) {
|
if (_silent) {
|
||||||
_silent->moveToRight(right, buttonsBottom);
|
_silent->moveToRight(right, buttonsBottom);
|
||||||
}
|
}
|
||||||
|
const auto kbShowShown = _history && !_kbShown && _keyboard->hasMarkup();
|
||||||
|
if (kbShowShown || _cmdStartShown || _silent) {
|
||||||
|
right += _botCommandStart->width();
|
||||||
|
}
|
||||||
|
if (_scheduled) {
|
||||||
|
_scheduled->moveToRight(right, buttonsBottom);
|
||||||
|
}
|
||||||
|
|
||||||
_fieldBarCancel->moveToRight(0, _field->y() - st::historySendPadding - _fieldBarCancel->height());
|
_fieldBarCancel->moveToRight(0, _field->y() - st::historySendPadding - _fieldBarCancel->height());
|
||||||
if (_inlineResults) {
|
if (_inlineResults) {
|
||||||
|
@ -3915,6 +3969,7 @@ void HistoryWidget::updateFieldSize() {
|
||||||
if (kbShowShown) fieldWidth -= _botKeyboardShow->width();
|
if (kbShowShown) fieldWidth -= _botKeyboardShow->width();
|
||||||
if (_cmdStartShown) fieldWidth -= _botCommandStart->width();
|
if (_cmdStartShown) fieldWidth -= _botCommandStart->width();
|
||||||
if (_silent) fieldWidth -= _silent->width();
|
if (_silent) fieldWidth -= _silent->width();
|
||||||
|
if (_scheduled) fieldWidth -= _scheduled->width();
|
||||||
|
|
||||||
if (_field->width() != fieldWidth) {
|
if (_field->width() != fieldWidth) {
|
||||||
_field->resize(fieldWidth, _field->height());
|
_field->resize(fieldWidth, _field->height());
|
||||||
|
@ -6089,6 +6144,7 @@ void HistoryWidget::fullPeerUpdated(PeerData *peer) {
|
||||||
if (!_canSendMessages) {
|
if (!_canSendMessages) {
|
||||||
cancelReply();
|
cancelReply();
|
||||||
}
|
}
|
||||||
|
refreshScheduledToggle();
|
||||||
refreshSilentToggle();
|
refreshSilentToggle();
|
||||||
refresh = true;
|
refresh = true;
|
||||||
}
|
}
|
||||||
|
@ -6135,6 +6191,7 @@ void HistoryWidget::handlePeerUpdate() {
|
||||||
if (!_canSendMessages) {
|
if (!_canSendMessages) {
|
||||||
cancelReply();
|
cancelReply();
|
||||||
}
|
}
|
||||||
|
refreshScheduledToggle();
|
||||||
refreshSilentToggle();
|
refreshSilentToggle();
|
||||||
resize = true;
|
resize = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -711,6 +711,9 @@ private:
|
||||||
bool showInlineBotCancel() const;
|
bool showInlineBotCancel() const;
|
||||||
void refreshSilentToggle();
|
void refreshSilentToggle();
|
||||||
|
|
||||||
|
void setupScheduledToggle();
|
||||||
|
void refreshScheduledToggle();
|
||||||
|
|
||||||
std::unique_ptr<HistoryView::ContactStatus> _contactStatus;
|
std::unique_ptr<HistoryView::ContactStatus> _contactStatus;
|
||||||
|
|
||||||
object_ptr<Ui::SendButton> _send;
|
object_ptr<Ui::SendButton> _send;
|
||||||
|
@ -728,6 +731,7 @@ private:
|
||||||
object_ptr<Ui::IconButton> _botKeyboardHide;
|
object_ptr<Ui::IconButton> _botKeyboardHide;
|
||||||
object_ptr<Ui::IconButton> _botCommandStart;
|
object_ptr<Ui::IconButton> _botCommandStart;
|
||||||
object_ptr<Ui::SilentToggle> _silent = { nullptr };
|
object_ptr<Ui::SilentToggle> _silent = { nullptr };
|
||||||
|
object_ptr<Ui::IconButton> _scheduled = { nullptr };
|
||||||
bool _cmdStartShown = false;
|
bool _cmdStartShown = false;
|
||||||
object_ptr<Ui::InputField> _field;
|
object_ptr<Ui::InputField> _field;
|
||||||
bool _recording = false;
|
bool _recording = false;
|
||||||
|
|
|
@ -92,7 +92,8 @@ public:
|
||||||
int shift = 0;
|
int shift = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit ListMemento(Data::MessagePosition position)
|
explicit ListMemento(
|
||||||
|
Data::MessagePosition position = Data::UnreadMessagePosition)
|
||||||
: _aroundPosition(position) {
|
: _aroundPosition(position) {
|
||||||
}
|
}
|
||||||
void setAroundPosition(Data::MessagePosition position) {
|
void setAroundPosition(Data::MessagePosition position) {
|
||||||
|
|
|
@ -0,0 +1,423 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "history/view/history_view_scheduled_section.h"
|
||||||
|
|
||||||
|
#include "history/view/history_view_top_bar_widget.h"
|
||||||
|
#include "history/view/history_view_list_widget.h"
|
||||||
|
#include "history/history.h"
|
||||||
|
#include "history/history_item.h"
|
||||||
|
#include "ui/widgets/scroll_area.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
|
#include "ui/special_buttons.h"
|
||||||
|
#include "window/window_session_controller.h"
|
||||||
|
#include "core/event_filter.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_scheduled_messages.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
|
#include "styles/style_history.h"
|
||||||
|
#include "styles/style_window.h"
|
||||||
|
#include "styles/style_info.h"
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
|
||||||
|
object_ptr<Window::SectionWidget> ScheduledMemento::createWidget(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
Window::Column column,
|
||||||
|
const QRect &geometry) {
|
||||||
|
if (column == Window::Column::Third) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto result = object_ptr<ScheduledWidget>(parent, controller, _history);
|
||||||
|
result->setInternalState(geometry, this);
|
||||||
|
return std::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScheduledWidget::ScheduledWidget(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<History*> history)
|
||||||
|
: Window::SectionWidget(parent, controller)
|
||||||
|
, _history(history)
|
||||||
|
, _scroll(this, st::historyScroll, false)
|
||||||
|
, _topBar(this, controller)
|
||||||
|
, _topBarShadow(this)
|
||||||
|
, _scrollDown(_scroll, st::historyToDown) {
|
||||||
|
_topBar->setActiveChat(_history);
|
||||||
|
|
||||||
|
_topBar->move(0, 0);
|
||||||
|
_topBar->resizeToWidth(width());
|
||||||
|
_topBar->show();
|
||||||
|
|
||||||
|
_topBar->deleteSelectionRequest(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
confirmDeleteSelected();
|
||||||
|
}, _topBar->lifetime());
|
||||||
|
_topBar->clearSelectionRequest(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
clearSelected();
|
||||||
|
}, _topBar->lifetime());
|
||||||
|
|
||||||
|
_topBarShadow->raise();
|
||||||
|
updateAdaptiveLayout();
|
||||||
|
subscribe(Adaptive::Changed(), [=] { updateAdaptiveLayout(); });
|
||||||
|
|
||||||
|
_inner = _scroll->setOwnedWidget(object_ptr<ListWidget>(
|
||||||
|
this,
|
||||||
|
controller,
|
||||||
|
static_cast<ListDelegate*>(this)));
|
||||||
|
_scroll->move(0, _topBar->height());
|
||||||
|
_scroll->show();
|
||||||
|
connect(_scroll, &Ui::ScrollArea::scrolled, [=] { onScroll(); });
|
||||||
|
|
||||||
|
setupScrollDownButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::setupScrollDownButton() {
|
||||||
|
_scrollDown->setClickedCallback([=] {
|
||||||
|
scrollDownClicked();
|
||||||
|
});
|
||||||
|
Core::InstallEventFilter(_scrollDown, [=](not_null<QEvent*> event) {
|
||||||
|
if (event->type() == QEvent::Wheel) {
|
||||||
|
return _scroll->viewportEvent(event);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
updateScrollDownVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::scrollDownClicked() {
|
||||||
|
showAtPosition(Data::MaxMessagePosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::showAtPosition(Data::MessagePosition position) {
|
||||||
|
if (showAtPositionNow(position)) {
|
||||||
|
if (const auto highlight = base::take(_highlightMessageId)) {
|
||||||
|
_inner->highlightMessage(highlight);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_nextAnimatedScrollPosition = position;
|
||||||
|
_nextAnimatedScrollDelta = _inner->isBelowPosition(position)
|
||||||
|
? -_scroll->height()
|
||||||
|
: _inner->isAbovePosition(position)
|
||||||
|
? _scroll->height()
|
||||||
|
: 0;
|
||||||
|
auto memento = HistoryView::ListMemento(position);
|
||||||
|
_inner->restoreState(&memento);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScheduledWidget::showAtPositionNow(Data::MessagePosition position) {
|
||||||
|
if (const auto scrollTop = _inner->scrollTopForPosition(position)) {
|
||||||
|
const auto currentScrollTop = _scroll->scrollTop();
|
||||||
|
const auto wanted = snap(*scrollTop, 0, _scroll->scrollTopMax());
|
||||||
|
const auto fullDelta = (wanted - currentScrollTop);
|
||||||
|
const auto limit = _scroll->height();
|
||||||
|
const auto scrollDelta = snap(fullDelta, -limit, limit);
|
||||||
|
_inner->animatedScrollTo(
|
||||||
|
wanted,
|
||||||
|
position,
|
||||||
|
scrollDelta,
|
||||||
|
(std::abs(fullDelta) > limit
|
||||||
|
? HistoryView::ListWidget::AnimatedScroll::Part
|
||||||
|
: HistoryView::ListWidget::AnimatedScroll::Full));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::updateScrollDownVisibility() {
|
||||||
|
if (animating()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto scrollDownIsVisible = [&]() -> std::optional<bool> {
|
||||||
|
const auto top = _scroll->scrollTop() + st::historyToDownShownAfter;
|
||||||
|
if (top < _scroll->scrollTopMax()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_inner->loadedAtBottomKnown()) {
|
||||||
|
return !_inner->loadedAtBottom();
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
};
|
||||||
|
const auto scrollDownIsShown = scrollDownIsVisible();
|
||||||
|
if (!scrollDownIsShown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_scrollDownIsShown != *scrollDownIsShown) {
|
||||||
|
_scrollDownIsShown = *scrollDownIsShown;
|
||||||
|
_scrollDownShown.start(
|
||||||
|
[=] { updateScrollDownPosition(); },
|
||||||
|
_scrollDownIsShown ? 0. : 1.,
|
||||||
|
_scrollDownIsShown ? 1. : 0.,
|
||||||
|
st::historyToDownDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::updateScrollDownPosition() {
|
||||||
|
// _scrollDown is a child widget of _scroll, not me.
|
||||||
|
auto top = anim::interpolate(
|
||||||
|
0,
|
||||||
|
_scrollDown->height() + st::historyToDownPosition.y(),
|
||||||
|
_scrollDownShown.value(_scrollDownIsShown ? 1. : 0.));
|
||||||
|
_scrollDown->moveToRight(
|
||||||
|
st::historyToDownPosition.x(),
|
||||||
|
_scroll->height() - top);
|
||||||
|
auto shouldBeHidden = !_scrollDownIsShown && !_scrollDownShown.animating();
|
||||||
|
if (shouldBeHidden != _scrollDown->isHidden()) {
|
||||||
|
_scrollDown->setVisible(!shouldBeHidden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::scrollDownAnimationFinish() {
|
||||||
|
_scrollDownShown.stop();
|
||||||
|
updateScrollDownPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::updateAdaptiveLayout() {
|
||||||
|
_topBarShadow->moveToLeft(
|
||||||
|
Adaptive::OneColumn() ? 0 : st::lineWidth,
|
||||||
|
_topBar->height());
|
||||||
|
}
|
||||||
|
|
||||||
|
not_null<History*> ScheduledWidget::history() const {
|
||||||
|
return _history;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialogs::RowDescriptor ScheduledWidget::activeChat() const {
|
||||||
|
return {
|
||||||
|
_history,
|
||||||
|
FullMsgId(_history->channelId(), ShowAtUnreadMsgId)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap ScheduledWidget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) {
|
||||||
|
if (params.withTopBarShadow) _topBarShadow->hide();
|
||||||
|
auto result = Ui::GrabWidget(this);
|
||||||
|
if (params.withTopBarShadow) _topBarShadow->show();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::doSetInnerFocus() {
|
||||||
|
_inner->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScheduledWidget::showInternal(
|
||||||
|
not_null<Window::SectionMemento*> memento,
|
||||||
|
const Window::SectionShow ¶ms) {
|
||||||
|
if (auto logMemento = dynamic_cast<ScheduledMemento*>(memento.get())) {
|
||||||
|
if (logMemento->getHistory() == history()) {
|
||||||
|
restoreState(logMemento);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::setInternalState(
|
||||||
|
const QRect &geometry,
|
||||||
|
not_null<ScheduledMemento*> memento) {
|
||||||
|
setGeometry(geometry);
|
||||||
|
Ui::SendPendingMoveResizeEvents(this);
|
||||||
|
restoreState(memento);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Window::SectionMemento> ScheduledWidget::createMemento() {
|
||||||
|
auto result = std::make_unique<ScheduledMemento>(history());
|
||||||
|
saveState(result.get());
|
||||||
|
return std::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::saveState(not_null<ScheduledMemento*> memento) {
|
||||||
|
_inner->saveState(memento->list());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::restoreState(not_null<ScheduledMemento*> memento) {
|
||||||
|
_inner->restoreState(memento->list());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::resizeEvent(QResizeEvent *e) {
|
||||||
|
if (!width() || !height()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateControlsGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::updateControlsGeometry() {
|
||||||
|
const auto contentWidth = width();
|
||||||
|
|
||||||
|
const auto newScrollTop = _scroll->isHidden()
|
||||||
|
? std::nullopt
|
||||||
|
: base::make_optional(_scroll->scrollTop() + topDelta());
|
||||||
|
_topBar->resizeToWidth(contentWidth);
|
||||||
|
_topBarShadow->resize(contentWidth, st::lineWidth);
|
||||||
|
|
||||||
|
const auto bottom = height();
|
||||||
|
const auto scrollHeight = bottom
|
||||||
|
- _topBar->height();
|
||||||
|
// - _showNext->height();
|
||||||
|
const auto scrollSize = QSize(contentWidth, scrollHeight);
|
||||||
|
if (_scroll->size() != scrollSize) {
|
||||||
|
_skipScrollEvent = true;
|
||||||
|
_scroll->resize(scrollSize);
|
||||||
|
_inner->resizeToWidth(scrollSize.width(), _scroll->height());
|
||||||
|
_skipScrollEvent = false;
|
||||||
|
}
|
||||||
|
if (!_scroll->isHidden()) {
|
||||||
|
if (newScrollTop) {
|
||||||
|
_scroll->scrollToY(*newScrollTop);
|
||||||
|
}
|
||||||
|
updateInnerVisibleArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateScrollDownPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::paintEvent(QPaintEvent *e) {
|
||||||
|
if (animating()) {
|
||||||
|
SectionWidget::paintEvent(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Ui::skipPaintEvent(this, e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//if (hasPendingResizedItems()) {
|
||||||
|
// updateListSize();
|
||||||
|
//}
|
||||||
|
|
||||||
|
//auto ms = crl::now();
|
||||||
|
//_historyDownShown.step(ms);
|
||||||
|
|
||||||
|
SectionWidget::PaintBackground(this, e->rect());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::onScroll() {
|
||||||
|
if (_skipScrollEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateInnerVisibleArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::updateInnerVisibleArea() {
|
||||||
|
const auto scrollTop = _scroll->scrollTop();
|
||||||
|
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||||
|
updateScrollDownVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::showAnimatedHook(
|
||||||
|
const Window::SectionSlideParams ¶ms) {
|
||||||
|
_topBar->setAnimatingMode(true);
|
||||||
|
if (params.withTopBarShadow) _topBarShadow->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::showFinishedHook() {
|
||||||
|
_topBar->setAnimatingMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScheduledWidget::wheelEventFromFloatPlayer(QEvent *e) {
|
||||||
|
return _scroll->viewportEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect ScheduledWidget::rectForFloatPlayer() const {
|
||||||
|
return mapToGlobal(_scroll->geometry());
|
||||||
|
}
|
||||||
|
|
||||||
|
Context ScheduledWidget::listContext() {
|
||||||
|
return Context::History;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::listScrollTo(int top) {
|
||||||
|
if (_scroll->scrollTop() != top) {
|
||||||
|
_scroll->scrollToY(top);
|
||||||
|
} else {
|
||||||
|
updateInnerVisibleArea();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::listCancelRequest() {
|
||||||
|
controller()->showBackFromStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::listDeleteRequest() {
|
||||||
|
confirmDeleteSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<Data::MessagesSlice> ScheduledWidget::listSource(
|
||||||
|
Data::MessagePosition aroundId,
|
||||||
|
int limitBefore,
|
||||||
|
int limitAfter) {
|
||||||
|
const auto data = &controller()->session().data();
|
||||||
|
return rpl::single(
|
||||||
|
rpl::empty_value()
|
||||||
|
) | rpl::then(
|
||||||
|
data->scheduledMessages().updates(_history)
|
||||||
|
) | rpl::map([=] {
|
||||||
|
return data->scheduledMessages().list(_history);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScheduledWidget::listAllowsMultiSelect() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScheduledWidget::listIsLessInOrder(
|
||||||
|
not_null<HistoryItem*> first,
|
||||||
|
not_null<HistoryItem*> second) {
|
||||||
|
return first->position() < second->position();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::listSelectionChanged(SelectedItems &&items) {
|
||||||
|
HistoryView::TopBarWidget::SelectedState state;
|
||||||
|
state.count = items.size();
|
||||||
|
for (const auto item : items) {
|
||||||
|
if (item.canForward) {
|
||||||
|
++state.canForwardCount;
|
||||||
|
}
|
||||||
|
if (item.canDelete) {
|
||||||
|
++state.canDeleteCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_topBar->showSelected(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::listVisibleItemsChanged(HistoryItemsList &&items) {
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> ScheduledWidget::listUnreadBarView(
|
||||||
|
const std::vector<not_null<Element*>> &elements) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::listContentRefreshed() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ClickHandlerPtr ScheduledWidget::listDateLink(not_null<Element*> view) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::confirmDeleteSelected() {
|
||||||
|
auto items = _inner->getSelectedItems();
|
||||||
|
if (items.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//const auto weak = make_weak(this);
|
||||||
|
//const auto box = Ui::show(Box<DeleteMessagesBox>(std::move(items)));
|
||||||
|
//box->setDeleteConfirmedCallback([=] {
|
||||||
|
// if (const auto strong = weak.data()) {
|
||||||
|
// strong->clearSelected();
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::clearSelected() {
|
||||||
|
_inner->cancelSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace HistoryView
|
|
@ -0,0 +1,161 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "window/section_widget.h"
|
||||||
|
#include "window/section_memento.h"
|
||||||
|
#include "history/view/history_view_list_widget.h"
|
||||||
|
|
||||||
|
class History;
|
||||||
|
|
||||||
|
namespace Notify {
|
||||||
|
struct PeerUpdate;
|
||||||
|
} // namespace Notify
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ScrollArea;
|
||||||
|
class PlainShadow;
|
||||||
|
class FlatButton;
|
||||||
|
class HistoryDownButton;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Profile {
|
||||||
|
class BackButton;
|
||||||
|
} // namespace Profile
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
|
||||||
|
class Element;
|
||||||
|
class TopBarWidget;
|
||||||
|
class ScheduledMemento;
|
||||||
|
|
||||||
|
class ScheduledWidget final
|
||||||
|
: public Window::SectionWidget
|
||||||
|
, private ListDelegate {
|
||||||
|
public:
|
||||||
|
ScheduledWidget(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<History*> history);
|
||||||
|
|
||||||
|
not_null<History*> history() const;
|
||||||
|
Dialogs::RowDescriptor activeChat() const override;
|
||||||
|
|
||||||
|
bool hasTopBarShadow() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap grabForShowAnimation(
|
||||||
|
const Window::SectionSlideParams ¶ms) override;
|
||||||
|
|
||||||
|
bool showInternal(
|
||||||
|
not_null<Window::SectionMemento*> memento,
|
||||||
|
const Window::SectionShow ¶ms) override;
|
||||||
|
std::unique_ptr<Window::SectionMemento> createMemento() override;
|
||||||
|
|
||||||
|
void setInternalState(
|
||||||
|
const QRect &geometry,
|
||||||
|
not_null<ScheduledMemento*> memento);
|
||||||
|
|
||||||
|
// Float player interface.
|
||||||
|
bool wheelEventFromFloatPlayer(QEvent *e) override;
|
||||||
|
QRect rectForFloatPlayer() const override;
|
||||||
|
|
||||||
|
// ListDelegate interface.
|
||||||
|
Context listContext() override;
|
||||||
|
void listScrollTo(int top) override;
|
||||||
|
void listCancelRequest() override;
|
||||||
|
void listDeleteRequest() override;
|
||||||
|
rpl::producer<Data::MessagesSlice> listSource(
|
||||||
|
Data::MessagePosition aroundId,
|
||||||
|
int limitBefore,
|
||||||
|
int limitAfter) override;
|
||||||
|
bool listAllowsMultiSelect() override;
|
||||||
|
bool listIsLessInOrder(
|
||||||
|
not_null<HistoryItem*> first,
|
||||||
|
not_null<HistoryItem*> second) override;
|
||||||
|
void listSelectionChanged(SelectedItems &&items) override;
|
||||||
|
void listVisibleItemsChanged(HistoryItemsList &&items) override;
|
||||||
|
std::optional<int> listUnreadBarView(
|
||||||
|
const std::vector<not_null<Element*>> &elements) override;
|
||||||
|
void listContentRefreshed() override;
|
||||||
|
ClickHandlerPtr listDateLink(not_null<Element*> view) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
|
void showAnimatedHook(
|
||||||
|
const Window::SectionSlideParams ¶ms) override;
|
||||||
|
void showFinishedHook() override;
|
||||||
|
void doSetInnerFocus() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onScroll();
|
||||||
|
void updateInnerVisibleArea();
|
||||||
|
void updateControlsGeometry();
|
||||||
|
void updateAdaptiveLayout();
|
||||||
|
void saveState(not_null<ScheduledMemento*> memento);
|
||||||
|
void restoreState(not_null<ScheduledMemento*> memento);
|
||||||
|
void showAtPosition(Data::MessagePosition position);
|
||||||
|
bool showAtPositionNow(Data::MessagePosition position);
|
||||||
|
|
||||||
|
void setupScrollDownButton();
|
||||||
|
void scrollDownClicked();
|
||||||
|
void scrollDownAnimationFinish();
|
||||||
|
void updateScrollDownVisibility();
|
||||||
|
void updateScrollDownPosition();
|
||||||
|
|
||||||
|
void confirmDeleteSelected();
|
||||||
|
void clearSelected();
|
||||||
|
|
||||||
|
const not_null<History*> _history;
|
||||||
|
object_ptr<Ui::ScrollArea> _scroll;
|
||||||
|
QPointer<ListWidget> _inner;
|
||||||
|
object_ptr<TopBarWidget> _topBar;
|
||||||
|
object_ptr<Ui::PlainShadow> _topBarShadow;
|
||||||
|
bool _skipScrollEvent = false;
|
||||||
|
|
||||||
|
FullMsgId _highlightMessageId;
|
||||||
|
std::optional<Data::MessagePosition> _nextAnimatedScrollPosition;
|
||||||
|
int _nextAnimatedScrollDelta = 0;
|
||||||
|
|
||||||
|
Ui::Animations::Simple _scrollDownShown;
|
||||||
|
bool _scrollDownIsShown = false;
|
||||||
|
object_ptr<Ui::HistoryDownButton> _scrollDown;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScheduledMemento : public Window::SectionMemento {
|
||||||
|
public:
|
||||||
|
ScheduledMemento(not_null<History*> history)
|
||||||
|
: _history(history)
|
||||||
|
, _list({}) {
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ptr<Window::SectionWidget> createWidget(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
Window::Column column,
|
||||||
|
const QRect &geometry) override;
|
||||||
|
|
||||||
|
not_null<History*> getHistory() const {
|
||||||
|
return _history;
|
||||||
|
}
|
||||||
|
|
||||||
|
not_null<ListMemento*> list() {
|
||||||
|
return &_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const not_null<History*> _history;
|
||||||
|
ListMemento _list;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HistoryScheduled
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_chat.h"
|
#include "data/data_chat.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
#include "data/data_scheduled_messages.h"
|
||||||
#include "ui/special_buttons.h"
|
#include "ui/special_buttons.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
|
|
|
@ -330,6 +330,8 @@
|
||||||
<(src_loc)/history/view/history_view_message.cpp
|
<(src_loc)/history/view/history_view_message.cpp
|
||||||
<(src_loc)/history/view/history_view_message.h
|
<(src_loc)/history/view/history_view_message.h
|
||||||
<(src_loc)/history/view/history_view_object.h
|
<(src_loc)/history/view/history_view_object.h
|
||||||
|
<(src_loc)/history/view/history_view_scheduled_section.cpp
|
||||||
|
<(src_loc)/history/view/history_view_scheduled_section.h
|
||||||
<(src_loc)/history/view/history_view_service_message.cpp
|
<(src_loc)/history/view/history_view_service_message.cpp
|
||||||
<(src_loc)/history/view/history_view_service_message.h
|
<(src_loc)/history/view/history_view_service_message.h
|
||||||
<(src_loc)/history/view/history_view_top_bar_widget.cpp
|
<(src_loc)/history/view/history_view_top_bar_widget.cpp
|
||||||
|
|
Loading…
Reference in New Issue