diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 091cf0610..a562c678a 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3702,6 +3702,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_view_button_background" = "View background"; "lng_view_button_theme" = "View theme"; "lng_view_button_message" = "View message"; +"lng_view_button_story" = "View story"; "lng_view_button_voice_chat" = "Voice chat"; "lng_view_button_voice_chat_channel" = "Live stream"; "lng_view_button_request_join" = "Request to Join"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index ea70c516b..c906e9c1e 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -779,7 +779,7 @@ QString ApiWrap::exportDirectStoryLink(not_null story) { const auto fallback = [&] { const auto base = user->username(); const auto story = QString::number(storyId.story); - const auto query = base + "/s" + story; + const auto query = base + "/s/" + story; return session().createInternalLinkFull(query); }; const auto i = _unlikelyStoryLinks.find(storyId); diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index 8cdaebc25..9e55643b0 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -1982,11 +1982,16 @@ MediaStory::MediaStory(not_null parent, FullStoryId storyId) : Media(parent) , _storyId(storyId) { const auto stories = &parent->history()->owner().stories(); - const auto maybeStory = stories->lookup(storyId); - if (!maybeStory) { + if (const auto maybeStory = stories->lookup(storyId)) { + parent->setText((*maybeStory)->caption()); + } else { if (maybeStory.error() == NoStory::Unknown) { stories->resolve(storyId, crl::guard(this, [=] { - _expired = !stories->lookup(storyId); + if (const auto maybeStory = stories->lookup(storyId)) { + parent->setText((*maybeStory)->caption()); + } else { + _expired = true; + } parent->history()->owner().requestItemViewRefresh(parent); })); } else { @@ -2052,6 +2057,7 @@ std::unique_ptr MediaStory::createView( const auto stories = &parent()->history()->owner().stories(); const auto maybeStory = stories->lookup(_storyId); if (!maybeStory) { + realParent->setText(TextWithEntities()); if (maybeStory.error() == Data::NoStory::Deleted) { _expired = true; return nullptr; @@ -2065,6 +2071,7 @@ std::unique_ptr MediaStory::createView( } _expired = false; const auto story = *maybeStory; + realParent->setText(story->caption()); if (const auto photo = story->photo()) { return std::make_unique( message, diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index ebc7ef8ee..2023c9b67 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -3215,6 +3215,7 @@ not_null Session::processWebpage(const MTPDwebPagePending &data) { QString(), QString(), TextWithEntities(), + FullStoryId(), nullptr, nullptr, WebPageCollage(), @@ -3269,6 +3270,7 @@ not_null Session::webpage( siteName, title, description, + FullStoryId(), photo, document, std::move(collage), @@ -3321,16 +3323,55 @@ void Session::webpageApplyFields( } return nullptr; }; + auto story = (Data::Story*)nullptr; + auto storyId = FullStoryId(); + if (const auto attributes = data.vattributes()) { + for (const auto &attribute : attributes->v) { + attribute.match([&](const MTPDwebPageAttributeStory &data) { + storyId = FullStoryId{ + peerFromUser(data.vuser_id()), + data.vid().v, + }; + if (const auto embed = data.vstory()) { + story = stories().applyFromWebpage( + peerFromUser(data.vuser_id()), + *embed); + } else if (const auto maybe = stories().lookup(storyId)) { + story = *maybe; + } else if (maybe.error() == Data::NoStory::Unknown) { + stories().resolve(storyId, [=] { + if (const auto maybe = stories().lookup(storyId)) { + const auto story = *maybe; + page->document = story->document(); + page->photo = story->photo(); + page->description = story->caption(); + page->type = WebPageType::Story; + notifyWebPageUpdateDelayed(page); + } + }); + } + }, [](const auto &) {}); + } + } webpageApplyFields( page, - ParseWebPageType(data), + (story ? WebPageType::Story : ParseWebPageType(data)), qs(data.vurl()), qs(data.vdisplay_url()), siteName, qs(data.vtitle().value_or_empty()), - description, - photo ? processPhoto(*photo).get() : nullptr, - document ? processDocument(*document).get() : lookupThemeDocument(), + (story ? story->caption() : description), + storyId, + (story + ? story->photo() + : photo + ? processPhoto(*photo).get() + : nullptr), + (story + ? story->document() + : document + ? processDocument(*document).get() + : lookupThemeDocument()), WebPageCollage(this, data), data.vduration().value_or_empty(), qs(data.vauthor().value_or_empty()), @@ -3345,6 +3386,7 @@ void Session::webpageApplyFields( const QString &siteName, const QString &title, const TextWithEntities &description, + FullStoryId storyId, PhotoData *photo, DocumentData *document, WebPageCollage &&collage, @@ -3359,6 +3401,7 @@ void Session::webpageApplyFields( siteName, title, description, + storyId, photo, document, std::move(collage), diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 154b1b73f..c287713d3 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -811,6 +811,7 @@ private: const QString &siteName, const QString &title, const TextWithEntities &description, + FullStoryId storyId, PhotoData *photo, DocumentData *document, WebPageCollage &&collage, diff --git a/Telegram/SourceFiles/data/data_stories.cpp b/Telegram/SourceFiles/data/data_stories.cpp index 8b27104f4..8ac462e05 100644 --- a/Telegram/SourceFiles/data/data_stories.cpp +++ b/Telegram/SourceFiles/data/data_stories.cpp @@ -455,6 +455,17 @@ void Stories::apply(not_null peer, const MTPUserStories *data) { } } +Story *Stories::applyFromWebpage(PeerId peerId, const MTPstoryItem &story) { + const auto idDates = parseAndApply( + _owner->peer(peerId), + story, + base::unixtime::now()); + const auto value = idDates + ? lookup({ peerId, idDates.id }) + : base::make_unexpected(NoStory::Deleted); + return value ? value->get() : nullptr; +} + void Stories::requestUserStories(not_null user) { if (!_requestingUserStories.emplace(user).second) { return; diff --git a/Telegram/SourceFiles/data/data_stories.h b/Telegram/SourceFiles/data/data_stories.h index 3199ff82f..2cd0dcccf 100644 --- a/Telegram/SourceFiles/data/data_stories.h +++ b/Telegram/SourceFiles/data/data_stories.h @@ -244,6 +244,7 @@ public: void loadMore(StorySourcesList list); void apply(const MTPDupdateStory &data); void apply(not_null peer, const MTPUserStories *data); + Story *applyFromWebpage(PeerId peerId, const MTPstoryItem &story); void loadAround(FullStoryId id, StoriesContext context); const StoriesSource *source(PeerId id) const; diff --git a/Telegram/SourceFiles/data/data_web_page.cpp b/Telegram/SourceFiles/data/data_web_page.cpp index 57b31d0f6..4a7b036e3 100644 --- a/Telegram/SourceFiles/data/data_web_page.cpp +++ b/Telegram/SourceFiles/data/data_web_page.cpp @@ -152,6 +152,8 @@ WebPageType ParseWebPageType( return WebPageType::WallPaper; } else if (type == u"telegram_theme"_q) { return WebPageType::Theme; + } else if (type == u"telegram_story"_q) { + return WebPageType::Story; } else if (type == u"telegram_channel"_q) { return WebPageType::Channel; } else if (type == u"telegram_channel_request"_q) { @@ -214,6 +216,7 @@ bool WebPageData::applyChanges( const QString &newSiteName, const QString &newTitle, const TextWithEntities &newDescription, + FullStoryId newStoryId, PhotoData *newPhoto, DocumentData *newDocument, WebPageCollage &&newCollage, @@ -254,6 +257,7 @@ bool WebPageData::applyChanges( && siteName == resultSiteName && title == resultTitle && description.text == newDescription.text + && storyId == newStoryId && photo == newPhoto && document == newDocument && collage.items == newCollage.items @@ -271,6 +275,7 @@ bool WebPageData::applyChanges( siteName = resultSiteName; title = resultTitle; description = newDescription; + storyId = newStoryId; photo = newPhoto; document = newDocument; collage = std::move(newCollage); diff --git a/Telegram/SourceFiles/data/data_web_page.h b/Telegram/SourceFiles/data/data_web_page.h index 8481a7b3b..83e7bde80 100644 --- a/Telegram/SourceFiles/data/data_web_page.h +++ b/Telegram/SourceFiles/data/data_web_page.h @@ -35,6 +35,7 @@ enum class WebPageType { WallPaper, Theme, + Story, Article, ArticleWithIV, @@ -70,6 +71,7 @@ struct WebPageData { const QString &newSiteName, const QString &newTitle, const TextWithEntities &newDescription, + FullStoryId newStoryId, PhotoData *newPhoto, DocumentData *newDocument, WebPageCollage &&newCollage, @@ -89,6 +91,7 @@ struct WebPageData { QString siteName; QString title; TextWithEntities description; + FullStoryId storyId; int duration = 0; QString author; PhotoData *photo = nullptr; diff --git a/Telegram/SourceFiles/history/view/history_view_view_button.cpp b/Telegram/SourceFiles/history/view/history_view_view_button.cpp index 1a2db4d6b..d7d406f4b 100644 --- a/Telegram/SourceFiles/history/view/history_view_view_button.cpp +++ b/Telegram/SourceFiles/history/view/history_view_view_button.cpp @@ -52,6 +52,8 @@ inline auto WebPageToPhrase(not_null webpage) { const auto type = webpage->type; return Ui::Text::Upper((type == WebPageType::Theme) ? tr::lng_view_button_theme(tr::now) + : (type == WebPageType::Story) + ? tr::lng_view_button_story(tr::now) : (type == WebPageType::Message) ? tr::lng_view_button_message(tr::now) : (type == WebPageType::Group) @@ -139,6 +141,8 @@ bool ViewButton::MediaHasViewButton( || ((type == WebPageType::Theme) && webpage->document && webpage->document->isTheme()) + || ((type == WebPageType::Story) + && (webpage->photo || webpage->document)) || ((type == WebPageType::WallPaper) && webpage->document && webpage->document->isWallPaper()); diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp index 3b909485f..cec353017 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp @@ -168,6 +168,7 @@ QSize WebPage::countOptimalSize() { && _data->photo && _data->type != WebPageType::Photo && _data->type != WebPageType::Document + && _data->type != WebPageType::Story && _data->type != WebPageType::Video) { if (_data->type == WebPageType::Profile) { _asArticle = true;