Fix crash in file inline bot results.

Fixes #4904.
This commit is contained in:
John Preston 2018-06-28 16:01:32 +01:00
parent 2f5fb3688a
commit 831f1b6aee
3 changed files with 64 additions and 46 deletions

View File

@ -30,10 +30,12 @@ namespace internal {
using TextState = HistoryView::TextState; using TextState = HistoryView::TextState;
FileBase::FileBase(not_null<Context*> context, Result *result) : ItemBase(context, result) { FileBase::FileBase(not_null<Context*> context, not_null<Result*> result)
: ItemBase(context, result) {
} }
FileBase::FileBase(not_null<Context*> context, DocumentData *document) : ItemBase(context, document) { FileBase::FileBase(not_null<Context*> context, DocumentData *document)
: ItemBase(context, document) {
} }
DocumentData *FileBase::getShownDocument() const { DocumentData *FileBase::getShownDocument() const {
@ -688,13 +690,19 @@ void CancelFileClickHandler::onClickImpl() const {
_result->cancelFile(); _result->cancelFile();
} }
File::File(not_null<Context*> context, Result *result) : FileBase(context, result) File::File(not_null<Context*> context, not_null<Result*> result)
: FileBase(context, result)
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::msgFileSize - st::inlineThumbSkip) , _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::msgFileSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::msgFileSize - st::inlineThumbSkip) , _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::msgFileSize - st::inlineThumbSkip)
, _open(std::make_shared<OpenFileClickHandler>(result)) , _open(std::make_shared<OpenFileClickHandler>(result))
, _cancel(std::make_shared<CancelFileClickHandler>(result)) { , _cancel(std::make_shared<CancelFileClickHandler>(result))
, _document(getShownDocument()) {
updateStatusText(); updateStatusText();
regDocumentItem(getShownDocument(), this);
// We have to save document, not read it from Result every time.
// Because we first delete the Result and then delete this File.
// So in destructor we have to remember _document, we can't read it.
regDocumentItem(_document, this);
} }
void File::initDimensions() { void File::initDimensions() {
@ -712,14 +720,14 @@ void File::initDimensions() {
} }
void File::paint(Painter &p, const QRect &clip, const PaintContext *context) const { void File::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
int32 left = st::msgFileSize + st::inlineThumbSkip; const auto left = st::msgFileSize + st::inlineThumbSkip;
DocumentData *document = getShownDocument(); const auto loaded = _document->loaded();
bool loaded = document->loaded(), displayLoading = document->displayLoading(); const auto displayLoading = _document->displayLoading();
if (displayLoading) { if (displayLoading) {
ensureAnimation(); ensureAnimation();
if (!_animation->radial.animating()) { if (!_animation->radial.animating()) {
_animation->radial.start(document->progress()); _animation->radial.start(_document->progress());
} }
} }
bool showPause = updateStatusText(); bool showPause = updateStatusText();
@ -731,7 +739,7 @@ void File::paint(Painter &p, const QRect &clip, const PaintContext *context) con
auto over = _animation->a_thumbOver.current(); auto over = _animation->a_thumbOver.current();
p.setBrush(anim::brush(st::msgFileInBg, st::msgFileInBgOver, over)); p.setBrush(anim::brush(st::msgFileInBg, st::msgFileInBgOver, over));
} else { } else {
bool over = ClickHandler::showAsActive(document->loading() ? _cancel : _open); bool over = ClickHandler::showAsActive(_document->loading() ? _cancel : _open);
p.setBrush(over ? st::msgFileInBgOver : st::msgFileInBg); p.setBrush(over ? st::msgFileInBgOver : st::msgFileInBg);
} }
@ -745,15 +753,16 @@ void File::paint(Painter &p, const QRect &clip, const PaintContext *context) con
_animation->radial.draw(p, radialCircle, st::msgFileRadialLine, st::historyFileInRadialFg); _animation->radial.draw(p, radialCircle, st::msgFileRadialLine, st::historyFileInRadialFg);
} }
auto icon = ([showPause, radial, document] { auto icon = ([&] {
if (showPause) { if (showPause) {
return &st::historyFileInPause; return &st::historyFileInPause;
} else if (radial || document->loading()) { } else if (radial || _document->loading()) {
return &st::historyFileInCancel; return &st::historyFileInCancel;
} else if (true || document->loaded()) { } else if (true || _document->loaded()) {
if (document->isImage()) { if (_document->isImage()) {
return &st::historyFileInImage; return &st::historyFileInImage;
} else if (document->isVoiceMessage() || document->isAudioFile()) { } else if (_document->isVoiceMessage()
|| _document->isAudioFile()) {
return &st::historyFileInPlay; return &st::historyFileInPlay;
} }
return &st::historyFileInDocument; return &st::historyFileInDocument;
@ -790,7 +799,7 @@ TextState File::getState(
QPoint point, QPoint point,
StateRequest request) const { StateRequest request) const {
if (QRect(0, st::inlineRowMargin, st::msgFileSize, st::msgFileSize).contains(point)) { if (QRect(0, st::inlineRowMargin, st::msgFileSize, st::msgFileSize).contains(point)) {
return { nullptr, getShownDocument()->loading() ? _cancel : _open }; return { nullptr, _document->loading() ? _cancel : _open };
} else { } else {
auto left = st::msgFileSize + st::inlineThumbSkip; auto left = st::msgFileSize + st::inlineThumbSkip;
if (QRect(left, 0, _width - left, _height).contains(point)) { if (QRect(left, 0, _width - left, _height).contains(point)) {
@ -808,7 +817,7 @@ void File::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
} }
File::~File() { File::~File() {
unregDocumentItem(getShownDocument(), this); unregDocumentItem(_document, this);
} }
void File::thumbAnimationCallback() { void File::thumbAnimationCallback() {
@ -819,8 +828,10 @@ void File::step_radial(TimeMs ms, bool timer) {
if (timer) { if (timer) {
update(); update();
} else { } else {
DocumentData *document = getShownDocument(); _animation->radial.update(
_animation->radial.update(document->progress(), !document->loading() || document->loaded(), ms); _document->progress(),
!_document->loading() || _document->loaded(),
ms);
if (!_animation->radial.animating()) { if (!_animation->radial.animating()) {
checkAnimationFinished(); checkAnimationFinished();
} }
@ -834,8 +845,10 @@ void File::ensureAnimation() const {
} }
void File::checkAnimationFinished() const { void File::checkAnimationFinished() const {
if (_animation && !_animation->a_thumbOver.animating() && !_animation->radial.animating()) { if (_animation
if (getShownDocument()->loaded()) { && !_animation->a_thumbOver.animating()
&& !_animation->radial.animating()) {
if (_document->loaded()) {
_animation.reset(); _animation.reset();
} }
} }
@ -844,32 +857,31 @@ void File::checkAnimationFinished() const {
bool File::updateStatusText() const { bool File::updateStatusText() const {
bool showPause = false; bool showPause = false;
int32 statusSize = 0, realDuration = 0; int32 statusSize = 0, realDuration = 0;
DocumentData *document = getShownDocument(); if (_document->status == FileDownloadFailed || _document->status == FileUploadFailed) {
if (document->status == FileDownloadFailed || document->status == FileUploadFailed) {
statusSize = FileStatusSizeFailed; statusSize = FileStatusSizeFailed;
} else if (document->uploading()) { } else if (_document->uploading()) {
statusSize = document->uploadingData->offset; statusSize = _document->uploadingData->offset;
} else if (document->loading()) { } else if (_document->loading()) {
statusSize = document->loadOffset(); statusSize = _document->loadOffset();
} else if (document->loaded()) { } else if (_document->loaded()) {
using State = Media::Player::State; using State = Media::Player::State;
if (document->isVoiceMessage()) { if (_document->isVoiceMessage()) {
statusSize = FileStatusSizeLoaded; statusSize = FileStatusSizeLoaded;
auto state = Media::Player::mixer()->currentState(AudioMsgId::Type::Voice); auto state = Media::Player::mixer()->currentState(AudioMsgId::Type::Voice);
if (state.id == AudioMsgId(document, FullMsgId()) && !Media::Player::IsStoppedOrStopping(state.state)) { if (state.id == AudioMsgId(_document, FullMsgId()) && !Media::Player::IsStoppedOrStopping(state.state)) {
statusSize = -1 - (state.position / state.frequency); statusSize = -1 - (state.position / state.frequency);
realDuration = (state.length / state.frequency); realDuration = (state.length / state.frequency);
showPause = (state.state == State::Playing || state.state == State::Resuming || state.state == State::Starting); showPause = (state.state == State::Playing || state.state == State::Resuming || state.state == State::Starting);
} }
} else if (document->isAudioFile()) { } else if (_document->isAudioFile()) {
statusSize = FileStatusSizeLoaded; statusSize = FileStatusSizeLoaded;
auto state = Media::Player::mixer()->currentState(AudioMsgId::Type::Song); auto state = Media::Player::mixer()->currentState(AudioMsgId::Type::Song);
if (state.id == AudioMsgId(document, FullMsgId()) && !Media::Player::IsStoppedOrStopping(state.state)) { if (state.id == AudioMsgId(_document, FullMsgId()) && !Media::Player::IsStoppedOrStopping(state.state)) {
statusSize = -1 - (state.position / state.frequency); statusSize = -1 - (state.position / state.frequency);
realDuration = (state.length / state.frequency); realDuration = (state.length / state.frequency);
showPause = (state.state == State::Playing || state.state == State::Resuming || state.state == State::Starting); showPause = (state.state == State::Playing || state.state == State::Resuming || state.state == State::Starting);
} }
if (!showPause && (state.id == AudioMsgId(document, FullMsgId())) && Media::Player::instance()->isSeeking(AudioMsgId::Type::Song)) { if (!showPause && (state.id == AudioMsgId(_document, FullMsgId())) && Media::Player::instance()->isSeeking(AudioMsgId::Type::Song)) {
showPause = true; showPause = true;
} }
} else { } else {
@ -879,12 +891,12 @@ bool File::updateStatusText() const {
statusSize = FileStatusSizeReady; statusSize = FileStatusSizeReady;
} }
if (statusSize != _statusSize) { if (statusSize != _statusSize) {
int32 duration = document->isSong() int32 duration = _document->isSong()
? document->song()->duration ? _document->song()->duration
: (document->isVoiceMessage() : (_document->isVoiceMessage()
? document->voice()->duration ? _document->voice()->duration
: -1); : -1);
setStatusSize(statusSize, document->size, duration, realDuration); setStatusSize(statusSize, _document->size, duration, realDuration);
} }
return showPause; return showPause;
} }

View File

@ -18,7 +18,7 @@ namespace internal {
class FileBase : public ItemBase { class FileBase : public ItemBase {
public: public:
FileBase(not_null<Context*> context, Result *result); FileBase(not_null<Context*> context, not_null<Result*> result);
// for saved gif layouts // for saved gif layouts
FileBase(not_null<Context*> context, DocumentData *doc); FileBase(not_null<Context*> context, DocumentData *doc);
@ -197,33 +197,33 @@ private:
class OpenFileClickHandler : public LeftButtonClickHandler { class OpenFileClickHandler : public LeftButtonClickHandler {
public: public:
OpenFileClickHandler(Result *result) : _result(result) { OpenFileClickHandler(not_null<Result*> result) : _result(result) {
} }
protected: protected:
void onClickImpl() const override; void onClickImpl() const override;
private: private:
Result *_result; not_null<Result*> _result;
}; };
class CancelFileClickHandler : public LeftButtonClickHandler { class CancelFileClickHandler : public LeftButtonClickHandler {
public: public:
CancelFileClickHandler(Result *result) : _result(result) { CancelFileClickHandler(not_null<Result*> result) : _result(result) {
} }
protected: protected:
void onClickImpl() const override; void onClickImpl() const override;
private: private:
Result *_result; not_null<Result*> _result;
}; };
class File : public FileBase { class File : public FileBase {
public: public:
File(not_null<Context*> context, Result *result); File(not_null<Context*> context, not_null<Result*> result);
void initDimensions() override; void initDimensions() override;
@ -283,6 +283,8 @@ private:
// duration = -1 - no duration, duration = -2 - "GIF" duration // duration = -1 - no duration, duration = -2 - "GIF" duration
void setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const; void setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const;
not_null<DocumentData*> _document;
}; };
class Contact : public ItemBase { class Contact : public ItemBase {

View File

@ -42,9 +42,13 @@ public:
class ItemBase : public LayoutItemBase { class ItemBase : public LayoutItemBase {
public: public:
ItemBase(not_null<Context*> context, Result *result) : _result(result), _context(context) { ItemBase(not_null<Context*> context, not_null<Result*> result)
: _result(result)
, _context(context) {
} }
ItemBase(not_null<Context*> context, DocumentData *doc) : _doc(doc), _context(context) { ItemBase(not_null<Context*> context, DocumentData *doc)
: _doc(doc)
, _context(context) {
} }
// Not used anywhere currently. // Not used anywhere currently.
//ItemBase(not_null<Context*> context, PhotoData *photo) : _photo(photo), _context(context) { //ItemBase(not_null<Context*> context, PhotoData *photo) : _photo(photo), _context(context) {