diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index b3b8e83a7..c48da093a 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2119,8 +2119,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_recommended_message_title" = "Recommended"; "lng_edited" = "edited"; "lng_commented" = "commented"; +"lng_approximate" = "appx."; "lng_edited_date" = "Edited: {date}"; "lng_sent_date" = "Sent: {date}"; +"lng_approximate_about" = "Estimated date of video publishing."; "lng_views_tooltip#one" = "Views: {count}"; "lng_views_tooltip#other" = "Views: {count}"; "lng_forwards_tooltip#one" = "Shares: {count}"; diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 3bbab8cf4..fc4644aae 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -316,6 +316,9 @@ void Updates::feedUpdateVector( } else if (policy == SkipUpdatePolicy::SkipExceptGroupCallParticipants) { return; } + if (policy == SkipUpdatePolicy::SkipNone) { + applyConvertToScheduledOnSend(updates); + } for (const auto &entry : std::as_const(list)) { const auto type = entry.type(); if ((policy == SkipUpdatePolicy::SkipMessageIds @@ -432,6 +435,7 @@ void Updates::feedChannelDifference( session().data().processChats(data.vchats()); _handlingChannelDifference = true; + applyConvertToScheduledOnSend(data.vother_updates()); feedMessageIds(data.vother_updates()); session().data().processMessages( data.vnew_messages(), @@ -596,6 +600,7 @@ void Updates::feedDifference( Core::App().checkAutoLock(); session().data().processUsers(users); session().data().processChats(chats); + applyConvertToScheduledOnSend(other); feedMessageIds(other); session().data().processMessages(msgs, NewMessageType::Unread); feedUpdateVector(other, SkipUpdatePolicy::SkipMessageIds); @@ -881,6 +886,39 @@ void Updates::mtpUpdateReceived(const MTPUpdates &updates) { } } +void Updates::applyConvertToScheduledOnSend( + const MTPVector &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) { updates.match([&](const MTPDupdates &data) { session().data().processUsers(data.vusers()); diff --git a/Telegram/SourceFiles/api/api_updates.h b/Telegram/SourceFiles/api/api_updates.h index 654e36b51..41bec419c 100644 --- a/Telegram/SourceFiles/api/api_updates.h +++ b/Telegram/SourceFiles/api/api_updates.h @@ -131,6 +131,7 @@ private: // Doesn't call sendHistoryChangeNotifications itself. void feedUpdate(const MTPUpdate &update); + void applyConvertToScheduledOnSend(const MTPVector &other); void applyGroupCallParticipantUpdates(const MTPUpdates &updates); bool whenGetDiffChanged( diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 14be85c06..b45bb0bed 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -4813,6 +4813,14 @@ void Session::viewTagsChanged( } } +void Session::sentToScheduled(SentToScheduled value) { + _sentToScheduled.fire(std::move(value)); +} + +rpl::producer Session::sentToScheduled() const { + return _sentToScheduled.events(); +} + void Session::clearLocalStorage() { _cache->close(); _cache->clear(); diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 654cfdba3..b1b550d37 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -89,6 +89,11 @@ struct GiftUpdate { Action action = {}; }; +struct SentToScheduled { + not_null item; + MsgId scheduledId = 0; +}; + class Session final { public: using ViewElement = HistoryView::Element; @@ -791,6 +796,9 @@ public: std::vector &&was, std::vector &&now); + void sentToScheduled(SentToScheduled value); + [[nodiscard]] rpl::producer sentToScheduled() const; + void clearLocalStorage(); private: @@ -963,6 +971,7 @@ private: rpl::event_stream _chatListEntryRefreshes; rpl::event_stream<> _unreadBadgeChanges; rpl::event_stream _repliesReadTillUpdates; + rpl::event_stream _sentToScheduled; Dialogs::MainList _chatsList; Dialogs::IndexedList _contactsList; diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index fbcdf3e3f..df62562ab 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -327,6 +327,8 @@ enum class MessageFlag : uint64 { SensitiveContent = (1ULL << 47), HasRestrictions = (1ULL << 48), + + EstimatedDate = (1ULL << 49), }; inline constexpr bool is_flag_type(MessageFlag) { return true; } using MessageFlags = base::flags; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index afdeb386c..8c0185f28 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -761,6 +761,10 @@ TimeId HistoryItem::date() const { return _date; } +bool HistoryItem::awaitingVideoProcessing() const { + return (_flags & MessageFlag::EstimatedDate); +} + HistoryServiceDependentData *HistoryItem::GetServiceDependentData() { if (const auto pinned = Get()) { return pinned; diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 169295c92..6182fa60c 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -482,6 +482,7 @@ public: [[nodiscard]] GlobalMsgId globalId() const; [[nodiscard]] Data::MessagePosition position() const; [[nodiscard]] TimeId date() const; + [[nodiscard]] bool awaitingVideoProcessing() const; [[nodiscard]] Data::Media *media() const { return _media.get(); diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 751a81f39..06ca6628c 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -451,7 +451,10 @@ MessageFlags FlagsFromMTP( : Flag()) | ((flags & MTP::f_views) ? Flag::HasViews : 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( diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 0ce64dedf..31d2a1362 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -723,6 +723,21 @@ HistoryWidget::HistoryWidget( maybeMarkReactionsRead(update.item); }, 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( + history, + id)); + }); + return; + } + }, lifetime()); + using MediaSwitch = Media::Player::Instance::Switch; Media::Player::instance()->switchToNextEvents( ) | rpl::filter([=](const MediaSwitch &pair) { diff --git a/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp b/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp index 6784c7eca..361e1ee51 100644 --- a/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp +++ b/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp @@ -407,6 +407,8 @@ void BottomInfo::layout() { void BottomInfo::layoutDateText() { const auto edited = (_data.flags & Data::Flag::Edited) ? (tr::lng_edited(tr::now) + ' ') + : (_data.flags & Data::Flag::EstimateDate) + ? (tr::lng_approximate(tr::now) + ' ') : QString(); const auto author = _data.author; const auto prefix = !author.isEmpty() ? u", "_q : QString(); @@ -601,6 +603,9 @@ BottomInfo::Data BottomInfoDataFromMessage(not_null message) { if (forwarded && forwarded->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. //if (item->unread()) { // result.flags |= Flag::Unread; diff --git a/Telegram/SourceFiles/history/view/history_view_bottom_info.h b/Telegram/SourceFiles/history/view/history_view_bottom_info.h index 594a488f1..32e3e8fcd 100644 --- a/Telegram/SourceFiles/history/view/history_view_bottom_info.h +++ b/Telegram/SourceFiles/history/view/history_view_bottom_info.h @@ -32,15 +32,16 @@ struct TextState; class BottomInfo final : public Object { public: struct Data { - enum class Flag : uchar { - Edited = 0x01, - OutLayout = 0x02, - Sending = 0x04, - RepliesContext = 0x08, - Sponsored = 0x10, - Pinned = 0x20, - Imported = 0x40, - Shortcut = 0x80, + enum class Flag : uint16 { + Edited = 0x001, + OutLayout = 0x002, + Sending = 0x004, + RepliesContext = 0x008, + Sponsored = 0x010, + Pinned = 0x020, + Imported = 0x040, + Shortcut = 0x080, + EstimateDate = 0x100, //Unread, // We don't want to pass and update it in Date for now. }; friend inline constexpr bool is_flag_type(Flag) { return true; }; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 880b58f75..95d5e7a29 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -264,6 +264,9 @@ QString DateTooltipText(not_null view) { const auto format = QLocale::LongFormat; const auto item = view->data(); auto dateText = locale.toString(view->dateTime(), format); + if (item->awaitingVideoProcessing()) { + dateText += '\n' + tr::lng_approximate_about(tr::now); + } if (const auto editedDate = view->displayedEditDate()) { dateText += '\n' + tr::lng_edited_date( tr::now, diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 31b31d01d..0d56c275b 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -56,18 +56,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { -ScheduledMemento::ScheduledMemento(not_null history) - : _history(history) - , _forumTopic(nullptr) { +ScheduledMemento::ScheduledMemento( + not_null history, + MsgId sentToScheduledId) +: _history(history) +, _forumTopic(nullptr) +, _sentToScheduledId(sentToScheduledId) { const auto list = _history->session().scheduledMessages().list(_history); - if (!list.ids.empty()) { - _list.setScrollTopState({ .item = {.fullId = list.ids.front() } }); + if (sentToScheduledId) { + _list.setScrollTopState({ + .item = { .fullId = { _history->peer->id, sentToScheduledId } }, + }); + } else if (!list.ids.empty()) { + _list.setScrollTopState({ .item = { .fullId = list.ids.front() } }); } } ScheduledMemento::ScheduledMemento(not_null forumTopic) - : _history(forumTopic->owningHistory()) - , _forumTopic(forumTopic) { +: _history(forumTopic->owningHistory()) +, _forumTopic(forumTopic) { const auto list = _history->session().scheduledMessages().list( _forumTopic); if (!list.ids.empty()) { diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h index 290b11c73..b761c7a40 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h @@ -288,7 +288,9 @@ private: class ScheduledMemento final : public Window::SectionMemento { public: - ScheduledMemento(not_null history); + ScheduledMemento( + not_null history, + MsgId sentToScheduledId = 0); ScheduledMemento(not_null forumTopic); object_ptr createWidget( @@ -309,6 +311,7 @@ private: const not_null _history; const Data::ForumTopic *_forumTopic; ListMemento _list; + MsgId _sentToScheduledId; };