mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Start stories viewer with ComposeControls.
This commit is contained in:
parent
429a3da3e5
commit
89ca38ed29
23 changed files with 884 additions and 20 deletions
|
@ -548,6 +548,8 @@ PRIVATE
|
|||
data/data_sparse_ids.h
|
||||
data/data_sponsored_messages.cpp
|
||||
data/data_sponsored_messages.h
|
||||
data/data_stories.cpp
|
||||
data/data_stories.h
|
||||
data/data_streaming.cpp
|
||||
data/data_streaming.h
|
||||
data/data_thread.cpp
|
||||
|
@ -936,8 +938,6 @@ PRIVATE
|
|||
main/session/send_as_peers.h
|
||||
main/session/session_show.cpp
|
||||
main/session/session_show.h
|
||||
media/system_media_controls_manager.h
|
||||
media/system_media_controls_manager.cpp
|
||||
media/audio/media_audio.cpp
|
||||
media/audio/media_audio.h
|
||||
media/audio/media_audio_capture.cpp
|
||||
|
@ -962,6 +962,16 @@ PRIVATE
|
|||
media/player/media_player_volume_controller.h
|
||||
media/player/media_player_widget.cpp
|
||||
media/player/media_player_widget.h
|
||||
media/stories/media_stories_delegate.cpp
|
||||
media/stories/media_stories_delegate.h
|
||||
media/stories/media_stories_header.cpp
|
||||
media/stories/media_stories_header.h
|
||||
media/stories/media_stories_reply.cpp
|
||||
media/stories/media_stories_reply.h
|
||||
media/stories/media_stories_slider.cpp
|
||||
media/stories/media_stories_slider.h
|
||||
media/stories/media_stories_view.cpp
|
||||
media/stories/media_stories_view.h
|
||||
media/streaming/media_streaming_audio_track.cpp
|
||||
media/streaming/media_streaming_audio_track.h
|
||||
media/streaming/media_streaming_common.h
|
||||
|
@ -1007,6 +1017,8 @@ PRIVATE
|
|||
media/view/media_view_playback_progress.cpp
|
||||
media/view/media_view_playback_progress.h
|
||||
media/view/media_view_open_common.h
|
||||
media/system_media_controls_manager.h
|
||||
media/system_media_controls_manager.cpp
|
||||
menu/menu_antispam_validator.cpp
|
||||
menu/menu_antispam_validator.h
|
||||
menu/menu_item_download_files.cpp
|
||||
|
|
|
@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_forum.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_send_action.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "inline_bots/bot_attach_web_view.h"
|
||||
#include "chat_helpers/emoji_interactions.h"
|
||||
|
@ -2517,7 +2518,11 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
|||
case mtpc_updateTranscribedAudio: {
|
||||
const auto &data = update.c_updateTranscribedAudio();
|
||||
_session->api().transcribes().apply(data);
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateStories: {
|
||||
_session->data().stories().apply(update.c_updateStories());
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public:
|
|||
Data::FileOrigin origin,
|
||||
not_null<PhotoData*> photo) const = 0;
|
||||
|
||||
virtual void processChosenSticker(FileChosen chosen) const = 0;
|
||||
virtual void processChosenSticker(FileChosen &&chosen) const = 0;
|
||||
|
||||
[[nodiscard]] virtual Window::SessionController *resolveWindow(
|
||||
WindowUsage) const;
|
||||
|
|
|
@ -66,6 +66,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_emoji_statuses.h"
|
||||
#include "data/data_forum_icons.h"
|
||||
#include "data/data_cloud_themes.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_streaming.h"
|
||||
#include "data/data_media_rotation.h"
|
||||
#include "data/data_histories.h"
|
||||
|
@ -266,7 +267,8 @@ Session::Session(not_null<Main::Session*> session)
|
|||
, _emojiStatuses(std::make_unique<EmojiStatuses>(this))
|
||||
, _forumIcons(std::make_unique<ForumIcons>(this))
|
||||
, _notifySettings(std::make_unique<NotifySettings>(this))
|
||||
, _customEmojiManager(std::make_unique<CustomEmojiManager>(this)) {
|
||||
, _customEmojiManager(std::make_unique<CustomEmojiManager>(this))
|
||||
, _stories(std::make_unique<Stories>(this)) {
|
||||
_cache->open(_session->local().cacheKey());
|
||||
_bigFileCache->open(_session->local().cacheBigFileKey());
|
||||
|
||||
|
@ -311,6 +313,8 @@ Session::Session(not_null<Main::Session*> session)
|
|||
}
|
||||
}
|
||||
}, _lifetime);
|
||||
|
||||
_stories->loadMore();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ class Stickers;
|
|||
class GroupCall;
|
||||
class NotifySettings;
|
||||
class CustomEmojiManager;
|
||||
class Stories;
|
||||
|
||||
struct RepliesReadTillUpdate {
|
||||
FullMsgId id;
|
||||
|
@ -136,6 +137,9 @@ public:
|
|||
[[nodiscard]] CustomEmojiManager &customEmojiManager() const {
|
||||
return *_customEmojiManager;
|
||||
}
|
||||
[[nodiscard]] Stories &stories() const {
|
||||
return *_stories;
|
||||
}
|
||||
|
||||
[[nodiscard]] MsgId nextNonHistoryEntryId() {
|
||||
return ++_nonHistoryEntryId;
|
||||
|
@ -1007,6 +1011,7 @@ private:
|
|||
const std::unique_ptr<ForumIcons> _forumIcons;
|
||||
const std::unique_ptr<NotifySettings> _notifySettings;
|
||||
const std::unique_ptr<CustomEmojiManager> _customEmojiManager;
|
||||
const std::unique_ptr<Stories> _stories;
|
||||
|
||||
MsgId _nonHistoryEntryId = ServerMaxMsgId.bare + ScheduledMsgIdsRange;
|
||||
|
||||
|
|
246
Telegram/SourceFiles/data/data_stories.cpp
Normal file
246
Telegram/SourceFiles/data/data_stories.cpp
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
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 "data/data_stories.h"
|
||||
|
||||
#include "api/api_text_entities.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
// #TODO stories testing
|
||||
#include "data/data_user.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
} // namespace
|
||||
|
||||
bool StoriesList::unread() const {
|
||||
return !items.empty() && readTill < items.front().id;
|
||||
}
|
||||
|
||||
Stories::Stories(not_null<Session*> owner) : _owner(owner) {
|
||||
}
|
||||
|
||||
Stories::~Stories() {
|
||||
}
|
||||
|
||||
Session &Stories::owner() const {
|
||||
return *_owner;
|
||||
}
|
||||
|
||||
void Stories::apply(const MTPDupdateStories &data) {
|
||||
pushToFront(parse(data.vstories()));
|
||||
}
|
||||
|
||||
StoriesList Stories::parse(const MTPUserStories &stories) {
|
||||
const auto &data = stories.data();
|
||||
const auto userId = UserId(data.vuser_id());
|
||||
const auto readTill = data.vmax_read_id().value_or_empty();
|
||||
const auto count = int(data.vstories().v.size());
|
||||
auto result = StoriesList{
|
||||
.user = _owner->user(userId),
|
||||
.readTill = readTill,
|
||||
.total = count,
|
||||
};
|
||||
const auto &list = data.vstories().v;
|
||||
result.items.reserve(list.size());
|
||||
for (const auto &story : list) {
|
||||
story.match([&](const MTPDstoryItem &data) {
|
||||
if (auto entry = parse(data)) {
|
||||
result.items.push_back(std::move(*entry));
|
||||
} else {
|
||||
--result.total;
|
||||
}
|
||||
}, [&](const MTPDstoryItemSkipped &) {
|
||||
}, [&](const MTPDstoryItemDeleted &) {
|
||||
--result.total;
|
||||
});
|
||||
}
|
||||
result.total = std::min(result.total, int(result.items.size()));
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<StoryItem> Stories::parse(const MTPDstoryItem &data) {
|
||||
const auto id = data.vid().v;
|
||||
using MaybeMedia = std::optional<
|
||||
std::variant<not_null<PhotoData*>, not_null<DocumentData*>>>;
|
||||
const auto media = data.vmedia().match([&](
|
||||
const MTPDmessageMediaPhoto &data) -> MaybeMedia {
|
||||
if (const auto photo = data.vphoto()) {
|
||||
const auto result = _owner->processPhoto(*photo);
|
||||
if (!result->isNull()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}, [&](const MTPDmessageMediaDocument &data) -> MaybeMedia {
|
||||
if (const auto document = data.vdocument()) {
|
||||
const auto result = _owner->processDocument(*document);
|
||||
if (!result->isNull()
|
||||
&& (result->isGifv() || result->isVideoFile())) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}, [](const auto &) { return MaybeMedia(); });
|
||||
if (!media) {
|
||||
return {};
|
||||
}
|
||||
auto caption = TextWithEntities{
|
||||
data.vcaption().value_or_empty(),
|
||||
Api::EntitiesFromMTP(
|
||||
&_owner->session(),
|
||||
data.ventities().value_or_empty()),
|
||||
};
|
||||
auto privacy = StoryPrivacy();
|
||||
|
||||
const auto date = data.vdate().v;
|
||||
return StoryItem{
|
||||
.id = data.vid().v,
|
||||
.media = *media,
|
||||
.caption = std::move(caption),
|
||||
.date = date,
|
||||
.privacy = privacy,
|
||||
};
|
||||
}
|
||||
|
||||
void Stories::loadMore() {
|
||||
if (_loadMoreRequestId || _allLoaded) {
|
||||
return;
|
||||
}
|
||||
const auto api = &_owner->session().api();
|
||||
using Flag = MTPstories_GetAllStories::Flag;
|
||||
_loadMoreRequestId = api->request(MTPstories_GetAllStories(
|
||||
MTP_flags(_state.isEmpty() ? Flag(0) : Flag::f_next),
|
||||
MTP_string(_state)
|
||||
)).done([=](const MTPstories_AllStories &result) {
|
||||
_loadMoreRequestId = 0;
|
||||
|
||||
result.match([&](const MTPDstories_allStories &data) {
|
||||
_owner->processUsers(data.vusers());
|
||||
_state = qs(data.vstate());
|
||||
_allLoaded = !data.is_has_more();
|
||||
for (const auto &single : data.vuser_stories().v) {
|
||||
pushToBack(parse(single));
|
||||
}
|
||||
}, [](const MTPDstories_allStoriesNotModified &) {
|
||||
});
|
||||
}).fail([=] {
|
||||
_loadMoreRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
const std::vector<StoriesList> &Stories::all() {
|
||||
return _all;
|
||||
}
|
||||
|
||||
bool Stories::allLoaded() const {
|
||||
return _allLoaded;
|
||||
}
|
||||
|
||||
// #TODO stories testing
|
||||
StoryId Stories::generate(
|
||||
not_null<HistoryItem*> item,
|
||||
std::variant<
|
||||
v::null_t,
|
||||
not_null<PhotoData*>,
|
||||
not_null<DocumentData*>> media) {
|
||||
if (v::is_null(media)
|
||||
|| !item->from()->isUser()
|
||||
|| !item->isRegular()) {
|
||||
return {};
|
||||
}
|
||||
const auto document = v::is<not_null<DocumentData*>>(media)
|
||||
? v::get<not_null<DocumentData*>>(media).get()
|
||||
: nullptr;
|
||||
if (document && !document->isVideoFile()) {
|
||||
return {};
|
||||
}
|
||||
using namespace Storage;
|
||||
auto resultId = StoryId();
|
||||
const auto listType = SharedMediaType::PhotoVideo;
|
||||
const auto itemId = item->id;
|
||||
const auto peer = item->history()->peer;
|
||||
const auto session = &peer->session();
|
||||
auto stories = StoriesList{ .user = item->from()->asUser() };
|
||||
const auto lifetime = session->storage().query(SharedMediaQuery(
|
||||
SharedMediaKey(peer->id, MsgId(0), listType, itemId),
|
||||
32,
|
||||
32
|
||||
)) | rpl::start_with_next([&](SharedMediaResult &&result) {
|
||||
stories.total = result.count.value_or(1);
|
||||
if (!result.messageIds.contains(itemId)) {
|
||||
result.messageIds.emplace(itemId);
|
||||
}
|
||||
stories.items.reserve(result.messageIds.size());
|
||||
auto index = StoryId();
|
||||
const auto owner = &peer->owner();
|
||||
for (const auto id : result.messageIds) {
|
||||
if (const auto item = owner->message(peer, id)) {
|
||||
if (id == itemId) {
|
||||
resultId = ++index;
|
||||
stories.items.push_back({
|
||||
.id = resultId,
|
||||
.media = (document
|
||||
? StoryMedia{ not_null(document) }
|
||||
: StoryMedia{ v::get<not_null<PhotoData*>>(media) }),
|
||||
.caption = item->originalText(),
|
||||
.date = item->date(),
|
||||
});
|
||||
} else if (const auto media = item->media()) {
|
||||
const auto photo = media->photo();
|
||||
const auto document = media->document();
|
||||
if (photo || (document && document->isVideoFile())) {
|
||||
stories.items.push_back({
|
||||
.id = ++index,
|
||||
.media = (document
|
||||
? StoryMedia{ not_null(document) }
|
||||
: StoryMedia{ not_null(photo) }),
|
||||
.caption = item->originalText(),
|
||||
.date = item->date(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto i = ranges::find(_all, stories.user, &StoriesList::user);
|
||||
if (i != end(_all)) {
|
||||
*i = std::move(stories);
|
||||
} else {
|
||||
_all.push_back(std::move(stories));
|
||||
}
|
||||
});
|
||||
return resultId;
|
||||
}
|
||||
|
||||
void Stories::pushToBack(StoriesList &&list) {
|
||||
const auto i = ranges::find(_all, list.user, &StoriesList::user);
|
||||
if (i != end(_all)) {
|
||||
*i = std::move(list);
|
||||
} else {
|
||||
_all.push_back(std::move(list));
|
||||
}
|
||||
}
|
||||
|
||||
void Stories::pushToFront(StoriesList &&list) {
|
||||
const auto i = ranges::find(_all, list.user, &StoriesList::user);
|
||||
if (i != end(_all)) {
|
||||
*i = std::move(list);
|
||||
ranges::rotate(begin(_all), i, i + 1);
|
||||
} else {
|
||||
_all.insert(begin(_all), std::move(list));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Data
|
74
Telegram/SourceFiles/data/data_stories.h
Normal file
74
Telegram/SourceFiles/data/data_stories.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
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
|
||||
|
||||
class PhotoData;
|
||||
class DocumentData;
|
||||
|
||||
namespace Data {
|
||||
|
||||
class Session;
|
||||
|
||||
struct StoryPrivacy {
|
||||
};
|
||||
|
||||
struct StoryMedia {
|
||||
std::variant<not_null<PhotoData*>, not_null<DocumentData*>> data;
|
||||
};
|
||||
|
||||
struct StoryItem {
|
||||
StoryId id = 0;
|
||||
StoryMedia media;
|
||||
TextWithEntities caption;
|
||||
TimeId date = 0;
|
||||
StoryPrivacy privacy;
|
||||
};
|
||||
|
||||
struct StoriesList {
|
||||
not_null<UserData*> user;
|
||||
std::vector<StoryItem> items;
|
||||
int total = 0;
|
||||
};
|
||||
|
||||
class Stories final {
|
||||
public:
|
||||
explicit Stories(not_null<Session*> owner);
|
||||
~Stories();
|
||||
|
||||
void loadMore();
|
||||
void apply(const MTPDupdateStories &data);
|
||||
|
||||
[[nodiscard]] const std::vector<StoriesList> &all();
|
||||
[[nodiscard]] bool allLoaded() const;
|
||||
|
||||
// #TODO stories testing
|
||||
[[nodiscard]] StoryId generate(
|
||||
not_null<HistoryItem*> item,
|
||||
std::variant<
|
||||
v::null_t,
|
||||
not_null<PhotoData*>,
|
||||
not_null<DocumentData*>> media);
|
||||
|
||||
private:
|
||||
[[nodiscard]] StoriesList parse(const MTPUserStories &data);
|
||||
[[nodiscard]] std::optional<StoryItem> parse(const MTPDstoryItem &data);
|
||||
|
||||
void pushToBack(StoriesList &&list);
|
||||
void pushToFront(StoriesList &&list);
|
||||
|
||||
const not_null<Session*> _owner;
|
||||
|
||||
std::vector<StoriesList> _all;
|
||||
QString _state;
|
||||
bool _allLoaded = false;
|
||||
|
||||
mtpRequestId _loadMoreRequestId = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
|
@ -135,6 +135,8 @@ using PollId = uint64;
|
|||
using WallPaperId = uint64;
|
||||
using CallId = uint64;
|
||||
using BotAppId = uint64;
|
||||
using StoryId = int32;
|
||||
|
||||
constexpr auto CancelledWebPageId = WebPageId(0xFFFFFFFFFFFFFFFFULL);
|
||||
|
||||
struct PreparedPhotoThumb {
|
||||
|
|
|
@ -2538,11 +2538,15 @@ bool ComposeControls::returnTabbedSelector() {
|
|||
}
|
||||
|
||||
void ComposeControls::createTabbedPanel() {
|
||||
auto descriptor = ChatHelpers::TabbedPanelDescriptor{
|
||||
using namespace ChatHelpers;
|
||||
auto descriptor = TabbedPanelDescriptor{
|
||||
.regularWindow = _regularWindow,
|
||||
.nonOwnedSelector = _selector,
|
||||
.ownedSelector = (_ownedSelector
|
||||
? object_ptr<TabbedSelector>::fromRaw(_ownedSelector.release())
|
||||
: object_ptr<TabbedSelector>(nullptr)),
|
||||
.nonOwnedSelector = _ownedSelector ? nullptr : _selector.get(),
|
||||
};
|
||||
setTabbedPanel(std::make_unique<ChatHelpers::TabbedPanel>(
|
||||
setTabbedPanel(std::make_unique<TabbedPanel>(
|
||||
_parent,
|
||||
std::move(descriptor)));
|
||||
}
|
||||
|
|
|
@ -315,7 +315,7 @@ private:
|
|||
const not_null<Main::Session*> _session;
|
||||
|
||||
Window::SessionController * const _regularWindow = nullptr;
|
||||
const std::unique_ptr<ChatHelpers::TabbedSelector> _ownedSelector;
|
||||
std::unique_ptr<ChatHelpers::TabbedSelector> _ownedSelector;
|
||||
const not_null<ChatHelpers::TabbedSelector*> _selector;
|
||||
rpl::event_stream<ChatHelpers::FileChosen> _stickerOrEmojiChosen;
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
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 "media/stories/media_stories_delegate.h"
|
||||
|
30
Telegram/SourceFiles/media/stories/media_stories_delegate.h
Normal file
30
Telegram/SourceFiles/media/stories/media_stories_delegate.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
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
|
||||
|
||||
namespace ChatHelpers {
|
||||
class Show;
|
||||
struct FileChosen;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
class Delegate {
|
||||
public:
|
||||
[[nodiscard]] virtual not_null<Ui::RpWidget*> storiesWrap() = 0;
|
||||
[[nodiscard]] virtual auto storiesShow()
|
||||
-> std::shared_ptr<ChatHelpers::Show> = 0;
|
||||
[[nodiscard]] virtual auto storiesStickerOrEmojiChosen()
|
||||
-> rpl::producer<ChatHelpers::FileChosen> = 0;
|
||||
};
|
||||
|
||||
} // namespace Media::Stories
|
65
Telegram/SourceFiles/media/stories/media_stories_header.cpp
Normal file
65
Telegram/SourceFiles/media/stories/media_stories_header.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
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 "media/stories/media_stories_header.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_user.h"
|
||||
#include "media/stories/media_stories_delegate.h"
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "styles/style_boxes.h" // defaultUserpicButton.
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
Header::Header(not_null<Delegate*> delegate)
|
||||
: _delegate(delegate) {
|
||||
}
|
||||
|
||||
Header::~Header() {
|
||||
}
|
||||
|
||||
void Header::show(HeaderData data) {
|
||||
if (_data == data) {
|
||||
return;
|
||||
}
|
||||
const auto userChanged = (!_data || _data->user != data.user);
|
||||
_data = data;
|
||||
if (userChanged) {
|
||||
_date = nullptr;
|
||||
const auto parent = _delegate->storiesWrap();
|
||||
auto widget = std::make_unique<Ui::RpWidget>(parent);
|
||||
const auto raw = widget.get();
|
||||
parent->sizeValue() | rpl::start_with_next([=](QSize size) {
|
||||
raw->setGeometry(50, 50, 600, 100);
|
||||
}, raw->lifetime());
|
||||
raw->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
const auto userpic = Ui::CreateChild<Ui::UserpicButton>(
|
||||
raw,
|
||||
data.user,
|
||||
st::defaultUserpicButton);
|
||||
userpic->move(0, 0);
|
||||
const auto name = Ui::CreateChild<Ui::FlatLabel>(
|
||||
raw,
|
||||
data.user->firstName,
|
||||
st::defaultFlatLabel);
|
||||
name->move(100, 0);
|
||||
raw->show();
|
||||
_widget = std::move(widget);
|
||||
}
|
||||
_date = std::make_unique<Ui::FlatLabel>(
|
||||
_widget.get(),
|
||||
Ui::FormatDateTime(base::unixtime::parse(data.date)),
|
||||
st::defaultFlatLabel);
|
||||
_date->move(100, 50);
|
||||
_date->show();
|
||||
}
|
||||
|
||||
} // namespace Media::Stories
|
43
Telegram/SourceFiles/media/stories/media_stories_header.h
Normal file
43
Telegram/SourceFiles/media/stories/media_stories_header.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
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 "ui/userpic_view.h"
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
class FlatLabel;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
class Delegate;
|
||||
|
||||
struct HeaderData {
|
||||
not_null<UserData*> user;
|
||||
TimeId date = 0;
|
||||
|
||||
friend inline auto operator<=>(HeaderData, HeaderData) = default;
|
||||
};
|
||||
|
||||
class Header final {
|
||||
public:
|
||||
explicit Header(not_null<Delegate*> delegate);
|
||||
~Header();
|
||||
|
||||
void show(HeaderData data);
|
||||
|
||||
private:
|
||||
const not_null<Delegate*> _delegate;
|
||||
std::unique_ptr<Ui::RpWidget> _widget;
|
||||
std::unique_ptr<Ui::FlatLabel> _date;
|
||||
std::optional<HeaderData> _data;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Media::Stories
|
50
Telegram/SourceFiles/media/stories/media_stories_reply.cpp
Normal file
50
Telegram/SourceFiles/media/stories/media_stories_reply.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
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 "media/stories/media_stories_reply.h"
|
||||
|
||||
#include "chat_helpers/compose/compose_show.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
#include "history/view/controls/history_view_compose_controls.h"
|
||||
#include "media/stories/media_stories_delegate.h"
|
||||
#include "menu/menu_send.h"
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
ReplyArea::ReplyArea(not_null<Delegate*> delegate)
|
||||
: _delegate(delegate)
|
||||
, _controls(std::make_unique<HistoryView::ComposeControls>(
|
||||
_delegate->storiesWrap(),
|
||||
HistoryView::ComposeControlsDescriptor{
|
||||
.show = _delegate->storiesShow(),
|
||||
.unavailableEmojiPasted = [=](not_null<DocumentData*> emoji) {
|
||||
showPremiumToast(emoji);
|
||||
},
|
||||
.mode = HistoryView::ComposeControlsMode::Normal,
|
||||
.sendMenuType = SendMenu::Type::SilentOnly,
|
||||
.stickerOrEmojiChosen = _delegate->storiesStickerOrEmojiChosen(),
|
||||
}
|
||||
)) {
|
||||
_delegate->storiesWrap()->sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
_controls->resizeToWidth(size.width() - 200);
|
||||
_controls->move(100, size.height() - _controls->heightCurrent() - 20);
|
||||
_controls->setAutocompleteBoundingRect({ QPoint() ,size });
|
||||
}, _lifetime);
|
||||
|
||||
_controls->show();
|
||||
_controls->showFinished();
|
||||
}
|
||||
|
||||
ReplyArea::~ReplyArea() {
|
||||
}
|
||||
|
||||
void ReplyArea::showPremiumToast(not_null<DocumentData*> emoji) {
|
||||
// #TODO stories
|
||||
}
|
||||
|
||||
} // namespace Media::Stories
|
39
Telegram/SourceFiles/media/stories/media_stories_reply.h
Normal file
39
Telegram/SourceFiles/media/stories/media_stories_reply.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
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
|
||||
|
||||
namespace HistoryView {
|
||||
class ComposeControls;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
class Delegate;
|
||||
|
||||
struct ReplyAreaData {
|
||||
not_null<UserData*> user;
|
||||
|
||||
friend inline auto operator<=>(ReplyAreaData, ReplyAreaData) = default;
|
||||
};
|
||||
|
||||
class ReplyArea final {
|
||||
public:
|
||||
explicit ReplyArea(not_null<Delegate*> delegate);
|
||||
~ReplyArea();
|
||||
|
||||
private:
|
||||
void showPremiumToast(not_null<DocumentData*> emoji);
|
||||
|
||||
const not_null<Delegate*> _delegate;
|
||||
const std::unique_ptr<HistoryView::ComposeControls> _controls;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Media::Stories
|
18
Telegram/SourceFiles/media/stories/media_stories_slider.cpp
Normal file
18
Telegram/SourceFiles/media/stories/media_stories_slider.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
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 "media/stories/media_stories_slider.h"
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
Slider::Slider() {
|
||||
}
|
||||
|
||||
Slider::~Slider() {
|
||||
}
|
||||
|
||||
} // namespace Media::Stories
|
20
Telegram/SourceFiles/media/stories/media_stories_slider.h
Normal file
20
Telegram/SourceFiles/media/stories/media_stories_slider.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
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
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
class Slider final {
|
||||
public:
|
||||
Slider();
|
||||
~Slider();
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace Media::Stories
|
37
Telegram/SourceFiles/media/stories/media_stories_view.cpp
Normal file
37
Telegram/SourceFiles/media/stories/media_stories_view.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
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 "media/stories/media_stories_view.h"
|
||||
|
||||
#include "media/stories/media_stories_delegate.h"
|
||||
#include "media/stories/media_stories_header.h"
|
||||
#include "media/stories/media_stories_slider.h"
|
||||
#include "media/stories/media_stories_reply.h"
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
View::View(not_null<Delegate*> delegate)
|
||||
: _delegate(delegate)
|
||||
, _wrap(_delegate->storiesWrap())
|
||||
, _header(std::make_unique<Header>(_delegate))
|
||||
, _slider(std::make_unique<Slider>())
|
||||
, _replyArea(std::make_unique<ReplyArea>(_delegate)) {
|
||||
}
|
||||
|
||||
View::~View() = default;
|
||||
|
||||
void View::show(const Data::StoriesList &list, int index) {
|
||||
Expects(index < list.items.size());
|
||||
|
||||
const auto &item = list.items[index];
|
||||
_header->show({
|
||||
.user = list.user,
|
||||
.date = item.date,
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Media::Stories
|
40
Telegram/SourceFiles/media/stories/media_stories_view.h
Normal file
40
Telegram/SourceFiles/media/stories/media_stories_view.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
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 "data/data_stories.h"
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
class Header;
|
||||
class Slider;
|
||||
class ReplyArea;
|
||||
class Delegate;
|
||||
|
||||
class View final {
|
||||
public:
|
||||
explicit View(not_null<Delegate*> delegate);
|
||||
~View();
|
||||
|
||||
void show(const Data::StoriesList &list, int index);
|
||||
|
||||
private:
|
||||
const not_null<Delegate*> _delegate;
|
||||
const not_null<Ui::RpWidget*> _wrap;
|
||||
|
||||
std::unique_ptr<Header> _header;
|
||||
std::unique_ptr<Slider> _slider;
|
||||
std::unique_ptr<ReplyArea> _replyArea;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Media::Stories
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/layers/layer_manager.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/platform/ui_platform_utility.h"
|
||||
#include "ui/platform/ui_platform_window_title.h"
|
||||
|
@ -45,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "media/view/media_view_pip.h"
|
||||
#include "media/view/media_view_overlay_raster.h"
|
||||
#include "media/view/media_view_overlay_opengl.h"
|
||||
#include "media/stories/media_stories_view.h"
|
||||
#include "media/streaming/media_streaming_instance.h"
|
||||
#include "media/streaming/media_streaming_player.h"
|
||||
#include "media/player/media_player_instance.h"
|
||||
|
@ -54,6 +56,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/media/history_view_media.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
|
@ -331,6 +334,7 @@ OverlayWidget::OverlayWidget()
|
|||
, _widget(_surface->rpWidget())
|
||||
, _fullscreen(Core::App().settings().mediaViewPosition().maximized == 2)
|
||||
, _windowed(Core::App().settings().mediaViewPosition().maximized == 0)
|
||||
, _layerBg(std::make_unique<Ui::LayerManager>(_body))
|
||||
, _docDownload(_body, tr::lng_media_download(tr::now), st::mediaviewFileLink)
|
||||
, _docSaveAs(_body, tr::lng_mediaview_save_as(tr::now), st::mediaviewFileLink)
|
||||
, _docCancel(_body, tr::lng_cancel(tr::now), st::mediaviewFileLink)
|
||||
|
@ -2870,6 +2874,14 @@ void OverlayWidget::show(OpenRequest request) {
|
|||
}
|
||||
setSession(&photo->session());
|
||||
|
||||
// #TODO stories testing
|
||||
if (const auto storyId = (!contextPeer && contextItem)
|
||||
? contextItem->history()->owner().stories().generate(
|
||||
contextItem,
|
||||
photo)
|
||||
: StoryId()) {
|
||||
setContext(StoriesContext{ contextItem->from()->asUser(), storyId });
|
||||
} else
|
||||
if (contextPeer) {
|
||||
setContext(contextPeer);
|
||||
} else if (contextItem) {
|
||||
|
@ -2888,6 +2900,14 @@ void OverlayWidget::show(OpenRequest request) {
|
|||
} else if (document) {
|
||||
setSession(&document->session());
|
||||
|
||||
// #TODO stories testing
|
||||
if (const auto storyId = contextItem
|
||||
? contextItem->history()->owner().stories().generate(
|
||||
contextItem,
|
||||
document)
|
||||
: StoryId()) {
|
||||
setContext(StoriesContext{ contextItem->from()->asUser(), storyId });
|
||||
} else
|
||||
if (contextItem) {
|
||||
setContext(ItemContext{ contextItem, contextTopicRootId });
|
||||
} else {
|
||||
|
@ -3808,6 +3828,91 @@ void OverlayWidget::switchToPip() {
|
|||
}
|
||||
}
|
||||
|
||||
not_null<Ui::RpWidget*> OverlayWidget::storiesWrap() {
|
||||
return _body;
|
||||
}
|
||||
|
||||
std::shared_ptr<ChatHelpers::Show> OverlayWidget::storiesShow() {
|
||||
class Show final : public ChatHelpers::Show {
|
||||
public:
|
||||
explicit Show(not_null<OverlayWidget*> widget) : _widget(widget) {
|
||||
}
|
||||
|
||||
void showBox(
|
||||
object_ptr<Ui::BoxContent> content,
|
||||
Ui::LayerOptions options
|
||||
= Ui::LayerOption::KeepOther) const override {
|
||||
_widget->_layerBg->showBox(
|
||||
std::move(content),
|
||||
options,
|
||||
anim::type::normal);
|
||||
}
|
||||
void hideLayer() const override {
|
||||
_widget->_layerBg->hideAll(anim::type::normal);
|
||||
}
|
||||
not_null<QWidget*> toastParent() const override {
|
||||
return _widget->_body;
|
||||
}
|
||||
bool valid() const override {
|
||||
return _widget->_storiesUser != nullptr;
|
||||
}
|
||||
operator bool() const override {
|
||||
return valid();
|
||||
}
|
||||
|
||||
Main::Session &session() const override {
|
||||
return _widget->_storiesUser->session();
|
||||
}
|
||||
bool paused(ChatHelpers::PauseReason reason) const override {
|
||||
if (_widget->isHidden()
|
||||
|| (!_widget->_fullscreen
|
||||
&& !_widget->_window->isActiveWindow())) {
|
||||
return true;
|
||||
} else if (reason < ChatHelpers::PauseReason::Layer
|
||||
&& _widget->_layerBg->topShownLayer() != nullptr) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
rpl::producer<> pauseChanged() const override {
|
||||
return rpl::never<>();
|
||||
}
|
||||
|
||||
rpl::producer<bool> adjustShadowLeft() const override {
|
||||
return rpl::single(false);
|
||||
}
|
||||
SendMenu::Type sendMenuType() const override {
|
||||
return SendMenu::Type::SilentOnly;
|
||||
}
|
||||
|
||||
bool showMediaPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<DocumentData*> document) const override {
|
||||
return false; // #TODO stories
|
||||
}
|
||||
bool showMediaPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<PhotoData*> photo) const override {
|
||||
return false; // #TODO stories
|
||||
}
|
||||
|
||||
void processChosenSticker(
|
||||
ChatHelpers::FileChosen &&chosen) const override {
|
||||
_widget->_storiesStickerOrEmojiChosen.fire(std::move(chosen));
|
||||
}
|
||||
|
||||
private:
|
||||
not_null<OverlayWidget*> _widget;
|
||||
|
||||
};
|
||||
return std::make_shared<Show>(this);
|
||||
}
|
||||
|
||||
auto OverlayWidget::storiesStickerOrEmojiChosen()
|
||||
-> rpl::producer<ChatHelpers::FileChosen> {
|
||||
return _storiesStickerOrEmojiChosen.events();
|
||||
}
|
||||
|
||||
void OverlayWidget::playbackToggleFullScreen() {
|
||||
Expects(_streamed != nullptr);
|
||||
|
||||
|
@ -4619,22 +4724,49 @@ void OverlayWidget::setContext(
|
|||
std::variant<
|
||||
v::null_t,
|
||||
ItemContext,
|
||||
not_null<PeerData*>> context) {
|
||||
not_null<PeerData*>,
|
||||
StoriesContext> context) {
|
||||
if (const auto item = std::get_if<ItemContext>(&context)) {
|
||||
_message = item->item;
|
||||
_history = _message->history();
|
||||
_peer = _history->peer;
|
||||
_topicRootId = _peer->isForum() ? item->topicRootId : MsgId();
|
||||
_stories = nullptr;
|
||||
_storiesUser = nullptr;
|
||||
} else if (const auto peer = std::get_if<not_null<PeerData*>>(&context)) {
|
||||
_peer = *peer;
|
||||
_history = _peer->owner().history(_peer);
|
||||
_message = nullptr;
|
||||
_topicRootId = MsgId();
|
||||
_stories = nullptr;
|
||||
_storiesUser = nullptr;
|
||||
} else if (const auto story = std::get_if<StoriesContext>(&context)) {
|
||||
_message = nullptr;
|
||||
_topicRootId = MsgId();
|
||||
_history = nullptr;
|
||||
_peer = nullptr;
|
||||
const auto &all = story->user->owner().stories().all();
|
||||
const auto i = ranges::find(
|
||||
all,
|
||||
story->user,
|
||||
&Data::StoriesList::user);
|
||||
Assert(i != end(all));
|
||||
const auto j = ranges::find(
|
||||
i->items,
|
||||
story->id,
|
||||
&Data::StoryItem::id);
|
||||
_storiesUser = story->user;
|
||||
if (!_stories) {
|
||||
_stories = std::make_unique<Stories::View>(
|
||||
static_cast<Stories::Delegate*>(this));
|
||||
}
|
||||
_stories->show(*i, j - begin(i->items));
|
||||
} else {
|
||||
_message = nullptr;
|
||||
_topicRootId = MsgId();
|
||||
_history = nullptr;
|
||||
_peer = nullptr;
|
||||
_stories = nullptr;
|
||||
}
|
||||
_migrated = nullptr;
|
||||
if (_history) {
|
||||
|
@ -4704,6 +4836,14 @@ bool OverlayWidget::moveToEntity(const Entity &entity, int preloadDelta) {
|
|||
if (v::is_null(entity.data) && !entity.item) {
|
||||
return false;
|
||||
}
|
||||
// #TODO stories testing
|
||||
if (const auto storyId = entity.item
|
||||
? entity.item->history()->owner().stories().generate(
|
||||
entity.item,
|
||||
entity.data)
|
||||
: StoryId()) {
|
||||
setContext(StoriesContext{ entity.item->from()->asUser(), storyId });
|
||||
} else
|
||||
if (const auto item = entity.item) {
|
||||
setContext(ItemContext{ item, entity.topicRootId });
|
||||
} else if (_peer) {
|
||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_cloud_themes.h" // Data::CloudTheme.
|
||||
#include "media/view/media_view_playback_controls.h"
|
||||
#include "media/view/media_view_open_common.h"
|
||||
#include "media/stories/media_stories_delegate.h"
|
||||
|
||||
class History;
|
||||
|
||||
|
@ -32,6 +33,7 @@ class PopupMenu;
|
|||
class LinkButton;
|
||||
class RoundButton;
|
||||
class RpWindow;
|
||||
class LayerManager;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Ui::GL {
|
||||
|
@ -50,17 +52,20 @@ struct Preview;
|
|||
} // namespace Theme
|
||||
} // namespace Window
|
||||
|
||||
namespace Media {
|
||||
namespace Player {
|
||||
namespace Media::Player {
|
||||
struct TrackState;
|
||||
} // namespace Player
|
||||
namespace Streaming {
|
||||
} // namespace Media::Player
|
||||
|
||||
namespace Media::Streaming {
|
||||
struct Information;
|
||||
struct Update;
|
||||
struct FrameWithInfo;
|
||||
enum class Error;
|
||||
} // namespace Streaming
|
||||
} // namespace Media
|
||||
} // namespace Media::Streaming
|
||||
|
||||
namespace Media::Stories {
|
||||
class View;
|
||||
} // namespace Media::Stories
|
||||
|
||||
namespace Media::View {
|
||||
|
||||
|
@ -69,7 +74,8 @@ class Pip;
|
|||
|
||||
class OverlayWidget final
|
||||
: public ClickHandlerHost
|
||||
, private PlaybackControls::Delegate {
|
||||
, private PlaybackControls::Delegate
|
||||
, private Stories::Delegate {
|
||||
public:
|
||||
OverlayWidget();
|
||||
~OverlayWidget();
|
||||
|
@ -217,6 +223,11 @@ private:
|
|||
void playbackPauseMusic();
|
||||
void switchToPip();
|
||||
|
||||
not_null<Ui::RpWidget*> storiesWrap() override;
|
||||
std::shared_ptr<ChatHelpers::Show> storiesShow() override;
|
||||
auto storiesStickerOrEmojiChosen()
|
||||
-> rpl::producer<ChatHelpers::FileChosen> override;
|
||||
|
||||
void hideControls(bool force = false);
|
||||
void subscribeToScreenGeometry();
|
||||
|
||||
|
@ -268,10 +279,15 @@ private:
|
|||
not_null<HistoryItem*> item;
|
||||
MsgId topicRootId = 0;
|
||||
};
|
||||
struct StoriesContext {
|
||||
not_null<UserData*> user;
|
||||
StoryId id = 0;
|
||||
};
|
||||
void setContext(std::variant<
|
||||
v::null_t,
|
||||
ItemContext,
|
||||
not_null<PeerData*>> context);
|
||||
not_null<PeerData*>,
|
||||
StoriesContext> context);
|
||||
|
||||
void refreshLang();
|
||||
void showSaveMsgFile();
|
||||
|
@ -551,6 +567,11 @@ private:
|
|||
int _streamedCreated = 0;
|
||||
bool _showAsPip = false;
|
||||
|
||||
std::unique_ptr<Stories::View> _stories;
|
||||
UserData *_storiesUser = nullptr;
|
||||
rpl::event_stream<ChatHelpers::FileChosen> _storiesStickerOrEmojiChosen;
|
||||
std::unique_ptr<Ui::LayerManager> _layerBg;
|
||||
|
||||
const style::icon *_docIcon = nullptr;
|
||||
style::color _docIconColor;
|
||||
QString _docName, _docSize, _docExt;
|
||||
|
|
|
@ -140,7 +140,7 @@ public:
|
|||
not_null<PhotoData*> photo) const override;
|
||||
|
||||
void processChosenSticker(
|
||||
ChatHelpers::FileChosen chosen) const override;
|
||||
ChatHelpers::FileChosen &&chosen) const override;
|
||||
|
||||
private:
|
||||
const base::weak_ptr<SessionController> _window;
|
||||
|
@ -233,7 +233,7 @@ bool MainWindowShow::showMediaPreview(
|
|||
}
|
||||
|
||||
void MainWindowShow::processChosenSticker(
|
||||
ChatHelpers::FileChosen chosen) const {
|
||||
ChatHelpers::FileChosen &&chosen) const {
|
||||
if (const auto window = _window.get()) {
|
||||
Ui::PostponeCall(window, [=, chosen = std::move(chosen)]() mutable {
|
||||
window->stickerOrEmojiChosen(std::move(chosen));
|
||||
|
|
Loading…
Add table
Reference in a new issue