mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Show toast/tooltip info on video processing.
This commit is contained in:
parent
3137c9f3f7
commit
66be2ac6ca
17 changed files with 480 additions and 65 deletions
|
@ -3304,6 +3304,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_scheduled_send_now" = "Send message now?";
|
"lng_scheduled_send_now" = "Send message now?";
|
||||||
"lng_scheduled_send_now_many#one" = "Send {count} message now?";
|
"lng_scheduled_send_now_many#one" = "Send {count} message now?";
|
||||||
"lng_scheduled_send_now_many#other" = "Send {count} messages now?";
|
"lng_scheduled_send_now_many#other" = "Send {count} messages now?";
|
||||||
|
"lng_scheduled_video_tip_title" = "Improving video...";
|
||||||
|
"lng_scheduled_video_tip_text" = "The video will be published after it's optimized for the bast viewing experience.";
|
||||||
|
"lng_scheduled_video_tip" = "Processing video may take a few minutes.";
|
||||||
|
"lng_scheduled_video_published" = "Video Published.";
|
||||||
|
"lng_scheduled_video_view" = "View";
|
||||||
|
|
||||||
"lng_replies_view#one" = "View {count} Reply";
|
"lng_replies_view#one" = "View {count} Reply";
|
||||||
"lng_replies_view#other" = "View {count} Replies";
|
"lng_replies_view#other" = "View {count} Replies";
|
||||||
|
|
|
@ -332,6 +332,15 @@ void Updates::feedUpdateVector(
|
||||||
session().data().sendHistoryChangeNotifications();
|
session().data().sendHistoryChangeNotifications();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Updates::checkForSentToScheduled(const MTPUpdates &updates) {
|
||||||
|
updates.match([&](const MTPDupdates &data) {
|
||||||
|
applyConvertToScheduledOnSend(data.vupdates(), true);
|
||||||
|
}, [&](const MTPDupdatesCombined &data) {
|
||||||
|
applyConvertToScheduledOnSend(data.vupdates(), true);
|
||||||
|
}, [](const auto &) {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Updates::feedMessageIds(const MTPVector<MTPUpdate> &updates) {
|
void Updates::feedMessageIds(const MTPVector<MTPUpdate> &updates) {
|
||||||
for (const auto &update : updates.v) {
|
for (const auto &update : updates.v) {
|
||||||
if (update.type() == mtpc_updateMessageID) {
|
if (update.type() == mtpc_updateMessageID) {
|
||||||
|
@ -887,23 +896,35 @@ void Updates::mtpUpdateReceived(const MTPUpdates &updates) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Updates::applyConvertToScheduledOnSend(
|
void Updates::applyConvertToScheduledOnSend(
|
||||||
const MTPVector<MTPUpdate> &other) {
|
const MTPVector<MTPUpdate> &other,
|
||||||
|
bool skipScheduledCheck) {
|
||||||
for (const auto &update : other.v) {
|
for (const auto &update : other.v) {
|
||||||
update.match([&](const MTPDupdateNewScheduledMessage &data) {
|
update.match([&](const MTPDupdateNewScheduledMessage &data) {
|
||||||
const auto id = IdFromMessage(data.vmessage());
|
const auto &message = data.vmessage();
|
||||||
|
const auto id = IdFromMessage(message);
|
||||||
const auto scheduledMessages = &_session->scheduledMessages();
|
const auto scheduledMessages = &_session->scheduledMessages();
|
||||||
const auto scheduledId = scheduledMessages->localMessageId(id);
|
const auto scheduledId = scheduledMessages->localMessageId(id);
|
||||||
for (const auto &updateId : other.v) {
|
for (const auto &updateId : other.v) {
|
||||||
updateId.match([&](const MTPDupdateMessageID &dataId) {
|
updateId.match([&](const MTPDupdateMessageID &dataId) {
|
||||||
if (dataId.vid().v == id) {
|
if (dataId.vid().v == id) {
|
||||||
const auto rand = dataId.vrandom_id().v;
|
|
||||||
auto &owner = session().data();
|
auto &owner = session().data();
|
||||||
|
if (skipScheduledCheck) {
|
||||||
|
const auto peerId = PeerFromMessage(message);
|
||||||
|
const auto history = owner.historyLoaded(peerId);
|
||||||
|
if (history) {
|
||||||
|
_session->data().sentToScheduled({
|
||||||
|
.history = history,
|
||||||
|
.scheduledId = scheduledId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto rand = dataId.vrandom_id().v;
|
||||||
const auto localId = owner.messageIdByRandomId(rand);
|
const auto localId = owner.messageIdByRandomId(rand);
|
||||||
if (const auto local = owner.message(localId)) {
|
if (const auto local = owner.message(localId)) {
|
||||||
if (!local->isScheduled()) {
|
if (!local->isScheduled()) {
|
||||||
using Flag = Data::MessageUpdate::Flag;
|
|
||||||
_session->data().sentToScheduled({
|
_session->data().sentToScheduled({
|
||||||
.item = local,
|
.history = local->history(),
|
||||||
.scheduledId = scheduledId,
|
.scheduledId = scheduledId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ public:
|
||||||
void applyUpdatesNoPtsCheck(const MTPUpdates &updates);
|
void applyUpdatesNoPtsCheck(const MTPUpdates &updates);
|
||||||
void applyUpdateNoPtsCheck(const MTPUpdate &update);
|
void applyUpdateNoPtsCheck(const MTPUpdate &update);
|
||||||
|
|
||||||
|
void checkForSentToScheduled(const MTPUpdates &updates);
|
||||||
|
|
||||||
[[nodiscard]] int32 pts() const;
|
[[nodiscard]] int32 pts() const;
|
||||||
|
|
||||||
void updateOnline(crl::time lastNonIdleTime = 0);
|
void updateOnline(crl::time lastNonIdleTime = 0);
|
||||||
|
@ -131,7 +133,9 @@ private:
|
||||||
// Doesn't call sendHistoryChangeNotifications itself.
|
// Doesn't call sendHistoryChangeNotifications itself.
|
||||||
void feedUpdate(const MTPUpdate &update);
|
void feedUpdate(const MTPUpdate &update);
|
||||||
|
|
||||||
void applyConvertToScheduledOnSend(const MTPVector<MTPUpdate> &other);
|
void applyConvertToScheduledOnSend(
|
||||||
|
const MTPVector<MTPUpdate> &other,
|
||||||
|
bool skipScheduledCheck = false);
|
||||||
void applyGroupCallParticipantUpdates(const MTPUpdates &updates);
|
void applyGroupCallParticipantUpdates(const MTPUpdates &updates);
|
||||||
|
|
||||||
bool whenGetDiffChanged(
|
bool whenGetDiffChanged(
|
||||||
|
|
|
@ -3329,6 +3329,7 @@ void ApiWrap::forwardMessages(
|
||||||
}
|
}
|
||||||
const auto requestType = Data::Histories::RequestType::Send;
|
const auto requestType = Data::Histories::RequestType::Send;
|
||||||
const auto idsCopy = localIds;
|
const auto idsCopy = localIds;
|
||||||
|
const auto scheduled = action.options.scheduled;
|
||||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||||
history->sendRequestId = request(MTPmessages_ForwardMessages(
|
history->sendRequestId = request(MTPmessages_ForwardMessages(
|
||||||
MTP_flags(sendFlags),
|
MTP_flags(sendFlags),
|
||||||
|
@ -3341,6 +3342,9 @@ void ApiWrap::forwardMessages(
|
||||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||||
Data::ShortcutIdToMTP(_session, action.options.shortcutId)
|
Data::ShortcutIdToMTP(_session, action.options.shortcutId)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
if (!scheduled) {
|
||||||
|
this->updates().checkForSentToScheduled(result);
|
||||||
|
}
|
||||||
applyUpdates(result);
|
applyUpdates(result);
|
||||||
if (shared && !--shared->requestsLeft) {
|
if (shared && !--shared->requestsLeft) {
|
||||||
shared->callback();
|
shared->callback();
|
||||||
|
|
|
@ -1519,3 +1519,22 @@ pickLocationChooseOnMap: RoundButton(defaultActiveButton) {
|
||||||
sendGifBox: Box(defaultBox) {
|
sendGifBox: Box(defaultBox) {
|
||||||
shadowIgnoreBottomSkip: true;
|
shadowIgnoreBottomSkip: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processingVideoTipMaxWidth: 364px;
|
||||||
|
processingVideoTipShift: 10px;
|
||||||
|
processingVideoToast: Toast(defaultToast) {
|
||||||
|
minWidth: 32px;
|
||||||
|
maxWidth: 380px;
|
||||||
|
padding: margins(19px, 17px, 19px, 16px);
|
||||||
|
}
|
||||||
|
processingVideoPreviewSkip: 0px;
|
||||||
|
processingVideoView: RoundButton(defaultActiveButton) {
|
||||||
|
width: -24px;
|
||||||
|
height: 68px;
|
||||||
|
textTop: 26px;
|
||||||
|
textFg: mediaviewTextLinkFg;
|
||||||
|
textFgOver: mediaviewTextLinkFg;
|
||||||
|
textBg: transparent;
|
||||||
|
textBgOver: transparent;
|
||||||
|
ripple: emptyRippleAnimation;
|
||||||
|
}
|
||||||
|
|
|
@ -343,10 +343,20 @@ void ScheduledMessages::apply(
|
||||||
if (i == end(_data)) {
|
if (i == end(_data)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const auto &id : update.vmessages().v) {
|
const auto sent = update.vsent_messages();
|
||||||
|
const auto &ids = update.vmessages().v;
|
||||||
|
for (auto k = 0, count = int(ids.size()); k != count; ++k) {
|
||||||
|
const auto id = ids[k].v;
|
||||||
const auto &list = i->second;
|
const auto &list = i->second;
|
||||||
const auto j = list.itemById.find(id.v);
|
const auto j = list.itemById.find(id);
|
||||||
if (j != end(list.itemById)) {
|
if (j != end(list.itemById)) {
|
||||||
|
if (sent && k < sent->v.size()) {
|
||||||
|
const auto &sentId = sent->v[k];
|
||||||
|
_session->data().sentFromScheduled({
|
||||||
|
.item = j->second,
|
||||||
|
.sentId = sentId.v,
|
||||||
|
});
|
||||||
|
}
|
||||||
j->second->destroy();
|
j->second->destroy();
|
||||||
i = _data.find(history);
|
i = _data.find(history);
|
||||||
if (i == end(_data)) {
|
if (i == end(_data)) {
|
||||||
|
|
|
@ -4821,6 +4821,14 @@ rpl::producer<SentToScheduled> Session::sentToScheduled() const {
|
||||||
return _sentToScheduled.events();
|
return _sentToScheduled.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::sentFromScheduled(SentFromScheduled value) {
|
||||||
|
_sentFromScheduled.fire(std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<SentFromScheduled> Session::sentFromScheduled() const {
|
||||||
|
return _sentFromScheduled.events();
|
||||||
|
}
|
||||||
|
|
||||||
void Session::clearLocalStorage() {
|
void Session::clearLocalStorage() {
|
||||||
_cache->close();
|
_cache->close();
|
||||||
_cache->clear();
|
_cache->clear();
|
||||||
|
|
|
@ -90,9 +90,13 @@ struct GiftUpdate {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SentToScheduled {
|
struct SentToScheduled {
|
||||||
not_null<HistoryItem*> item;
|
not_null<History*> history;
|
||||||
MsgId scheduledId = 0;
|
MsgId scheduledId = 0;
|
||||||
};
|
};
|
||||||
|
struct SentFromScheduled {
|
||||||
|
not_null<HistoryItem*> item;
|
||||||
|
MsgId sentId = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class Session final {
|
class Session final {
|
||||||
public:
|
public:
|
||||||
|
@ -798,6 +802,8 @@ public:
|
||||||
|
|
||||||
void sentToScheduled(SentToScheduled value);
|
void sentToScheduled(SentToScheduled value);
|
||||||
[[nodiscard]] rpl::producer<SentToScheduled> sentToScheduled() const;
|
[[nodiscard]] rpl::producer<SentToScheduled> sentToScheduled() const;
|
||||||
|
void sentFromScheduled(SentFromScheduled value);
|
||||||
|
[[nodiscard]] rpl::producer<SentFromScheduled> sentFromScheduled() const;
|
||||||
|
|
||||||
void clearLocalStorage();
|
void clearLocalStorage();
|
||||||
|
|
||||||
|
@ -972,6 +978,7 @@ private:
|
||||||
rpl::event_stream<> _unreadBadgeChanges;
|
rpl::event_stream<> _unreadBadgeChanges;
|
||||||
rpl::event_stream<RepliesReadTillUpdate> _repliesReadTillUpdates;
|
rpl::event_stream<RepliesReadTillUpdate> _repliesReadTillUpdates;
|
||||||
rpl::event_stream<SentToScheduled> _sentToScheduled;
|
rpl::event_stream<SentToScheduled> _sentToScheduled;
|
||||||
|
rpl::event_stream<SentFromScheduled> _sentFromScheduled;
|
||||||
|
|
||||||
Dialogs::MainList _chatsList;
|
Dialogs::MainList _chatsList;
|
||||||
Dialogs::IndexedList _contactsList;
|
Dialogs::IndexedList _contactsList;
|
||||||
|
|
|
@ -725,19 +725,33 @@ HistoryWidget::HistoryWidget(
|
||||||
|
|
||||||
session().data().sentToScheduled(
|
session().data().sentToScheduled(
|
||||||
) | rpl::start_with_next([=](const Data::SentToScheduled &value) {
|
) | rpl::start_with_next([=](const Data::SentToScheduled &value) {
|
||||||
if (value.item->history() == _history) {
|
const auto history = value.history;
|
||||||
const auto history = value.item->history();
|
if (history == _history) {
|
||||||
const auto id = value.scheduledId;
|
const auto id = value.scheduledId;
|
||||||
crl::on_main(this, [=] {
|
crl::on_main(this, [=] {
|
||||||
controller->showSection(
|
if (history == _history) {
|
||||||
std::make_shared<HistoryView::ScheduledMemento>(
|
controller->showSection(
|
||||||
history,
|
std::make_shared<HistoryView::ScheduledMemento>(
|
||||||
id));
|
history,
|
||||||
|
id));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
session().data().sentFromScheduled(
|
||||||
|
) | rpl::start_with_next([=](const Data::SentFromScheduled &value) {
|
||||||
|
if (value.item->awaitingVideoProcessing()
|
||||||
|
&& !_sentFromScheduledTip
|
||||||
|
&& HistoryView::ShowScheduledVideoPublished(
|
||||||
|
controller,
|
||||||
|
value,
|
||||||
|
crl::guard(this, [=] { _sentFromScheduledTip = false; }))) {
|
||||||
|
_sentFromScheduledTip = true;
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
using MediaSwitch = Media::Player::Instance::Switch;
|
using MediaSwitch = Media::Player::Instance::Switch;
|
||||||
Media::Player::instance()->switchToNextEvents(
|
Media::Player::instance()->switchToNextEvents(
|
||||||
) | rpl::filter([=](const MediaSwitch &pair) {
|
) | rpl::filter([=](const MediaSwitch &pair) {
|
||||||
|
|
|
@ -702,6 +702,7 @@ private:
|
||||||
|
|
||||||
bool _preserveScrollTop = false;
|
bool _preserveScrollTop = false;
|
||||||
bool _repaintFieldScheduled = false;
|
bool _repaintFieldScheduled = false;
|
||||||
|
bool _sentFromScheduledTip = false;
|
||||||
|
|
||||||
mtpRequestId _saveEditMsgRequestId = 0;
|
mtpRequestId _saveEditMsgRequestId = 0;
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history_drag_area.h"
|
#include "history/history_drag_area.h"
|
||||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||||
#include "menu/menu_send.h" // SendMenu::Type.
|
#include "menu/menu_send.h" // SendMenu::Type.
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/widgets/tooltip.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/chat/chat_style.h"
|
#include "ui/chat/chat_style.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
|
#include "ui/toast/toast.h"
|
||||||
|
#include "ui/dynamic_image.h"
|
||||||
|
#include "ui/dynamic_thumbnails.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "api/api_editing.h"
|
#include "api/api_editing.h"
|
||||||
#include "api/api_sending.h"
|
#include "api/api_sending.h"
|
||||||
|
@ -34,7 +39,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "core/mime_type.h"
|
#include "core/mime_type.h"
|
||||||
#include "chat_helpers/tabbed_selector.h"
|
#include "chat_helpers/tabbed_selector.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
#include "data/components/scheduled_messages.h"
|
#include "data/components/scheduled_messages.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_forum.h"
|
#include "data/data_forum.h"
|
||||||
#include "data/data_forum_topic.h"
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
@ -55,6 +63,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <QtCore/QMimeData>
|
#include <QtCore/QMimeData>
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kVideoProcessingInfoDuration = 4 * crl::time(1000);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
ScheduledMemento::ScheduledMemento(
|
ScheduledMemento::ScheduledMemento(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
|
@ -104,33 +117,33 @@ ScheduledWidget::ScheduledWidget(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
const Data::ForumTopic *forumTopic)
|
const Data::ForumTopic *forumTopic)
|
||||||
: Window::SectionWidget(parent, controller, history->peer)
|
: Window::SectionWidget(parent, controller, history->peer)
|
||||||
, WindowListDelegate(controller)
|
, WindowListDelegate(controller)
|
||||||
, _show(controller->uiShow())
|
, _show(controller->uiShow())
|
||||||
, _history(history)
|
, _history(history)
|
||||||
, _forumTopic(forumTopic)
|
, _forumTopic(forumTopic)
|
||||||
, _scroll(
|
, _scroll(
|
||||||
this,
|
this,
|
||||||
controller->chatStyle()->value(lifetime(), st::historyScroll),
|
controller->chatStyle()->value(lifetime(), st::historyScroll),
|
||||||
false)
|
false)
|
||||||
, _topBar(this, controller)
|
, _topBar(this, controller)
|
||||||
, _topBarShadow(this)
|
, _topBarShadow(this)
|
||||||
, _composeControls(std::make_unique<ComposeControls>(
|
, _composeControls(std::make_unique<ComposeControls>(
|
||||||
this,
|
this,
|
||||||
ComposeControlsDescriptor{
|
ComposeControlsDescriptor{
|
||||||
.show = controller->uiShow(),
|
.show = controller->uiShow(),
|
||||||
.unavailableEmojiPasted = [=](not_null<DocumentData*> emoji) {
|
.unavailableEmojiPasted = [=](not_null<DocumentData*> emoji) {
|
||||||
listShowPremiumToast(emoji);
|
listShowPremiumToast(emoji);
|
||||||
},
|
},
|
||||||
.mode = ComposeControls::Mode::Scheduled,
|
.mode = ComposeControls::Mode::Scheduled,
|
||||||
.sendMenuDetails = [] { return SendMenu::Details(); },
|
.sendMenuDetails = [] { return SendMenu::Details(); },
|
||||||
.regularWindow = controller,
|
.regularWindow = controller,
|
||||||
.stickerOrEmojiChosen = controller->stickerOrEmojiChosen(),
|
.stickerOrEmojiChosen = controller->stickerOrEmojiChosen(),
|
||||||
}))
|
}))
|
||||||
, _cornerButtons(
|
, _cornerButtons(
|
||||||
_scroll.data(),
|
_scroll.data(),
|
||||||
controller->chatStyle(),
|
controller->chatStyle(),
|
||||||
static_cast<HistoryView::CornerButtonsDelegate*>(this)) {
|
static_cast<HistoryView::CornerButtonsDelegate*>(this)) {
|
||||||
controller->chatStyle()->paletteChanged(
|
controller->chatStyle()->paletteChanged(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
_scroll->updateBars();
|
_scroll->updateBars();
|
||||||
|
@ -1070,6 +1083,24 @@ void ScheduledWidget::saveState(not_null<ScheduledMemento*> memento) {
|
||||||
|
|
||||||
void ScheduledWidget::restoreState(not_null<ScheduledMemento*> memento) {
|
void ScheduledWidget::restoreState(not_null<ScheduledMemento*> memento) {
|
||||||
_inner->restoreState(memento->list());
|
_inner->restoreState(memento->list());
|
||||||
|
if (const auto id = memento->sentToScheduledId()) {
|
||||||
|
const auto item = _history->owner().message(_history->peer, id);
|
||||||
|
if (item) {
|
||||||
|
controller()->showToast({
|
||||||
|
.title = tr::lng_scheduled_video_tip_title(tr::now),
|
||||||
|
.text = { tr::lng_scheduled_video_tip_text(tr::now) },
|
||||||
|
.attach = RectPart::Top,
|
||||||
|
.duration = kVideoProcessingInfoDuration,
|
||||||
|
});
|
||||||
|
clearProcessingVideoTracking(false);
|
||||||
|
_processingVideoPosition = item->position();
|
||||||
|
_processingVideoTipTimer.setCallback([=] {
|
||||||
|
_processingVideoCanShow = true;
|
||||||
|
updateInnerVisibleArea();
|
||||||
|
});
|
||||||
|
_processingVideoTipTimer.callOnce(kVideoProcessingInfoDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduledWidget::resizeEvent(QResizeEvent *e) {
|
void ScheduledWidget::resizeEvent(QResizeEvent *e) {
|
||||||
|
@ -1141,9 +1172,153 @@ void ScheduledWidget::updateInnerVisibleArea() {
|
||||||
checkReplyReturns();
|
checkReplyReturns();
|
||||||
}
|
}
|
||||||
const auto scrollTop = _scroll->scrollTop();
|
const auto scrollTop = _scroll->scrollTop();
|
||||||
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
const auto scrollBottom = scrollTop + _scroll->height();
|
||||||
|
_inner->setVisibleTopBottom(scrollTop, scrollBottom);
|
||||||
_cornerButtons.updateJumpDownVisibility();
|
_cornerButtons.updateJumpDownVisibility();
|
||||||
_cornerButtons.updateUnreadThingsVisibility();
|
_cornerButtons.updateUnreadThingsVisibility();
|
||||||
|
if (!_processingVideoLifetime) {
|
||||||
|
if (const auto &position = _processingVideoPosition) {
|
||||||
|
if (const auto view = _inner->viewByPosition(position)) {
|
||||||
|
initProcessingVideoView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkProcessingVideoTooltip(scrollTop, scrollBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::initProcessingVideoView(not_null<Element*> view) {
|
||||||
|
_processingVideoView = view;
|
||||||
|
|
||||||
|
controller()->session().data().sentFromScheduled(
|
||||||
|
) | rpl::start_with_next([=](const Data::SentFromScheduled &value) {
|
||||||
|
if (value.item->position() == _processingVideoPosition) {
|
||||||
|
controller()->showPeerHistory(
|
||||||
|
value.item->history(),
|
||||||
|
Window::SectionShow::Way::Backward,
|
||||||
|
value.sentId);
|
||||||
|
}
|
||||||
|
}, _processingVideoLifetime);
|
||||||
|
|
||||||
|
controller()->session().data().viewRemoved(
|
||||||
|
) | rpl::start_with_next([=](not_null<const Element*> view) {
|
||||||
|
if (view == _processingVideoView.get()) {
|
||||||
|
const auto position = _processingVideoPosition;
|
||||||
|
if (const auto now = _inner->viewByPosition(position)) {
|
||||||
|
_processingVideoView = now;
|
||||||
|
updateProcessingVideoTooltipPosition();
|
||||||
|
} else {
|
||||||
|
clearProcessingVideoTracking(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, _processingVideoLifetime);
|
||||||
|
|
||||||
|
controller()->session().data().viewResizeRequest(
|
||||||
|
) | rpl::start_with_next([this](not_null<const Element*> view) {
|
||||||
|
if (view->delegate() == _inner.data()) {
|
||||||
|
if (!_processingVideoUpdateScheduled) {
|
||||||
|
if (const auto tooltip = _processingVideoTooltip.get()) {
|
||||||
|
_processingVideoUpdateScheduled = true;
|
||||||
|
crl::on_main(tooltip, [=] {
|
||||||
|
_processingVideoUpdateScheduled = false;
|
||||||
|
updateProcessingVideoTooltipPosition();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, _processingVideoLifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::clearProcessingVideoTracking(bool fast) {
|
||||||
|
if (const auto tooltip = _processingVideoTooltip.release()) {
|
||||||
|
tooltip->toggleAnimated(false);
|
||||||
|
}
|
||||||
|
_processingVideoPosition = {};
|
||||||
|
if (const auto tooltip = _processingVideoTooltip.release()) {
|
||||||
|
if (fast) {
|
||||||
|
tooltip->toggleFast(false);
|
||||||
|
} else {
|
||||||
|
tooltip->toggleAnimated(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_processingVideoTooltipShown = false;
|
||||||
|
_processingVideoCanShow = false;
|
||||||
|
_processingVideoView = nullptr;
|
||||||
|
_processingVideoTipTimer.cancel();
|
||||||
|
_processingVideoLifetime.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::checkProcessingVideoTooltip(
|
||||||
|
int visibleTop,
|
||||||
|
int visibleBottom) {
|
||||||
|
if (_processingVideoTooltip
|
||||||
|
|| _processingVideoTooltipShown
|
||||||
|
|| !_processingVideoCanShow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto view = _processingVideoView.get();
|
||||||
|
if (!view) {
|
||||||
|
_processingVideoCanShow = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto rect = view->effectIconGeometry();
|
||||||
|
if (rect.top() > visibleTop
|
||||||
|
&& rect.top() + rect.height() <= visibleBottom) {
|
||||||
|
showProcessingVideoTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::updateProcessingVideoTooltipPosition() {
|
||||||
|
const auto tooltip = _processingVideoTooltip.get();
|
||||||
|
if (!tooltip) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto view = _processingVideoView.get();
|
||||||
|
if (!view) {
|
||||||
|
clearProcessingVideoTracking(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto shift = view->skipBlockWidth() / 2;
|
||||||
|
const auto rect = view->effectIconGeometry().translated(shift, 0);
|
||||||
|
const auto countPosition = [=](QSize size) {
|
||||||
|
const auto origin = rect.bottomLeft();
|
||||||
|
return origin - QPoint(
|
||||||
|
size.width() / 2,
|
||||||
|
size.height() + st::processingVideoTipShift);
|
||||||
|
};
|
||||||
|
tooltip->pointAt(rect, RectPart::Top, countPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledWidget::showProcessingVideoTooltip() {
|
||||||
|
_processingVideoTooltipShown = true;
|
||||||
|
_processingVideoTooltip = std::make_unique<Ui::ImportantTooltip>(
|
||||||
|
_inner.data(),
|
||||||
|
Ui::MakeNiceTooltipLabel(
|
||||||
|
_inner.data(),
|
||||||
|
tr::lng_scheduled_video_tip(Ui::Text::WithEntities),
|
||||||
|
st::processingVideoTipMaxWidth,
|
||||||
|
st::defaultImportantTooltipLabel),
|
||||||
|
st::defaultImportantTooltip);
|
||||||
|
const auto tooltip = _processingVideoTooltip.get();
|
||||||
|
const auto weak = QPointer<QWidget>(tooltip);
|
||||||
|
const auto destroy = [=] {
|
||||||
|
delete weak.data();
|
||||||
|
};
|
||||||
|
tooltip->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
tooltip->setHiddenCallback([=] {
|
||||||
|
const auto tip = _processingVideoTooltip.get();
|
||||||
|
if (tooltip == tip) {
|
||||||
|
_processingVideoTooltip.release();
|
||||||
|
}
|
||||||
|
crl::on_main(tip, [=] {
|
||||||
|
delete tip;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
updateProcessingVideoTooltipPosition();
|
||||||
|
tooltip->toggleAnimated(true);
|
||||||
|
_processingVideoTipTimer.setCallback(crl::guard(tooltip, [=] {
|
||||||
|
tooltip->toggleAnimated(false);
|
||||||
|
}));
|
||||||
|
_processingVideoTipTimer.callOnce(kVideoProcessingInfoDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduledWidget::showAnimatedHook(
|
void ScheduledWidget::showAnimatedHook(
|
||||||
|
@ -1495,4 +1670,114 @@ void ScheduledWidget::setupDragArea() {
|
||||||
areas.photo->setDroppedCallback(droppedCallback(true));
|
areas.photo->setDroppedCallback(droppedCallback(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShowScheduledVideoPublished(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
const Data::SentFromScheduled &info,
|
||||||
|
Fn<void()> hidden) {
|
||||||
|
if (!controller->widget()->isActive()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto media = info.item->media();
|
||||||
|
const auto document = media ? media->document() : nullptr;
|
||||||
|
if (!document->isVideoFile()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto history = info.item->history();
|
||||||
|
const auto itemId = info.sentId;
|
||||||
|
|
||||||
|
const auto text = tr::lng_scheduled_video_published(
|
||||||
|
tr::now,
|
||||||
|
Ui::Text::Bold);
|
||||||
|
const auto &st = st::processingVideoToast;
|
||||||
|
const auto skip = st::processingVideoPreviewSkip;
|
||||||
|
const auto size = st.style.font->height * 2;
|
||||||
|
const auto view = tr::lng_scheduled_video_view(tr::now);
|
||||||
|
const auto additional = QMargins(
|
||||||
|
skip + size,
|
||||||
|
0,
|
||||||
|
(st::processingVideoView.style.font->width(view)
|
||||||
|
- (st::processingVideoView.width / 2)),
|
||||||
|
0);
|
||||||
|
|
||||||
|
const auto parent = controller->uiShow()->toastParent();
|
||||||
|
const auto weak = Ui::Toast::Show(parent, Ui::Toast::Config{
|
||||||
|
.text = text,
|
||||||
|
.padding = rpl::single(additional),
|
||||||
|
.st = &st,
|
||||||
|
.attach = RectPart::Top,
|
||||||
|
.acceptinput = true,
|
||||||
|
.duration = kVideoProcessingInfoDuration,
|
||||||
|
});
|
||||||
|
const auto strong = weak.get();
|
||||||
|
if (!strong) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto widget = strong->widget();
|
||||||
|
const auto hideToast = [weak] {
|
||||||
|
if (const auto strong = weak.get()) {
|
||||||
|
strong->hideAnimated();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto clickableBackground = Ui::CreateChild<Ui::AbstractButton>(
|
||||||
|
widget.get());
|
||||||
|
clickableBackground->setPointerCursor(false);
|
||||||
|
clickableBackground->setAcceptBoth();
|
||||||
|
clickableBackground->show();
|
||||||
|
clickableBackground->addClickHandler([=](Qt::MouseButton button) {
|
||||||
|
if (button == Qt::RightButton) {
|
||||||
|
hideToast();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto button = Ui::CreateChild<Ui::RoundButton>(
|
||||||
|
widget.get(),
|
||||||
|
rpl::single(view),
|
||||||
|
st::processingVideoView);
|
||||||
|
button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||||
|
button->show();
|
||||||
|
rpl::combine(
|
||||||
|
widget->sizeValue(),
|
||||||
|
button->sizeValue()
|
||||||
|
) | rpl::start_with_next([=](QSize outer, QSize inner) {
|
||||||
|
button->moveToRight(
|
||||||
|
0,
|
||||||
|
(outer.height() - inner.height()) / 2,
|
||||||
|
outer.width());
|
||||||
|
clickableBackground->resize(outer);
|
||||||
|
}, widget->lifetime());
|
||||||
|
const auto preview = Ui::CreateChild<Ui::RpWidget>(widget.get());
|
||||||
|
preview->moveToLeft(skip, skip);
|
||||||
|
preview->resize(size, size);
|
||||||
|
preview->show();
|
||||||
|
|
||||||
|
const auto thumbnail = Ui::MakeDocumentThumbnail(document, FullMsgId(
|
||||||
|
history->peer->id,
|
||||||
|
itemId));
|
||||||
|
thumbnail->subscribeToUpdates([=] {
|
||||||
|
preview->update();
|
||||||
|
});
|
||||||
|
preview->paintRequest(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
auto p = QPainter(preview);
|
||||||
|
const auto image = Images::Round(
|
||||||
|
thumbnail->image(size),
|
||||||
|
ImageRoundRadius::Small);
|
||||||
|
p.drawImage(QRect(0, 0, size, size), image);
|
||||||
|
}, preview->lifetime());
|
||||||
|
|
||||||
|
button->setClickedCallback([=] {
|
||||||
|
controller->showPeerHistory(
|
||||||
|
history,
|
||||||
|
Window::SectionShow::Way::Forward,
|
||||||
|
itemId);
|
||||||
|
hideToast();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hidden) {
|
||||||
|
widget->lifetime().add(std::move(hidden));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -21,6 +21,10 @@ namespace ChatHelpers {
|
||||||
class Show;
|
class Show;
|
||||||
} // namespace ChatHelpers
|
} // namespace ChatHelpers
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
struct SentFromScheduled;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace SendMenu {
|
namespace SendMenu {
|
||||||
struct Details;
|
struct Details;
|
||||||
} // namespace SendMenu
|
} // namespace SendMenu
|
||||||
|
@ -37,6 +41,7 @@ class PlainShadow;
|
||||||
class FlatButton;
|
class FlatButton;
|
||||||
struct PreparedList;
|
struct PreparedList;
|
||||||
class SendFilesWay;
|
class SendFilesWay;
|
||||||
|
class ImportantTooltip;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Profile {
|
namespace Profile {
|
||||||
|
@ -51,6 +56,10 @@ namespace HistoryView::Controls {
|
||||||
struct VoiceToSend;
|
struct VoiceToSend;
|
||||||
} // namespace HistoryView::Controls
|
} // namespace HistoryView::Controls
|
||||||
|
|
||||||
|
namespace Window {
|
||||||
|
class SessionController;
|
||||||
|
} // namespace Window
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
|
||||||
class Element;
|
class Element;
|
||||||
|
@ -199,6 +208,12 @@ private:
|
||||||
Data::MessagePosition position,
|
Data::MessagePosition position,
|
||||||
FullMsgId originId = {});
|
FullMsgId originId = {});
|
||||||
|
|
||||||
|
void initProcessingVideoView(not_null<Element*> view);
|
||||||
|
void checkProcessingVideoTooltip(int visibleTop, int visibleBottom);
|
||||||
|
void showProcessingVideoTooltip();
|
||||||
|
void updateProcessingVideoTooltipPosition();
|
||||||
|
void clearProcessingVideoTracking(bool fast);
|
||||||
|
|
||||||
void setupComposeControls();
|
void setupComposeControls();
|
||||||
|
|
||||||
void setupDragArea();
|
void setupDragArea();
|
||||||
|
@ -277,7 +292,16 @@ private:
|
||||||
std::unique_ptr<ComposeControls> _composeControls;
|
std::unique_ptr<ComposeControls> _composeControls;
|
||||||
bool _skipScrollEvent = false;
|
bool _skipScrollEvent = false;
|
||||||
|
|
||||||
|
Data::MessagePosition _processingVideoPosition;
|
||||||
|
base::weak_ptr<Element> _processingVideoView;
|
||||||
|
rpl::lifetime _processingVideoLifetime;
|
||||||
|
|
||||||
std::unique_ptr<HistoryView::StickerToast> _stickerToast;
|
std::unique_ptr<HistoryView::StickerToast> _stickerToast;
|
||||||
|
std::unique_ptr<Ui::ImportantTooltip> _processingVideoTooltip;
|
||||||
|
base::Timer _processingVideoTipTimer;
|
||||||
|
bool _processingVideoUpdateScheduled = false;
|
||||||
|
bool _processingVideoTooltipShown = false;
|
||||||
|
bool _processingVideoCanShow = false;
|
||||||
|
|
||||||
CornerButtons _cornerButtons;
|
CornerButtons _cornerButtons;
|
||||||
|
|
||||||
|
@ -299,20 +323,29 @@ public:
|
||||||
Window::Column column,
|
Window::Column column,
|
||||||
const QRect &geometry) override;
|
const QRect &geometry) override;
|
||||||
|
|
||||||
not_null<History*> getHistory() const {
|
[[nodiscard]] not_null<History*> getHistory() const {
|
||||||
return _history;
|
return _history;
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<ListMemento*> list() {
|
[[nodiscard]] not_null<ListMemento*> list() {
|
||||||
return &_list;
|
return &_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] MsgId sentToScheduledId() const {
|
||||||
|
return _sentToScheduledId;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
const Data::ForumTopic *_forumTopic;
|
const Data::ForumTopic *_forumTopic;
|
||||||
ListMemento _list;
|
ListMemento _list;
|
||||||
MsgId _sentToScheduledId;
|
MsgId _sentToScheduledId = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool ShowScheduledVideoPublished(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
const Data::SentFromScheduled &info,
|
||||||
|
Fn<void()> hidden = nullptr);
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -1982,10 +1982,12 @@ bool Gif::dataLoaded() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Gif::needInfoDisplay() const {
|
bool Gif::needInfoDisplay() const {
|
||||||
if (_parent->data()->isFakeAboutView()) {
|
const auto item = _parent->data();
|
||||||
|
if (item->isFakeAboutView()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _parent->data()->isSending()
|
return item->isSending()
|
||||||
|
|| item->awaitingVideoProcessing()
|
||||||
|| _data->uploading()
|
|| _data->uploading()
|
||||||
|| _parent->isUnderCursor()
|
|| _parent->isUnderCursor()
|
||||||
|| (_parent->delegate()->elementContext() == Context::ChatPreview)
|
|| (_parent->delegate()->elementContext() == Context::ChatPreview)
|
||||||
|
|
|
@ -893,9 +893,11 @@ bool GroupedMedia::computeNeedBubble() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GroupedMedia::needInfoDisplay() const {
|
bool GroupedMedia::needInfoDisplay() const {
|
||||||
|
const auto item = _parent->data();
|
||||||
return (_mode != Mode::Column)
|
return (_mode != Mode::Column)
|
||||||
&& (_parent->data()->isSending()
|
&& (item->isSending()
|
||||||
|| _parent->data()->hasFailed()
|
|| item->awaitingVideoProcessing()
|
||||||
|
|| item->hasFailed()
|
||||||
|| _parent->isUnderCursor()
|
|| _parent->isUnderCursor()
|
||||||
|| (_parent->delegate()->elementContext() == Context::ChatPreview)
|
|| (_parent->delegate()->elementContext() == Context::ChatPreview)
|
||||||
|| _parent->isLastAndSelfMessage());
|
|| _parent->isLastAndSelfMessage());
|
||||||
|
|
|
@ -820,7 +820,7 @@ rpl::producer<uint64> AddCurrencyAction(
|
||||||
) | rpl::start_with_error_done([=](const QString &error) {
|
) | rpl::start_with_error_done([=](const QString &error) {
|
||||||
currencyLoadLifetime->destroy();
|
currencyLoadLifetime->destroy();
|
||||||
}, [=] {
|
}, [=] {
|
||||||
if (const auto strong = weak.get()) {
|
if (const auto strong = weak.data()) {
|
||||||
state->balance = currencyLoad->data().currentBalance;
|
state->balance = currencyLoad->data().currentBalance;
|
||||||
currencyLoadLifetime->destroy();
|
currencyLoadLifetime->destroy();
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,9 +59,9 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class StoryThumbnail : public DynamicImage {
|
class MediaThumbnail : public DynamicImage {
|
||||||
public:
|
public:
|
||||||
explicit StoryThumbnail(Data::FileOrigin origin, bool forceRound);
|
explicit MediaThumbnail(Data::FileOrigin origin, bool forceRound);
|
||||||
|
|
||||||
QImage image(int size) override;
|
QImage image(int size) override;
|
||||||
void subscribeToUpdates(Fn<void()> callback) override;
|
void subscribeToUpdates(Fn<void()> callback) override;
|
||||||
|
@ -89,7 +89,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PhotoThumbnail final : public StoryThumbnail {
|
class PhotoThumbnail final : public MediaThumbnail {
|
||||||
public:
|
public:
|
||||||
PhotoThumbnail(
|
PhotoThumbnail(
|
||||||
not_null<PhotoData*> photo,
|
not_null<PhotoData*> photo,
|
||||||
|
@ -108,7 +108,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class VideoThumbnail final : public StoryThumbnail {
|
class VideoThumbnail final : public MediaThumbnail {
|
||||||
public:
|
public:
|
||||||
VideoThumbnail(
|
VideoThumbnail(
|
||||||
not_null<DocumentData*> video,
|
not_null<DocumentData*> video,
|
||||||
|
@ -304,12 +304,12 @@ void PeerUserpic::processNewPhoto() {
|
||||||
}, _subscribed->downloadLifetime);
|
}, _subscribed->downloadLifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
StoryThumbnail::StoryThumbnail(Data::FileOrigin origin, bool forceRound)
|
MediaThumbnail::MediaThumbnail(Data::FileOrigin origin, bool forceRound)
|
||||||
: _origin(origin)
|
: _origin(origin)
|
||||||
, _forceRound(forceRound) {
|
, _forceRound(forceRound) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage StoryThumbnail::image(int size) {
|
QImage MediaThumbnail::image(int size) {
|
||||||
const auto ratio = style::DevicePixelRatio();
|
const auto ratio = style::DevicePixelRatio();
|
||||||
if (_prepared.width() != size * ratio) {
|
if (_prepared.width() != size * ratio) {
|
||||||
if (_full.isNull()) {
|
if (_full.isNull()) {
|
||||||
|
@ -333,7 +333,7 @@ QImage StoryThumbnail::image(int size) {
|
||||||
return _prepared;
|
return _prepared;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StoryThumbnail::subscribeToUpdates(Fn<void()> callback) {
|
void MediaThumbnail::subscribeToUpdates(Fn<void()> callback) {
|
||||||
_subscription.destroy();
|
_subscription.destroy();
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
clear();
|
clear();
|
||||||
|
@ -363,11 +363,11 @@ void StoryThumbnail::subscribeToUpdates(Fn<void()> callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::FileOrigin StoryThumbnail::origin() const {
|
Data::FileOrigin MediaThumbnail::origin() const {
|
||||||
return _origin;
|
return _origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StoryThumbnail::forceRound() const {
|
bool MediaThumbnail::forceRound() const {
|
||||||
return _forceRound;
|
return _forceRound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ PhotoThumbnail::PhotoThumbnail(
|
||||||
not_null<PhotoData*> photo,
|
not_null<PhotoData*> photo,
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
bool forceRound)
|
bool forceRound)
|
||||||
: StoryThumbnail(origin, forceRound)
|
: MediaThumbnail(origin, forceRound)
|
||||||
, _photo(photo) {
|
, _photo(photo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +387,7 @@ Main::Session &PhotoThumbnail::session() {
|
||||||
return _photo->session();
|
return _photo->session();
|
||||||
}
|
}
|
||||||
|
|
||||||
StoryThumbnail::Thumb PhotoThumbnail::loaded(Data::FileOrigin origin) {
|
MediaThumbnail::Thumb PhotoThumbnail::loaded(Data::FileOrigin origin) {
|
||||||
if (!_media) {
|
if (!_media) {
|
||||||
_media = _photo->createMediaView();
|
_media = _photo->createMediaView();
|
||||||
_media->wanted(Data::PhotoSize::Small, origin);
|
_media->wanted(Data::PhotoSize::Small, origin);
|
||||||
|
@ -406,7 +406,7 @@ VideoThumbnail::VideoThumbnail(
|
||||||
not_null<DocumentData*> video,
|
not_null<DocumentData*> video,
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
bool forceRound)
|
bool forceRound)
|
||||||
: StoryThumbnail(origin, forceRound)
|
: MediaThumbnail(origin, forceRound)
|
||||||
, _video(video) {
|
, _video(video) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +418,7 @@ Main::Session &VideoThumbnail::session() {
|
||||||
return _video->session();
|
return _video->session();
|
||||||
}
|
}
|
||||||
|
|
||||||
StoryThumbnail::Thumb VideoThumbnail::loaded(Data::FileOrigin origin) {
|
MediaThumbnail::Thumb VideoThumbnail::loaded(Data::FileOrigin origin) {
|
||||||
if (!_media) {
|
if (!_media) {
|
||||||
_media = _video->createMediaView();
|
_media = _video->createMediaView();
|
||||||
_media->thumbnailWanted(origin);
|
_media->thumbnailWanted(origin);
|
||||||
|
|
|
@ -14,6 +14,7 @@ class PhotoData;
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Story;
|
class Story;
|
||||||
class Session;
|
class Session;
|
||||||
|
struct FileOrigin;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
@ -33,7 +34,6 @@ class DynamicImage;
|
||||||
[[nodiscard]] std::shared_ptr<DynamicImage> MakeEmojiThumbnail(
|
[[nodiscard]] std::shared_ptr<DynamicImage> MakeEmojiThumbnail(
|
||||||
not_null<Data::Session*> owner,
|
not_null<Data::Session*> owner,
|
||||||
const QString &data);
|
const QString &data);
|
||||||
|
|
||||||
[[nodiscard]] std::shared_ptr<DynamicImage> MakePhotoThumbnail(
|
[[nodiscard]] std::shared_ptr<DynamicImage> MakePhotoThumbnail(
|
||||||
not_null<PhotoData*> photo,
|
not_null<PhotoData*> photo,
|
||||||
FullMsgId fullId);
|
FullMsgId fullId);
|
||||||
|
|
Loading…
Add table
Reference in a new issue