mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Show recent viewers in self stories.
This commit is contained in:
parent
e90642f3a0
commit
d76c80bf0e
15 changed files with 342 additions and 50 deletions
|
@ -973,6 +973,8 @@ PRIVATE
|
|||
media/stories/media_stories_delegate.h
|
||||
media/stories/media_stories_header.cpp
|
||||
media/stories/media_stories_header.h
|
||||
media/stories/media_stories_recent_views.cpp
|
||||
media/stories/media_stories_recent_views.h
|
||||
media/stories/media_stories_reply.cpp
|
||||
media/stories/media_stories_reply.h
|
||||
media/stories/media_stories_sibling.cpp
|
||||
|
|
|
@ -3793,6 +3793,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_stories_row_count#other" = "{count} Stories";
|
||||
"lng_stories_row_unread_and_one" = "{accumulated}, {user}";
|
||||
"lng_stories_row_unread_and_last" = "{accumulated} and {user}";
|
||||
"lng_stories_views#one" = "{count} view";
|
||||
"lng_stories_views#other" = "{count} views";
|
||||
"lng_stories_no_views" = "No views";
|
||||
|
||||
// Wnd specific
|
||||
|
||||
|
|
|
@ -229,4 +229,15 @@ QList<QUrl> ReadMimeUrls(not_null<const QMimeData*> data) {
|
|||
: QList<QUrl>();
|
||||
}
|
||||
|
||||
bool CanSendFiles(not_null<const QMimeData*> data) {
|
||||
if (data->hasImage()) {
|
||||
return true;
|
||||
} else if (const auto urls = ReadMimeUrls(data); !urls.empty()) {
|
||||
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -67,5 +67,6 @@ struct MimeImageData {
|
|||
[[nodiscard]] MimeImageData ReadMimeImage(not_null<const QMimeData*> data);
|
||||
[[nodiscard]] QString ReadMimeText(not_null<const QMimeData*> data);
|
||||
[[nodiscard]] QList<QUrl> ReadMimeUrls(not_null<const QMimeData*> data);
|
||||
[[nodiscard]] bool CanSendFiles(not_null<const QMimeData*> data);
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -36,10 +36,10 @@ constexpr auto kMarkAsReadDelay = 3 * crl::time(1000);
|
|||
using UpdateFlag = StoryUpdate::Flag;
|
||||
|
||||
std::optional<StoryMedia> ParseMedia(
|
||||
not_null<Session*> owner,
|
||||
const MTPMessageMedia &media) {
|
||||
not_null<Session*> owner,
|
||||
const MTPMessageMedia &media) {
|
||||
return media.match([&](const MTPDmessageMediaPhoto &data)
|
||||
-> std::optional<StoryMedia> {
|
||||
-> std::optional<StoryMedia> {
|
||||
if (const auto photo = data.vphoto()) {
|
||||
const auto result = owner->processPhoto(*photo);
|
||||
if (!result->isNull()) {
|
||||
|
@ -48,7 +48,7 @@ std::optional<StoryMedia> ParseMedia(
|
|||
}
|
||||
return {};
|
||||
}, [&](const MTPDmessageMediaDocument &data)
|
||||
-> std::optional<StoryMedia> {
|
||||
-> std::optional<StoryMedia> {
|
||||
if (const auto document = data.vdocument()) {
|
||||
const auto result = owner->processDocument(*document);
|
||||
if (!result->isNull()
|
||||
|
@ -71,10 +71,10 @@ Story::Story(
|
|||
not_null<PeerData*> peer,
|
||||
StoryMedia media,
|
||||
TimeId date)
|
||||
: _id(id)
|
||||
, _peer(peer)
|
||||
, _media(std::move(media))
|
||||
, _date(date) {
|
||||
: _id(id)
|
||||
, _peer(peer)
|
||||
, _media(std::move(media))
|
||||
, _date(date) {
|
||||
}
|
||||
|
||||
Session &Story::owner() const {
|
||||
|
@ -170,6 +170,21 @@ const TextWithEntities &Story::caption() const {
|
|||
return _caption;
|
||||
}
|
||||
|
||||
void Story::setViewsData(
|
||||
std::vector<not_null<PeerData*>> recent,
|
||||
int total) {
|
||||
_recentViewers = std::move(recent);
|
||||
_views = total;
|
||||
}
|
||||
|
||||
const std::vector<not_null<PeerData*>> &Story::recentViewers() const {
|
||||
return _recentViewers;
|
||||
}
|
||||
|
||||
int Story::views() const {
|
||||
return _views;
|
||||
}
|
||||
|
||||
bool Story::applyChanges(StoryMedia media, const MTPDstoryItem &data) {
|
||||
const auto pinned = data.is_pinned();
|
||||
auto caption = TextWithEntities{
|
||||
|
@ -178,15 +193,32 @@ bool Story::applyChanges(StoryMedia media, const MTPDstoryItem &data) {
|
|||
&owner().session(),
|
||||
data.ventities().value_or_empty()),
|
||||
};
|
||||
auto views = 0;
|
||||
auto recent = std::vector<not_null<PeerData*>>();
|
||||
if (const auto info = data.vviews()) {
|
||||
views = info->data().vviews_count().v;
|
||||
if (const auto list = info->data().vrecent_viewers()) {
|
||||
recent.reserve(list->v.size());
|
||||
auto &owner = _peer->owner();
|
||||
for (const auto &id : list->v) {
|
||||
recent.push_back(owner.peer(peerFromUser(id)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto changed = (_media != media)
|
||||
|| (_pinned != pinned)
|
||||
|| (_caption != caption);
|
||||
|| (_caption != caption)
|
||||
|| (_views != views)
|
||||
|| (_recentViewers != recent);
|
||||
if (!changed) {
|
||||
return false;
|
||||
}
|
||||
_media = std::move(media);
|
||||
_pinned = pinned;
|
||||
_caption = std::move(caption);
|
||||
_views = views;
|
||||
_recentViewers = std::move(recent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,11 @@ public:
|
|||
void setCaption(TextWithEntities &&caption);
|
||||
[[nodiscard]] const TextWithEntities &caption() const;
|
||||
|
||||
void setViewsData(std::vector<not_null<PeerData*>> recent, int total);
|
||||
[[nodiscard]] auto recentViewers() const
|
||||
-> const std::vector<not_null<PeerData*>> &;
|
||||
[[nodiscard]] int views() const;
|
||||
|
||||
bool applyChanges(StoryMedia media, const MTPDstoryItem &data);
|
||||
|
||||
private:
|
||||
|
@ -64,6 +69,8 @@ private:
|
|||
const not_null<PeerData*> _peer;
|
||||
StoryMedia _media;
|
||||
TextWithEntities _caption;
|
||||
std::vector<not_null<PeerData*>> _recentViewers;
|
||||
int _views = 0;
|
||||
const TimeId _date = 0;
|
||||
bool _pinned = false;
|
||||
|
||||
|
|
|
@ -97,17 +97,6 @@ namespace {
|
|||
|
||||
constexpr auto kRefreshSlowmodeLabelTimeout = crl::time(200);
|
||||
|
||||
bool CanSendFiles(not_null<const QMimeData*> data) {
|
||||
if (data->hasImage()) {
|
||||
return true;
|
||||
} else if (const auto urls = Core::ReadMimeUrls(data); !urls.empty()) {
|
||||
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
rpl::producer<Ui::MessageBarContent> RootViewContent(
|
||||
not_null<History*> history,
|
||||
MsgId rootId,
|
||||
|
@ -819,7 +808,7 @@ void RepliesWidget::setupComposeControls() {
|
|||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action) {
|
||||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
return CanSendFiles(data);
|
||||
return Core::CanSendFiles(data);
|
||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||
return confirmSendingFiles(
|
||||
data,
|
||||
|
|
|
@ -65,20 +65,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <QtCore/QMimeData>
|
||||
|
||||
namespace HistoryView {
|
||||
namespace {
|
||||
|
||||
bool CanSendFiles(not_null<const QMimeData*> data) {
|
||||
if (data->hasImage()) {
|
||||
return true;
|
||||
} else if (const auto urls = Core::ReadMimeUrls(data); !urls.empty()) {
|
||||
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
object_ptr<Window::SectionWidget> ScheduledMemento::createWidget(
|
||||
QWidget *parent,
|
||||
|
@ -308,7 +294,7 @@ void ScheduledWidget::setupComposeControls() {
|
|||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action) {
|
||||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
return CanSendFiles(data);
|
||||
return Core::CanSendFiles(data);
|
||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||
return confirmSendingFiles(
|
||||
data,
|
||||
|
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "media/stories/media_stories_header.h"
|
||||
#include "media/stories/media_stories_sibling.h"
|
||||
#include "media/stories/media_stories_slider.h"
|
||||
#include "media/stories/media_stories_recent_views.h"
|
||||
#include "media/stories/media_stories_reply.h"
|
||||
#include "media/stories/media_stories_view.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
|
@ -123,7 +124,8 @@ Controller::Controller(not_null<Delegate*> delegate)
|
|||
, _wrap(_delegate->storiesWrap())
|
||||
, _header(std::make_unique<Header>(this))
|
||||
, _slider(std::make_unique<Slider>(this))
|
||||
, _replyArea(std::make_unique<ReplyArea>(this)) {
|
||||
, _replyArea(std::make_unique<ReplyArea>(this))
|
||||
, _recentViews(std::make_unique<RecentViews>(this)) {
|
||||
initLayout();
|
||||
|
||||
_replyArea->activeValue(
|
||||
|
@ -249,6 +251,9 @@ void Controller::initLayout() {
|
|||
+ layout.content.height()
|
||||
+ fieldMinHeight
|
||||
- st::storiesFieldMargin.bottom()));
|
||||
layout.views = QRect(
|
||||
layout.controlsBottomPosition - QPoint(0, fieldMinHeight),
|
||||
QSize(layout.controlsWidth, fieldMinHeight));
|
||||
layout.autocompleteRect = QRect(
|
||||
layout.controlsBottomPosition.x(),
|
||||
0,
|
||||
|
@ -422,9 +427,18 @@ void Controller::show(
|
|||
_captionText = story->caption();
|
||||
_captionFullView = nullptr;
|
||||
|
||||
if (_replyFocused) {
|
||||
unfocusReply();
|
||||
}
|
||||
|
||||
_header->show({ .user = list.user, .date = story->date() });
|
||||
_slider->show({ .index = _index, .total = list.total });
|
||||
_replyArea->show({ .user = list.user, .id = id });
|
||||
_recentViews->show({
|
||||
.list = story->recentViewers(),
|
||||
.total = story->views(),
|
||||
.valid = list.user->isSelf(),
|
||||
});
|
||||
|
||||
const auto session = &list.user->session();
|
||||
if (_session != session) {
|
||||
|
@ -450,11 +464,7 @@ void Controller::show(
|
|||
}
|
||||
stories.loadAround(storyId);
|
||||
|
||||
if (_replyFocused) {
|
||||
unfocusReply();
|
||||
}
|
||||
updatePlayingAllowed();
|
||||
|
||||
list.user->updateFull();
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace Media::Stories {
|
|||
class Header;
|
||||
class Slider;
|
||||
class ReplyArea;
|
||||
class RecentViews;
|
||||
class Sibling;
|
||||
class Delegate;
|
||||
struct SiblingView;
|
||||
|
@ -68,6 +69,7 @@ struct Layout {
|
|||
QRect slider;
|
||||
int controlsWidth = 0;
|
||||
QPoint controlsBottomPosition;
|
||||
QRect views;
|
||||
QRect autocompleteRect;
|
||||
HeaderLayout headerLayout = HeaderLayout::Normal;
|
||||
SiblingLayout siblingLeft;
|
||||
|
@ -148,6 +150,7 @@ private:
|
|||
const std::unique_ptr<Header> _header;
|
||||
const std::unique_ptr<Slider> _slider;
|
||||
const std::unique_ptr<ReplyArea> _replyArea;
|
||||
const std::unique_ptr<RecentViews> _recentViews;
|
||||
std::unique_ptr<PhotoPlayback> _photoPlayback;
|
||||
std::unique_ptr<CaptionFullView> _captionFullView;
|
||||
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
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_recent_views.h"
|
||||
|
||||
#include "data/data_peer.h"
|
||||
#include "main/main_session.h"
|
||||
#include "media/stories/media_stories_controller.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/chat/group_call_userpics.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/userpic_view.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_media_view.h"
|
||||
|
||||
namespace Media::Stories {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] rpl::producer<std::vector<Ui::GroupCallUser>> ContentByUsers(
|
||||
const std::vector<not_null<PeerData*>> &list) {
|
||||
struct Userpic {
|
||||
not_null<PeerData*> peer;
|
||||
mutable Ui::PeerUserpicView view;
|
||||
mutable InMemoryKey uniqueKey;
|
||||
};
|
||||
|
||||
struct State {
|
||||
std::vector<Userpic> userpics;
|
||||
std::vector<Ui::GroupCallUser> current;
|
||||
base::has_weak_ptr guard;
|
||||
bool someUserpicsNotLoaded = false;
|
||||
bool scheduled = false;
|
||||
};
|
||||
|
||||
static const auto size = st::storiesRecentViewsUserpics.size;
|
||||
|
||||
static const auto GenerateUserpic = [](Userpic &userpic) {
|
||||
auto result = userpic.peer->generateUserpicImage(
|
||||
userpic.view,
|
||||
size * style::DevicePixelRatio());
|
||||
result.setDevicePixelRatio(style::DevicePixelRatio());
|
||||
return result;
|
||||
};
|
||||
|
||||
static const auto RegenerateUserpics = [](not_null<State*> state) {
|
||||
Expects(state->userpics.size() == state->current.size());
|
||||
|
||||
state->someUserpicsNotLoaded = false;
|
||||
const auto count = int(state->userpics.size());
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
auto &userpic = state->userpics[i];
|
||||
auto &participant = state->current[i];
|
||||
const auto peer = userpic.peer;
|
||||
const auto key = peer->userpicUniqueKey(userpic.view);
|
||||
if (peer->hasUserpic() && peer->useEmptyUserpic(userpic.view)) {
|
||||
state->someUserpicsNotLoaded = true;
|
||||
}
|
||||
if (userpic.uniqueKey == key) {
|
||||
continue;
|
||||
}
|
||||
participant.userpicKey = userpic.uniqueKey = key;
|
||||
participant.userpic = GenerateUserpic(userpic);
|
||||
}
|
||||
};
|
||||
|
||||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
|
||||
const auto state = lifetime.make_state<State>();
|
||||
const auto pushNext = [=] {
|
||||
RegenerateUserpics(state);
|
||||
consumer.put_next_copy(state->current);
|
||||
};
|
||||
|
||||
for (const auto &peer : list) {
|
||||
state->userpics.push_back(Userpic{
|
||||
.peer = peer,
|
||||
});
|
||||
state->current.push_back(Ui::GroupCallUser{
|
||||
.id = uint64(peer->id.value),
|
||||
});
|
||||
peer->loadUserpic();
|
||||
}
|
||||
pushNext();
|
||||
|
||||
if (!list.empty()) {
|
||||
list.front()->session().downloaderTaskFinished(
|
||||
) | rpl::filter([=] {
|
||||
return state->someUserpicsNotLoaded && !state->scheduled;
|
||||
}) | rpl::start_with_next([=] {
|
||||
for (const auto &userpic : state->userpics) {
|
||||
if (userpic.peer->userpicUniqueKey(userpic.view)
|
||||
!= userpic.uniqueKey) {
|
||||
state->scheduled = true;
|
||||
crl::on_main(&state->guard, [=] {
|
||||
state->scheduled = false;
|
||||
pushNext();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, lifetime);
|
||||
}
|
||||
return lifetime;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RecentViews::RecentViews(not_null<Controller*> controller)
|
||||
: _controller(controller) {
|
||||
}
|
||||
|
||||
RecentViews::~RecentViews() = default;
|
||||
|
||||
void RecentViews::show(RecentViewsData data) {
|
||||
if (_data == data) {
|
||||
return;
|
||||
}
|
||||
const auto totalChanged = _text.isEmpty() || (_data.total != data.total);
|
||||
const auto usersChanged = !_userpics || (_data.list != data.list);
|
||||
_data = data;
|
||||
if (!_data.valid) {
|
||||
_text = {};
|
||||
_userpics = nullptr;
|
||||
_widget = nullptr;
|
||||
return;
|
||||
}
|
||||
if (!_widget) {
|
||||
const auto parent = _controller->wrap();
|
||||
auto widget = std::make_unique<Ui::RpWidget>(parent);
|
||||
const auto raw = widget.get();
|
||||
raw->show();
|
||||
|
||||
_controller->layoutValue(
|
||||
) | rpl::start_with_next([=](const Layout &layout) {
|
||||
raw->setGeometry(layout.views);
|
||||
}, raw->lifetime());
|
||||
|
||||
raw->paintRequest(
|
||||
) | rpl::start_with_next([=](QRect clip) {
|
||||
auto p = Painter(raw);
|
||||
const auto skip = st::storiesRecentViewsSkip;
|
||||
const auto full = _userpicsWidth + skip + _text.maxWidth();
|
||||
const auto use = std::min(full, raw->width());
|
||||
const auto ux = (raw->width() - use) / 2;
|
||||
const auto height = st::storiesRecentViewsUserpics.size;
|
||||
const auto uy = (raw->height() - height) / 2;
|
||||
const auto tx = ux + _userpicsWidth + skip;
|
||||
const auto ty = (raw->height() - st::normalFont->height) / 2;
|
||||
_userpics->paint(p, ux, uy, height);
|
||||
p.setPen(st::storiesComposeWhiteText);
|
||||
_text.drawElided(p, tx, ty, use - _userpicsWidth - skip);
|
||||
}, raw->lifetime());
|
||||
|
||||
_widget = std::move(widget);
|
||||
}
|
||||
if (totalChanged) {
|
||||
_text.setText(st::defaultTextStyle, data.total
|
||||
? tr::lng_stories_views(tr::now, lt_count, data.total)
|
||||
: tr::lng_stories_no_views(tr::now));
|
||||
}
|
||||
if (!_userpics) {
|
||||
_userpics = std::make_unique<Ui::GroupCallUserpics>(
|
||||
st::storiesRecentViewsUserpics,
|
||||
rpl::single(true),
|
||||
[=] { _widget->update(); });
|
||||
|
||||
_userpics->widthValue() | rpl::start_with_next([=](int width) {
|
||||
_userpicsWidth = width;
|
||||
}, _widget->lifetime());
|
||||
}
|
||||
if (usersChanged) {
|
||||
_userpicsLifetime = ContentByUsers(
|
||||
data.list
|
||||
) | rpl::start_with_next([=](
|
||||
const std::vector<Ui::GroupCallUser> &list) {
|
||||
_userpics->update(list, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Media::Stories
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
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/text/text.h"
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
class GroupCallUserpics;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
class Controller;
|
||||
|
||||
struct RecentViewsData {
|
||||
std::vector<not_null<PeerData*>> list;
|
||||
int total = 0;
|
||||
bool valid = false;
|
||||
|
||||
friend inline auto operator<=>(
|
||||
const RecentViewsData &,
|
||||
const RecentViewsData &) = default;
|
||||
friend inline bool operator==(
|
||||
const RecentViewsData &,
|
||||
const RecentViewsData &) = default;
|
||||
};
|
||||
|
||||
class RecentViews final {
|
||||
public:
|
||||
explicit RecentViews(not_null<Controller*> controller);
|
||||
~RecentViews();
|
||||
|
||||
void show(RecentViewsData data);
|
||||
|
||||
private:
|
||||
const not_null<Controller*> _controller;
|
||||
|
||||
std::unique_ptr<Ui::RpWidget> _widget;
|
||||
std::unique_ptr<Ui::GroupCallUserpics> _userpics;
|
||||
Ui::Text::String _text;
|
||||
RecentViewsData _data;
|
||||
rpl::lifetime _userpicsLifetime;
|
||||
int _userpicsWidth = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Media::Stories
|
|
@ -524,12 +524,12 @@ void ReplyArea::initActions() {
|
|||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action) {
|
||||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
return false;// checkSendingFiles(data);
|
||||
return Core::CanSendFiles(data);
|
||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||
return false;/* confirmSendingFiles(
|
||||
return confirmSendingFiles(
|
||||
data,
|
||||
std::nullopt,
|
||||
Core::ReadMimeText(data));*/
|
||||
Core::ReadMimeText(data));
|
||||
}
|
||||
Unexpected("action in MimeData hook.");
|
||||
});
|
||||
|
@ -562,6 +562,11 @@ void ReplyArea::show(ReplyAreaData data) {
|
|||
.history = history,
|
||||
});
|
||||
_controls->clear();
|
||||
if (!user || user->isSelf()) {
|
||||
_controls->hide();
|
||||
} else {
|
||||
_controls->show();
|
||||
}
|
||||
}
|
||||
|
||||
Main::Session &ReplyArea::session() const {
|
||||
|
|
|
@ -66,18 +66,12 @@ private:
|
|||
[[nodiscard]] Main::Session &session() const;
|
||||
[[nodiscard]] not_null<History*> history() const;
|
||||
|
||||
bool confirmSendingFiles(const QStringList &files);
|
||||
bool confirmSendingFiles(not_null<const QMimeData*> data);
|
||||
|
||||
void uploadFile(const QByteArray &fileContent, SendMediaType type);
|
||||
bool confirmSendingFiles(
|
||||
QImage &&image,
|
||||
QByteArray &&content,
|
||||
std::optional<bool> overrideSendImagesAsPhotos = std::nullopt,
|
||||
const QString &insertTextOnCancel = QString());
|
||||
bool confirmSendingFiles(
|
||||
const QStringList &files,
|
||||
const QString &insertTextOnCancel);
|
||||
bool confirmSendingFiles(
|
||||
Ui::PreparedList &&list,
|
||||
const QString &insertTextOnCancel = QString());
|
||||
|
|
|
@ -729,3 +729,11 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
|
|||
}
|
||||
premium: storiesComposePremium;
|
||||
}
|
||||
storiesRecentViewsUserpics: GroupCallUserpics {
|
||||
size: 24px;
|
||||
shift: 9px;
|
||||
stroke: 4px;
|
||||
align: align(left);
|
||||
}
|
||||
storiesRecentViewsSkip: 8px;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue