Jump-to-scheduled on video processing.

This commit is contained in:
John Preston 2024-10-29 13:20:42 +04:00
parent b9ebb02e72
commit 3137c9f3f7
15 changed files with 120 additions and 18 deletions

View file

@ -2119,8 +2119,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_recommended_message_title" = "Recommended"; "lng_recommended_message_title" = "Recommended";
"lng_edited" = "edited"; "lng_edited" = "edited";
"lng_commented" = "commented"; "lng_commented" = "commented";
"lng_approximate" = "appx.";
"lng_edited_date" = "Edited: {date}"; "lng_edited_date" = "Edited: {date}";
"lng_sent_date" = "Sent: {date}"; "lng_sent_date" = "Sent: {date}";
"lng_approximate_about" = "Estimated date of video publishing.";
"lng_views_tooltip#one" = "Views: {count}"; "lng_views_tooltip#one" = "Views: {count}";
"lng_views_tooltip#other" = "Views: {count}"; "lng_views_tooltip#other" = "Views: {count}";
"lng_forwards_tooltip#one" = "Shares: {count}"; "lng_forwards_tooltip#one" = "Shares: {count}";

View file

@ -316,6 +316,9 @@ void Updates::feedUpdateVector(
} else if (policy == SkipUpdatePolicy::SkipExceptGroupCallParticipants) { } else if (policy == SkipUpdatePolicy::SkipExceptGroupCallParticipants) {
return; return;
} }
if (policy == SkipUpdatePolicy::SkipNone) {
applyConvertToScheduledOnSend(updates);
}
for (const auto &entry : std::as_const(list)) { for (const auto &entry : std::as_const(list)) {
const auto type = entry.type(); const auto type = entry.type();
if ((policy == SkipUpdatePolicy::SkipMessageIds if ((policy == SkipUpdatePolicy::SkipMessageIds
@ -432,6 +435,7 @@ void Updates::feedChannelDifference(
session().data().processChats(data.vchats()); session().data().processChats(data.vchats());
_handlingChannelDifference = true; _handlingChannelDifference = true;
applyConvertToScheduledOnSend(data.vother_updates());
feedMessageIds(data.vother_updates()); feedMessageIds(data.vother_updates());
session().data().processMessages( session().data().processMessages(
data.vnew_messages(), data.vnew_messages(),
@ -596,6 +600,7 @@ void Updates::feedDifference(
Core::App().checkAutoLock(); Core::App().checkAutoLock();
session().data().processUsers(users); session().data().processUsers(users);
session().data().processChats(chats); session().data().processChats(chats);
applyConvertToScheduledOnSend(other);
feedMessageIds(other); feedMessageIds(other);
session().data().processMessages(msgs, NewMessageType::Unread); session().data().processMessages(msgs, NewMessageType::Unread);
feedUpdateVector(other, SkipUpdatePolicy::SkipMessageIds); feedUpdateVector(other, SkipUpdatePolicy::SkipMessageIds);
@ -881,6 +886,39 @@ void Updates::mtpUpdateReceived(const MTPUpdates &updates) {
} }
} }
void Updates::applyConvertToScheduledOnSend(
const MTPVector<MTPUpdate> &other) {
for (const auto &update : other.v) {
update.match([&](const MTPDupdateNewScheduledMessage &data) {
const auto id = IdFromMessage(data.vmessage());
const auto scheduledMessages = &_session->scheduledMessages();
const auto scheduledId = scheduledMessages->localMessageId(id);
for (const auto &updateId : other.v) {
updateId.match([&](const MTPDupdateMessageID &dataId) {
if (dataId.vid().v == id) {
const auto rand = dataId.vrandom_id().v;
auto &owner = session().data();
const auto localId = owner.messageIdByRandomId(rand);
if (const auto local = owner.message(localId)) {
if (!local->isScheduled()) {
using Flag = Data::MessageUpdate::Flag;
_session->data().sentToScheduled({
.item = local,
.scheduledId = scheduledId,
});
// We've sent a non-scheduled message,
// but it was converted to a scheduled.
local->destroy();
}
}
}
}, [](const auto &) {});
}
}, [](const auto &) {});
}
}
void Updates::applyGroupCallParticipantUpdates(const MTPUpdates &updates) { void Updates::applyGroupCallParticipantUpdates(const MTPUpdates &updates) {
updates.match([&](const MTPDupdates &data) { updates.match([&](const MTPDupdates &data) {
session().data().processUsers(data.vusers()); session().data().processUsers(data.vusers());

View file

@ -131,6 +131,7 @@ private:
// Doesn't call sendHistoryChangeNotifications itself. // Doesn't call sendHistoryChangeNotifications itself.
void feedUpdate(const MTPUpdate &update); void feedUpdate(const MTPUpdate &update);
void applyConvertToScheduledOnSend(const MTPVector<MTPUpdate> &other);
void applyGroupCallParticipantUpdates(const MTPUpdates &updates); void applyGroupCallParticipantUpdates(const MTPUpdates &updates);
bool whenGetDiffChanged( bool whenGetDiffChanged(

View file

@ -4813,6 +4813,14 @@ void Session::viewTagsChanged(
} }
} }
void Session::sentToScheduled(SentToScheduled value) {
_sentToScheduled.fire(std::move(value));
}
rpl::producer<SentToScheduled> Session::sentToScheduled() const {
return _sentToScheduled.events();
}
void Session::clearLocalStorage() { void Session::clearLocalStorage() {
_cache->close(); _cache->close();
_cache->clear(); _cache->clear();

View file

@ -89,6 +89,11 @@ struct GiftUpdate {
Action action = {}; Action action = {};
}; };
struct SentToScheduled {
not_null<HistoryItem*> item;
MsgId scheduledId = 0;
};
class Session final { class Session final {
public: public:
using ViewElement = HistoryView::Element; using ViewElement = HistoryView::Element;
@ -791,6 +796,9 @@ public:
std::vector<ReactionId> &&was, std::vector<ReactionId> &&was,
std::vector<ReactionId> &&now); std::vector<ReactionId> &&now);
void sentToScheduled(SentToScheduled value);
[[nodiscard]] rpl::producer<SentToScheduled> sentToScheduled() const;
void clearLocalStorage(); void clearLocalStorage();
private: private:
@ -963,6 +971,7 @@ private:
rpl::event_stream<ChatListEntryRefresh> _chatListEntryRefreshes; rpl::event_stream<ChatListEntryRefresh> _chatListEntryRefreshes;
rpl::event_stream<> _unreadBadgeChanges; rpl::event_stream<> _unreadBadgeChanges;
rpl::event_stream<RepliesReadTillUpdate> _repliesReadTillUpdates; rpl::event_stream<RepliesReadTillUpdate> _repliesReadTillUpdates;
rpl::event_stream<SentToScheduled> _sentToScheduled;
Dialogs::MainList _chatsList; Dialogs::MainList _chatsList;
Dialogs::IndexedList _contactsList; Dialogs::IndexedList _contactsList;

View file

@ -327,6 +327,8 @@ enum class MessageFlag : uint64 {
SensitiveContent = (1ULL << 47), SensitiveContent = (1ULL << 47),
HasRestrictions = (1ULL << 48), HasRestrictions = (1ULL << 48),
EstimatedDate = (1ULL << 49),
}; };
inline constexpr bool is_flag_type(MessageFlag) { return true; } inline constexpr bool is_flag_type(MessageFlag) { return true; }
using MessageFlags = base::flags<MessageFlag>; using MessageFlags = base::flags<MessageFlag>;

View file

@ -761,6 +761,10 @@ TimeId HistoryItem::date() const {
return _date; return _date;
} }
bool HistoryItem::awaitingVideoProcessing() const {
return (_flags & MessageFlag::EstimatedDate);
}
HistoryServiceDependentData *HistoryItem::GetServiceDependentData() { HistoryServiceDependentData *HistoryItem::GetServiceDependentData() {
if (const auto pinned = Get<HistoryServicePinned>()) { if (const auto pinned = Get<HistoryServicePinned>()) {
return pinned; return pinned;

View file

@ -482,6 +482,7 @@ public:
[[nodiscard]] GlobalMsgId globalId() const; [[nodiscard]] GlobalMsgId globalId() const;
[[nodiscard]] Data::MessagePosition position() const; [[nodiscard]] Data::MessagePosition position() const;
[[nodiscard]] TimeId date() const; [[nodiscard]] TimeId date() const;
[[nodiscard]] bool awaitingVideoProcessing() const;
[[nodiscard]] Data::Media *media() const { [[nodiscard]] Data::Media *media() const {
return _media.get(); return _media.get();

View file

@ -451,7 +451,10 @@ MessageFlags FlagsFromMTP(
: Flag()) : Flag())
| ((flags & MTP::f_views) ? Flag::HasViews : Flag()) | ((flags & MTP::f_views) ? Flag::HasViews : Flag())
| ((flags & MTP::f_noforwards) ? Flag::NoForwards : Flag()) | ((flags & MTP::f_noforwards) ? Flag::NoForwards : Flag())
| ((flags & MTP::f_invert_media) ? Flag::InvertMedia : Flag()); | ((flags & MTP::f_invert_media) ? Flag::InvertMedia : Flag())
| ((flags & MTP::f_video_processing_pending)
? Flag::EstimatedDate
: Flag());
} }
MessageFlags FlagsFromMTP( MessageFlags FlagsFromMTP(

View file

@ -723,6 +723,21 @@ HistoryWidget::HistoryWidget(
maybeMarkReactionsRead(update.item); maybeMarkReactionsRead(update.item);
}, lifetime()); }, lifetime());
session().data().sentToScheduled(
) | rpl::start_with_next([=](const Data::SentToScheduled &value) {
if (value.item->history() == _history) {
const auto history = value.item->history();
const auto id = value.scheduledId;
crl::on_main(this, [=] {
controller->showSection(
std::make_shared<HistoryView::ScheduledMemento>(
history,
id));
});
return;
}
}, lifetime());
using MediaSwitch = Media::Player::Instance::Switch; using MediaSwitch = Media::Player::Instance::Switch;
Media::Player::instance()->switchToNextEvents( Media::Player::instance()->switchToNextEvents(
) | rpl::filter([=](const MediaSwitch &pair) { ) | rpl::filter([=](const MediaSwitch &pair) {

View file

@ -407,6 +407,8 @@ void BottomInfo::layout() {
void BottomInfo::layoutDateText() { void BottomInfo::layoutDateText() {
const auto edited = (_data.flags & Data::Flag::Edited) const auto edited = (_data.flags & Data::Flag::Edited)
? (tr::lng_edited(tr::now) + ' ') ? (tr::lng_edited(tr::now) + ' ')
: (_data.flags & Data::Flag::EstimateDate)
? (tr::lng_approximate(tr::now) + ' ')
: QString(); : QString();
const auto author = _data.author; const auto author = _data.author;
const auto prefix = !author.isEmpty() ? u", "_q : QString(); const auto prefix = !author.isEmpty() ? u", "_q : QString();
@ -601,6 +603,9 @@ BottomInfo::Data BottomInfoDataFromMessage(not_null<Message*> message) {
if (forwarded && forwarded->imported) { if (forwarded && forwarded->imported) {
result.flags |= Flag::Imported; result.flags |= Flag::Imported;
} }
if (item->awaitingVideoProcessing()) {
result.flags |= Flag::EstimateDate;
}
// We don't want to pass and update it in Data for now. // We don't want to pass and update it in Data for now.
//if (item->unread()) { //if (item->unread()) {
// result.flags |= Flag::Unread; // result.flags |= Flag::Unread;

View file

@ -32,15 +32,16 @@ struct TextState;
class BottomInfo final : public Object { class BottomInfo final : public Object {
public: public:
struct Data { struct Data {
enum class Flag : uchar { enum class Flag : uint16 {
Edited = 0x01, Edited = 0x001,
OutLayout = 0x02, OutLayout = 0x002,
Sending = 0x04, Sending = 0x004,
RepliesContext = 0x08, RepliesContext = 0x008,
Sponsored = 0x10, Sponsored = 0x010,
Pinned = 0x20, Pinned = 0x020,
Imported = 0x40, Imported = 0x040,
Shortcut = 0x80, Shortcut = 0x080,
EstimateDate = 0x100,
//Unread, // We don't want to pass and update it in Date for now. //Unread, // We don't want to pass and update it in Date for now.
}; };
friend inline constexpr bool is_flag_type(Flag) { return true; }; friend inline constexpr bool is_flag_type(Flag) { return true; };

View file

@ -264,6 +264,9 @@ QString DateTooltipText(not_null<Element*> view) {
const auto format = QLocale::LongFormat; const auto format = QLocale::LongFormat;
const auto item = view->data(); const auto item = view->data();
auto dateText = locale.toString(view->dateTime(), format); auto dateText = locale.toString(view->dateTime(), format);
if (item->awaitingVideoProcessing()) {
dateText += '\n' + tr::lng_approximate_about(tr::now);
}
if (const auto editedDate = view->displayedEditDate()) { if (const auto editedDate = view->displayedEditDate()) {
dateText += '\n' + tr::lng_edited_date( dateText += '\n' + tr::lng_edited_date(
tr::now, tr::now,

View file

@ -56,18 +56,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView { namespace HistoryView {
ScheduledMemento::ScheduledMemento(not_null<History*> history) ScheduledMemento::ScheduledMemento(
: _history(history) not_null<History*> history,
, _forumTopic(nullptr) { MsgId sentToScheduledId)
: _history(history)
, _forumTopic(nullptr)
, _sentToScheduledId(sentToScheduledId) {
const auto list = _history->session().scheduledMessages().list(_history); const auto list = _history->session().scheduledMessages().list(_history);
if (!list.ids.empty()) { if (sentToScheduledId) {
_list.setScrollTopState({ .item = {.fullId = list.ids.front() } }); _list.setScrollTopState({
.item = { .fullId = { _history->peer->id, sentToScheduledId } },
});
} else if (!list.ids.empty()) {
_list.setScrollTopState({ .item = { .fullId = list.ids.front() } });
} }
} }
ScheduledMemento::ScheduledMemento(not_null<Data::ForumTopic*> forumTopic) ScheduledMemento::ScheduledMemento(not_null<Data::ForumTopic*> forumTopic)
: _history(forumTopic->owningHistory()) : _history(forumTopic->owningHistory())
, _forumTopic(forumTopic) { , _forumTopic(forumTopic) {
const auto list = _history->session().scheduledMessages().list( const auto list = _history->session().scheduledMessages().list(
_forumTopic); _forumTopic);
if (!list.ids.empty()) { if (!list.ids.empty()) {

View file

@ -288,7 +288,9 @@ private:
class ScheduledMemento final : public Window::SectionMemento { class ScheduledMemento final : public Window::SectionMemento {
public: public:
ScheduledMemento(not_null<History*> history); ScheduledMemento(
not_null<History*> history,
MsgId sentToScheduledId = 0);
ScheduledMemento(not_null<Data::ForumTopic*> forumTopic); ScheduledMemento(not_null<Data::ForumTopic*> forumTopic);
object_ptr<Window::SectionWidget> createWidget( object_ptr<Window::SectionWidget> createWidget(
@ -309,6 +311,7 @@ private:
const not_null<History*> _history; const not_null<History*> _history;
const Data::ForumTopic *_forumTopic; const Data::ForumTopic *_forumTopic;
ListMemento _list; ListMemento _list;
MsgId _sentToScheduledId;
}; };