Display shared stories in message history.
This commit is contained in:
parent
d7186e68e2
commit
c133f4de69
|
@ -1503,6 +1503,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_action_pinned_media_sticker" = "a sticker";
|
"lng_action_pinned_media_sticker" = "a sticker";
|
||||||
"lng_action_pinned_media_emoji_sticker" = "a {emoji} sticker";
|
"lng_action_pinned_media_emoji_sticker" = "a {emoji} sticker";
|
||||||
"lng_action_pinned_media_game" = "the game «{game}»";
|
"lng_action_pinned_media_game" = "the game «{game}»";
|
||||||
|
"lng_action_pinned_media_story" = "a story";
|
||||||
"lng_action_game_score#one" = "{from} scored {count} in {game}";
|
"lng_action_game_score#one" = "{from} scored {count} in {game}";
|
||||||
"lng_action_game_score#other" = "{from} scored {count} in {game}";
|
"lng_action_game_score#other" = "{from} scored {count} in {game}";
|
||||||
"lng_action_game_you_scored#one" = "You scored {count} in {game}";
|
"lng_action_game_you_scored#one" = "You scored {count} in {game}";
|
||||||
|
@ -3810,6 +3811,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_stories_archive_button" = "Archive";
|
"lng_stories_archive_button" = "Archive";
|
||||||
"lng_stories_archive_title" = "Stories Archive";
|
"lng_stories_archive_title" = "Stories Archive";
|
||||||
|
|
||||||
|
"lng_stories_link_invalid" = "This link is broken or has expired.";
|
||||||
|
|
||||||
// Wnd specific
|
// Wnd specific
|
||||||
|
|
||||||
"lng_wnd_choose_program_menu" = "Choose Default Program...";
|
"lng_wnd_choose_program_menu" = "Choose Default Program...";
|
||||||
|
|
|
@ -56,6 +56,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_poll.h"
|
#include "data/data_poll.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_stories.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_session_settings.h"
|
#include "main/main_session_settings.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
|
@ -72,6 +73,7 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kFastRevokeRestriction = 24 * 60 * TimeId(60);
|
constexpr auto kFastRevokeRestriction = 24 * 60 * TimeId(60);
|
||||||
constexpr auto kMaxPreviewImages = 3;
|
constexpr auto kMaxPreviewImages = 3;
|
||||||
|
constexpr auto kLoadingStoryPhotoId = PhotoId(0x7FFF'DEAD'FFFF'FFFFULL);
|
||||||
|
|
||||||
using ItemPreview = HistoryView::ItemPreview;
|
using ItemPreview = HistoryView::ItemPreview;
|
||||||
using ItemPreviewImage = HistoryView::ItemPreviewImage;
|
using ItemPreviewImage = HistoryView::ItemPreviewImage;
|
||||||
|
@ -404,6 +406,10 @@ const WallPaper *Media::paper() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FullStoryId Media::storyId() const {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool Media::uploading() const {
|
bool Media::uploading() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1968,4 +1974,82 @@ std::unique_ptr<HistoryView::Media> MediaWallPaper::createView(
|
||||||
std::make_unique<HistoryView::ThemeDocumentBox>(message, _paper));
|
std::make_unique<HistoryView::ThemeDocumentBox>(message, _paper));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MediaStory::MediaStory(not_null<HistoryItem*> parent, FullStoryId storyId)
|
||||||
|
: Media(parent)
|
||||||
|
, _storyId(storyId) {
|
||||||
|
const auto stories = &parent->history()->owner().stories();
|
||||||
|
if (!stories->lookup(storyId)) {
|
||||||
|
stories->resolve(storyId, crl::guard(this, [=] {
|
||||||
|
if (stories->lookup(storyId)) {
|
||||||
|
parent->history()->owner().requestItemViewRefresh(parent);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Media> MediaStory::clone(not_null<HistoryItem*> parent) {
|
||||||
|
return std::make_unique<MediaStory>(parent, _storyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
FullStoryId MediaStory::storyId() const {
|
||||||
|
return _storyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithEntities MediaStory::notificationText() const {
|
||||||
|
const auto stories = &parent()->history()->owner().stories();
|
||||||
|
const auto maybeStory = stories->lookup(_storyId);
|
||||||
|
return WithCaptionNotificationText(
|
||||||
|
tr::lng_in_dlg_story(tr::now),
|
||||||
|
(maybeStory
|
||||||
|
? (*maybeStory)->caption()
|
||||||
|
: TextWithEntities()));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MediaStory::pinnedTextSubstring() const {
|
||||||
|
return tr::lng_action_pinned_media_story(tr::now);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextForMimeData MediaStory::clipboardText() const {
|
||||||
|
return WithCaptionClipboardText(
|
||||||
|
tr::lng_in_dlg_story(tr::now),
|
||||||
|
parent()->clipboardText());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MediaStory::updateInlineResultMedia(const MTPMessageMedia &media) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MediaStory::updateSentMedia(const MTPMessageMedia &media) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<HistoryView::Media> MediaStory::createView(
|
||||||
|
not_null<HistoryView::Element*> message,
|
||||||
|
not_null<HistoryItem*> realParent,
|
||||||
|
HistoryView::Element *replacing) {
|
||||||
|
const auto spoiler = false;
|
||||||
|
const auto stories = &parent()->history()->owner().stories();
|
||||||
|
const auto maybeStory = stories->lookup(_storyId);
|
||||||
|
if (const auto story = maybeStory ? maybeStory->get() : nullptr) {
|
||||||
|
if (const auto photo = story->photo()) {
|
||||||
|
return std::make_unique<HistoryView::Photo>(
|
||||||
|
message,
|
||||||
|
realParent,
|
||||||
|
photo,
|
||||||
|
spoiler);
|
||||||
|
} else {
|
||||||
|
return std::make_unique<HistoryView::Gif>(
|
||||||
|
message,
|
||||||
|
realParent,
|
||||||
|
story->document(),
|
||||||
|
spoiler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_unique<HistoryView::Photo>(
|
||||||
|
message,
|
||||||
|
realParent,
|
||||||
|
realParent->history()->owner().photo(kLoadingStoryPhotoId),
|
||||||
|
spoiler);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/weak_ptr.h"
|
||||||
#include "data/data_location.h"
|
#include "data/data_location.h"
|
||||||
#include "data/data_wall_paper.h"
|
#include "data/data_wall_paper.h"
|
||||||
|
|
||||||
|
@ -110,6 +111,7 @@ public:
|
||||||
virtual CloudImage *location() const;
|
virtual CloudImage *location() const;
|
||||||
virtual PollData *poll() const;
|
virtual PollData *poll() const;
|
||||||
virtual const WallPaper *paper() const;
|
virtual const WallPaper *paper() const;
|
||||||
|
virtual FullStoryId storyId() const;
|
||||||
|
|
||||||
virtual bool uploading() const;
|
virtual bool uploading() const;
|
||||||
virtual Storage::SharedMediaTypesMask sharedMediaTypes() const;
|
virtual Storage::SharedMediaTypesMask sharedMediaTypes() const;
|
||||||
|
@ -563,6 +565,30 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MediaStory final : public Media, public base::has_weak_ptr {
|
||||||
|
public:
|
||||||
|
MediaStory(not_null<HistoryItem*> parent, FullStoryId storyId);
|
||||||
|
|
||||||
|
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
|
||||||
|
|
||||||
|
[[nodiscard]] FullStoryId storyId() const override;
|
||||||
|
|
||||||
|
TextWithEntities notificationText() const override;
|
||||||
|
QString pinnedTextSubstring() const override;
|
||||||
|
TextForMimeData clipboardText() const override;
|
||||||
|
|
||||||
|
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
|
||||||
|
bool updateSentMedia(const MTPMessageMedia &media) override;
|
||||||
|
std::unique_ptr<HistoryView::Media> createView(
|
||||||
|
not_null<HistoryView::Element*> message,
|
||||||
|
not_null<HistoryItem*> realParent,
|
||||||
|
HistoryView::Element *replacing = nullptr) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const FullStoryId _storyId;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
[[nodiscard]] TextForMimeData WithCaptionClipboardText(
|
[[nodiscard]] TextForMimeData WithCaptionClipboardText(
|
||||||
const QString &attachType,
|
const QString &attachType,
|
||||||
TextForMimeData &&caption);
|
TextForMimeData &&caption);
|
||||||
|
|
|
@ -291,7 +291,10 @@ std::unique_ptr<Data::Media> HistoryItem::CreateMedia(
|
||||||
qs(media.vemoticon()),
|
qs(media.vemoticon()),
|
||||||
media.vvalue().v);
|
media.vvalue().v);
|
||||||
}, [&](const MTPDmessageMediaStory &media) -> Result {
|
}, [&](const MTPDmessageMediaStory &media) -> Result {
|
||||||
return nullptr; // #TODO stories
|
return std::make_unique<Data::MediaStory>(item, FullStoryId{
|
||||||
|
peerFromUser(media.vuser_id()),
|
||||||
|
media.vid().v,
|
||||||
|
});
|
||||||
}, [](const MTPDmessageMediaEmpty &) -> Result {
|
}, [](const MTPDmessageMediaEmpty &) -> Result {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}, [](const MTPDmessageMediaUnsupported &) -> Result {
|
}, [](const MTPDmessageMediaUnsupported &) -> Result {
|
||||||
|
@ -3594,9 +3597,29 @@ void HistoryItem::createServiceFromMtp(const MTPDmessageService &message) {
|
||||||
|
|
||||||
void HistoryItem::setMedia(const MTPMessageMedia &media) {
|
void HistoryItem::setMedia(const MTPMessageMedia &media) {
|
||||||
_media = CreateMedia(this, media);
|
_media = CreateMedia(this, media);
|
||||||
|
checkStoryForwardInfo();
|
||||||
checkBuyButton();
|
checkBuyButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryItem::checkStoryForwardInfo() {
|
||||||
|
if (const auto storyId = _media ? _media->storyId() : FullStoryId()) {
|
||||||
|
const auto adding = !Has<HistoryMessageForwarded>();
|
||||||
|
if (adding) {
|
||||||
|
AddComponents(HistoryMessageForwarded::Bit());
|
||||||
|
}
|
||||||
|
const auto forwarded = Get<HistoryMessageForwarded>();
|
||||||
|
if (forwarded->story || adding) {
|
||||||
|
const auto peer = history()->owner().peer(storyId.peer);
|
||||||
|
forwarded->story = true;
|
||||||
|
forwarded->originalSender = peer;
|
||||||
|
}
|
||||||
|
} else if (const auto forwarded = Get<HistoryMessageForwarded>()) {
|
||||||
|
if (forwarded->story) {
|
||||||
|
RemoveComponents(HistoryMessageForwarded::Bit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryItem::applyServiceDateEdition(const MTPDmessageService &data) {
|
void HistoryItem::applyServiceDateEdition(const MTPDmessageService &data) {
|
||||||
const auto date = data.vdate().v;
|
const auto date = data.vdate().v;
|
||||||
if (_date == date) {
|
if (_date == date) {
|
||||||
|
|
|
@ -192,6 +192,7 @@ public:
|
||||||
[[nodiscard]] MsgId dependencyMsgId() const;
|
[[nodiscard]] MsgId dependencyMsgId() const;
|
||||||
[[nodiscard]] bool notificationReady() const;
|
[[nodiscard]] bool notificationReady() const;
|
||||||
[[nodiscard]] PeerData *specialNotificationPeer() const;
|
[[nodiscard]] PeerData *specialNotificationPeer() const;
|
||||||
|
void checkStoryForwardInfo();
|
||||||
void checkBuyButton();
|
void checkBuyButton();
|
||||||
|
|
||||||
void updateServiceText(PreparedServiceText &&text);
|
void updateServiceText(PreparedServiceText &&text);
|
||||||
|
|
|
@ -129,6 +129,7 @@ struct HistoryMessageForwarded : public RuntimeComponent<HistoryMessageForwarded
|
||||||
PeerData *savedFromPeer = nullptr;
|
PeerData *savedFromPeer = nullptr;
|
||||||
MsgId savedFromMsgId = 0;
|
MsgId savedFromMsgId = 0;
|
||||||
bool imported = false;
|
bool imported = false;
|
||||||
|
bool story = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HistoryMessageSponsored : public RuntimeComponent<HistoryMessageSponsored, HistoryItem> {
|
struct HistoryMessageSponsored : public RuntimeComponent<HistoryMessageSponsored, HistoryItem> {
|
||||||
|
|
|
@ -248,6 +248,7 @@ TextSelection ShiftItemSelection(
|
||||||
QString DateTooltipText(not_null<Element*> view) {
|
QString DateTooltipText(not_null<Element*> view) {
|
||||||
const auto locale = QLocale();
|
const auto locale = QLocale();
|
||||||
const auto format = QLocale::LongFormat;
|
const auto format = QLocale::LongFormat;
|
||||||
|
const auto item = view->data();
|
||||||
auto dateText = locale.toString(view->dateTime(), format);
|
auto dateText = locale.toString(view->dateTime(), format);
|
||||||
if (const auto editedDate = view->displayedEditDate()) {
|
if (const auto editedDate = view->displayedEditDate()) {
|
||||||
dateText += '\n' + tr::lng_edited_date(
|
dateText += '\n' + tr::lng_edited_date(
|
||||||
|
@ -255,18 +256,22 @@ QString DateTooltipText(not_null<Element*> view) {
|
||||||
lt_date,
|
lt_date,
|
||||||
locale.toString(base::unixtime::parse(editedDate), format));
|
locale.toString(base::unixtime::parse(editedDate), format));
|
||||||
}
|
}
|
||||||
if (const auto forwarded = view->data()->Get<HistoryMessageForwarded>()) {
|
if (const auto forwarded = item->Get<HistoryMessageForwarded>()) {
|
||||||
dateText += '\n' + tr::lng_forwarded_date(
|
if (!forwarded->story && forwarded->psaType.isEmpty()) {
|
||||||
tr::now,
|
dateText += '\n' + tr::lng_forwarded_date(
|
||||||
lt_date,
|
tr::now,
|
||||||
locale.toString(base::unixtime::parse(forwarded->originalDate), format));
|
lt_date,
|
||||||
if (forwarded->imported) {
|
locale.toString(
|
||||||
dateText = tr::lng_forwarded_imported(tr::now)
|
base::unixtime::parse(forwarded->originalDate),
|
||||||
+ "\n\n" + dateText;
|
format));
|
||||||
|
if (forwarded->imported) {
|
||||||
|
dateText = tr::lng_forwarded_imported(tr::now)
|
||||||
|
+ "\n\n" + dateText;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (view->isSignedAuthorElided()) {
|
if (view->isSignedAuthorElided()) {
|
||||||
if (const auto msgsigned = view->data()->Get<HistoryMessageSigned>()) {
|
if (const auto msgsigned = item->Get<HistoryMessageSigned>()) {
|
||||||
dateText += '\n'
|
dateText += '\n'
|
||||||
+ tr::lng_signed_author(tr::now, lt_user, msgsigned->author);
|
+ tr::lng_signed_author(tr::now, lt_user, msgsigned->author);
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,11 @@ Gif::Gif(
|
||||||
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right())
|
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right())
|
||||||
, _spoiler(spoiler ? std::make_unique<MediaSpoiler>() : nullptr)
|
, _spoiler(spoiler ? std::make_unique<MediaSpoiler>() : nullptr)
|
||||||
, _downloadSize(Ui::FormatSizeText(_data->size)) {
|
, _downloadSize(Ui::FormatSizeText(_data->size)) {
|
||||||
|
if (const auto media = realParent->media()) {
|
||||||
|
if (media->storyId()) {
|
||||||
|
_story = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
setDocumentLinks(_data, realParent, [=] {
|
setDocumentLinks(_data, realParent, [=] {
|
||||||
if (!_data->createMediaView()->canBePlayed(realParent)
|
if (!_data->createMediaView()->canBePlayed(realParent)
|
||||||
|| !_data->isAnimation()
|
|| !_data->isAnimation()
|
||||||
|
@ -1441,7 +1446,9 @@ void Gif::hideSpoilers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Gif::needsBubble() const {
|
bool Gif::needsBubble() const {
|
||||||
if (_data->isVideoMessage()) {
|
if (_story) {
|
||||||
|
return true;
|
||||||
|
} else if (_data->isVideoMessage()) {
|
||||||
return false;
|
return false;
|
||||||
} else if (!_caption.isEmpty()) {
|
} else if (!_caption.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -219,8 +219,9 @@ private:
|
||||||
mutable QImage _thumbCache;
|
mutable QImage _thumbCache;
|
||||||
mutable QImage _roundingMask;
|
mutable QImage _roundingMask;
|
||||||
mutable std::optional<Ui::BubbleRounding> _thumbCacheRounding;
|
mutable std::optional<Ui::BubbleRounding> _thumbCacheRounding;
|
||||||
mutable bool _thumbCacheBlurred = false;
|
mutable bool _thumbCacheBlurred : 1 = false;
|
||||||
mutable bool _thumbIsEllipse = false;
|
mutable bool _thumbIsEllipse : 1 = false;
|
||||||
|
mutable bool _story : 1 = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kStoryWidth = 720;
|
||||||
|
constexpr auto kStoryHeight = 1280;
|
||||||
|
|
||||||
using Data::PhotoSize;
|
using Data::PhotoSize;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -67,6 +70,11 @@ Photo::Photo(
|
||||||
, _data(photo)
|
, _data(photo)
|
||||||
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right())
|
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right())
|
||||||
, _spoiler(spoiler ? std::make_unique<MediaSpoiler>() : nullptr) {
|
, _spoiler(spoiler ? std::make_unique<MediaSpoiler>() : nullptr) {
|
||||||
|
if (const auto media = realParent->media()) {
|
||||||
|
if (media->storyId()) {
|
||||||
|
_story = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
_caption = createCaption(realParent);
|
_caption = createCaption(realParent);
|
||||||
create(realParent->fullId());
|
create(realParent->fullId());
|
||||||
}
|
}
|
||||||
|
@ -167,7 +175,7 @@ QSize Photo::countOptimalSize() {
|
||||||
_parent->skipBlockHeight());
|
_parent->skipBlockHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto dimensions = QSize(_data->width(), _data->height());
|
const auto dimensions = photoSize();
|
||||||
const auto scaled = CountDesiredMediaSize(dimensions);
|
const auto scaled = CountDesiredMediaSize(dimensions);
|
||||||
const auto minWidth = std::clamp(
|
const auto minWidth = std::clamp(
|
||||||
_parent->minWidthForMedia(),
|
_parent->minWidthForMedia(),
|
||||||
|
@ -210,7 +218,7 @@ QSize Photo::countCurrentSize(int newWidth) {
|
||||||
? st::historyPhotoBubbleMinWidth
|
? st::historyPhotoBubbleMinWidth
|
||||||
: st::minPhotoSize),
|
: st::minPhotoSize),
|
||||||
thumbMaxWidth);
|
thumbMaxWidth);
|
||||||
const auto dimensions = QSize(_data->width(), _data->height());
|
const auto dimensions = photoSize();
|
||||||
auto pix = CountPhotoMediaSize(
|
auto pix = CountPhotoMediaSize(
|
||||||
CountDesiredMediaSize(dimensions),
|
CountDesiredMediaSize(dimensions),
|
||||||
newWidth,
|
newWidth,
|
||||||
|
@ -255,7 +263,11 @@ int Photo::adjustHeightForLessCrop(QSize dimensions, QSize current) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Photo::draw(Painter &p, const PaintContext &context) const {
|
void Photo::draw(Painter &p, const PaintContext &context) const {
|
||||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
|
||||||
|
return;
|
||||||
|
} else if (_story && _data->isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ensureDataMediaCreated();
|
ensureDataMediaCreated();
|
||||||
_dataMedia->automaticLoad(_realParent->fullId(), _parent->data());
|
_dataMedia->automaticLoad(_realParent->fullId(), _parent->data());
|
||||||
|
@ -590,11 +602,20 @@ void Photo::paintUserpicFrame(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSize Photo::photoSize() const {
|
||||||
|
if (_story) {
|
||||||
|
return { kStoryWidth, kStoryHeight };
|
||||||
|
}
|
||||||
|
return QSize(_data->width(), _data->height());
|
||||||
|
}
|
||||||
|
|
||||||
TextState Photo::textState(QPoint point, StateRequest request) const {
|
TextState Photo::textState(QPoint point, StateRequest request) const {
|
||||||
auto result = TextState(_parent);
|
auto result = TextState(_parent);
|
||||||
|
|
||||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
|
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
|
||||||
return result;
|
return result;
|
||||||
|
} else if (_story && _data->isNull()) {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
||||||
auto bubble = _parent->hasBubble();
|
auto bubble = _parent->hasBubble();
|
||||||
|
@ -657,9 +678,8 @@ TextState Photo::textState(QPoint point, StateRequest request) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize Photo::sizeForGroupingOptimal(int maxWidth) const {
|
QSize Photo::sizeForGroupingOptimal(int maxWidth) const {
|
||||||
const auto width = _data->width();
|
const auto size = photoSize();
|
||||||
const auto height = _data->height();
|
return { std::max(size.width(), 1), std::max(size.height(), 1)};
|
||||||
return { std::max(width, 1), std::max(height, 1) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize Photo::sizeForGrouping(int width) const {
|
QSize Photo::sizeForGrouping(int width) const {
|
||||||
|
@ -848,8 +868,9 @@ void Photo::validateGroupedCache(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto originalWidth = style::ConvertScale(_data->width());
|
const auto unscaled = photoSize();
|
||||||
const auto originalHeight = style::ConvertScale(_data->height());
|
const auto originalWidth = style::ConvertScale(unscaled.width());
|
||||||
|
const auto originalHeight = style::ConvertScale(unscaled.height());
|
||||||
const auto pixSize = Ui::GetImageScaleSizeForGeometry(
|
const auto pixSize = Ui::GetImageScaleSizeForGeometry(
|
||||||
{ originalWidth, originalHeight },
|
{ originalWidth, originalHeight },
|
||||||
{ width, height });
|
{ width, height });
|
||||||
|
@ -1012,7 +1033,7 @@ void Photo::hideSpoilers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Photo::needsBubble() const {
|
bool Photo::needsBubble() const {
|
||||||
if (!_caption.isEmpty()) {
|
if (_story || !_caption.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const auto item = _parent->data();
|
const auto item = _parent->data();
|
||||||
|
|
|
@ -158,6 +158,8 @@ private:
|
||||||
const PaintContext &context,
|
const PaintContext &context,
|
||||||
QPoint photoPosition) const;
|
QPoint photoPosition) const;
|
||||||
|
|
||||||
|
[[nodiscard]] QSize photoSize() const;
|
||||||
|
|
||||||
const not_null<PhotoData*> _data;
|
const not_null<PhotoData*> _data;
|
||||||
Ui::Text::String _caption;
|
Ui::Text::String _caption;
|
||||||
mutable std::shared_ptr<Data::PhotoMedia> _dataMedia;
|
mutable std::shared_ptr<Data::PhotoMedia> _dataMedia;
|
||||||
|
@ -165,9 +167,10 @@ private:
|
||||||
const std::unique_ptr<MediaSpoiler> _spoiler;
|
const std::unique_ptr<MediaSpoiler> _spoiler;
|
||||||
mutable QImage _imageCache;
|
mutable QImage _imageCache;
|
||||||
mutable std::optional<Ui::BubbleRounding> _imageCacheRounding;
|
mutable std::optional<Ui::BubbleRounding> _imageCacheRounding;
|
||||||
int _serviceWidth : 30 = 0;
|
int _serviceWidth : 29 = 0;
|
||||||
mutable int _imageCacheForum : 1 = 0;
|
mutable int _imageCacheForum : 1 = 0;
|
||||||
mutable int _imageCacheBlurred : 1 = 0;
|
mutable int _imageCacheBlurred : 1 = 0;
|
||||||
|
mutable int _story : 1 = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -512,7 +512,7 @@ void SessionNavigation::showPeerByLinkResolved(
|
||||||
storyId.story,
|
storyId.story,
|
||||||
Data::StoriesContext{ Data::StoriesContextSingle() });
|
Data::StoriesContext{ Data::StoriesContextSingle() });
|
||||||
} else {
|
} else {
|
||||||
showToast(tr::lng_confirm_phone_link_invalid(tr::now));
|
showToast(tr::lng_stories_link_invalid(tr::now));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
} else if (bot && resolveType == ResolveType::BotApp) {
|
} else if (bot && resolveType == ResolveType::BotApp) {
|
||||||
|
@ -2155,14 +2155,12 @@ void SessionController::openPhoto(
|
||||||
not_null<PhotoData*> photo,
|
not_null<PhotoData*> photo,
|
||||||
FullMsgId contextId,
|
FullMsgId contextId,
|
||||||
MsgId topicRootId) {
|
MsgId topicRootId) {
|
||||||
if (openStory(contextId)) {
|
const auto item = session().data().message(contextId);
|
||||||
|
if (openSharedStory(item) || openFakeItemStory(contextId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_window->openInMediaView(Media::View::OpenRequest(
|
_window->openInMediaView(
|
||||||
this,
|
Media::View::OpenRequest(this, photo, item, topicRootId));
|
||||||
photo,
|
|
||||||
session().data().message(contextId),
|
|
||||||
topicRootId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionController::openPhoto(
|
void SessionController::openPhoto(
|
||||||
|
@ -2176,24 +2174,34 @@ void SessionController::openDocument(
|
||||||
FullMsgId contextId,
|
FullMsgId contextId,
|
||||||
MsgId topicRootId,
|
MsgId topicRootId,
|
||||||
bool showInMediaView) {
|
bool showInMediaView) {
|
||||||
if (openStory(contextId)) {
|
const auto item = session().data().message(contextId);
|
||||||
|
if (openSharedStory(item) || openFakeItemStory(contextId)) {
|
||||||
return;
|
return;
|
||||||
} else if (showInMediaView) {
|
} else if (showInMediaView) {
|
||||||
_window->openInMediaView(Media::View::OpenRequest(
|
_window->openInMediaView(
|
||||||
this,
|
Media::View::OpenRequest(this, document, item, topicRootId));
|
||||||
document,
|
|
||||||
session().data().message(contextId),
|
|
||||||
topicRootId));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Data::ResolveDocument(
|
Data::ResolveDocument(this, document, item, topicRootId);
|
||||||
this,
|
|
||||||
document,
|
|
||||||
session().data().message(contextId),
|
|
||||||
topicRootId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SessionController::openStory(
|
bool SessionController::openSharedStory(HistoryItem *item) {
|
||||||
|
if (const auto media = item ? item->media() : nullptr) {
|
||||||
|
if (const auto storyId = media->storyId()) {
|
||||||
|
const auto story = session().data().stories().lookup(storyId);
|
||||||
|
if (story) {
|
||||||
|
_window->openInMediaView(::Media::View::OpenRequest(
|
||||||
|
this,
|
||||||
|
*story,
|
||||||
|
Data::StoriesContext{ Data::StoriesContextSingle() }));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SessionController::openFakeItemStory(
|
||||||
FullMsgId fakeItemId,
|
FullMsgId fakeItemId,
|
||||||
bool forceArchiveContext) {
|
bool forceArchiveContext) {
|
||||||
if (!peerIsUser(fakeItemId.peer)
|
if (!peerIsUser(fakeItemId.peer)
|
||||||
|
|
|
@ -492,7 +492,10 @@ public:
|
||||||
FullMsgId contextId,
|
FullMsgId contextId,
|
||||||
MsgId topicRootId,
|
MsgId topicRootId,
|
||||||
bool showInMediaView = false);
|
bool showInMediaView = false);
|
||||||
bool openStory(FullMsgId fakeItemId, bool forceArchiveContext = false);
|
bool openSharedStory(HistoryItem *item);
|
||||||
|
bool openFakeItemStory(
|
||||||
|
FullMsgId fakeItemId,
|
||||||
|
bool forceArchiveContext = false);
|
||||||
|
|
||||||
void showChooseReportMessages(
|
void showChooseReportMessages(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
|
|
Loading…
Reference in New Issue