From 8a9317f9e11d3dca6a019bcf477bcc1a5927de1f Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 9 Nov 2020 15:05:36 +0300 Subject: [PATCH] Download video avatars as .mp4 in media viewer. Fixes #9017. --- .../media/view/media_view_overlay_widget.cpp | 80 +++++++++++++++++-- .../media/view/media_view_overlay_widget.h | 9 +++ .../SourceFiles/storage/file_download.cpp | 3 +- 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 47c119cd4b..245388078e 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -627,6 +627,34 @@ void OverlayWidget::refreshNavVisibility() { } } +bool OverlayWidget::contentCanBeSaved() const { + if (_photo) { + return _photo->hasVideo() || _photoMedia->loaded(); + } else if (_document) { + return _document->filepath(true).isEmpty() && !_document->loading(); + } else { + return false; + } +} + +void OverlayWidget::checkForSaveLoaded() { + if (_savePhotoVideoWhenLoaded == SavePhotoVideo::None) { + return; + } else if (!_photo + || !_photo->hasVideo() + || _photoMedia->videoContent().isEmpty()) { + return; + } else if (_savePhotoVideoWhenLoaded == SavePhotoVideo::QuickSave) { + _savePhotoVideoWhenLoaded = SavePhotoVideo::None; + onDownload(); + } else if (_savePhotoVideoWhenLoaded == SavePhotoVideo::SaveAs) { + _savePhotoVideoWhenLoaded = SavePhotoVideo::None; + onSaveAs(); + } else { + Unexpected("SavePhotoVideo in OverlayWidget::checkForSaveLoaded."); + } +} + void OverlayWidget::updateControls() { if (_document && documentBubbleShown()) { if (_document->loading()) { @@ -658,10 +686,7 @@ void OverlayWidget::updateControls() { updateThemePreviewGeometry(); - _saveVisible = (_photo && _photoMedia->loaded()) - || (_document - && _document->filepath(true).isEmpty() - && !_document->loading()); + _saveVisible = contentCanBeSaved(); _rotateVisible = !_themePreviewShown; const auto navRect = [&](int i) { return myrtlrect(width() - st::mediaviewIconSize.width() * i, @@ -1153,6 +1178,7 @@ OverlayWidget::~OverlayWidget() { } void OverlayWidget::assignMediaPointer(DocumentData *document) { + _savePhotoVideoWhenLoaded = SavePhotoVideo::None; _photo = nullptr; _photoMedia = nullptr; if (_document != document) { @@ -1167,6 +1193,7 @@ void OverlayWidget::assignMediaPointer(DocumentData *document) { } void OverlayWidget::assignMediaPointer(not_null photo) { + _savePhotoVideoWhenLoaded = SavePhotoVideo::None; _document = nullptr; _documentMedia = nullptr; if (_photo != photo) { @@ -1348,6 +1375,31 @@ void OverlayWidget::onSaveAs() { updateControls(); updateOver(_lastMouseMovePos); } + } else if (_photo && _photo->hasVideo()) { + if (const auto bytes = _photoMedia->videoContent(); !bytes.isEmpty()) { + auto filter = qsl("Video Files (*.mp4);;") + FileDialog::AllFilesFilter(); + FileDialog::GetWritePath( + this, + tr::lng_save_video(tr::now), + filter, + filedialogDefaultName( + qsl("photo"), + qsl(".mp4"), + QString(), + false, + _photo->date), + crl::guard(this, [=, photo = _photo](const QString &result) { + QFile f(result); + if (!result.isEmpty() + && _photo == photo + && f.open(QIODevice::WriteOnly)) { + f.write(bytes); + } + })); + } else { + _photo->loadVideo(fileOrigin()); + _savePhotoVideoWhenLoaded = SavePhotoVideo::SaveAs; + } } else { if (!_photo || !_photoMedia->loaded()) { return; @@ -1436,14 +1488,29 @@ void OverlayWidget::onDownload() { DocumentSaveClickHandler::Mode::ToFile); updateControls(); } else { - _saveVisible = false; + _saveVisible = contentCanBeSaved(); update(_saveNav); } updateOver(_lastMouseMovePos); } + } else if (_photo && _photo->hasVideo()) { + if (const auto bytes = _photoMedia->videoContent(); !bytes.isEmpty()) { + if (!QDir().exists(path)) { + QDir().mkpath(path); + } + toName = filedialogDefaultName(qsl("photo"), qsl(".mp4"), path); + QFile f(toName); + if (!f.open(QIODevice::WriteOnly) + || f.write(bytes) != bytes.size()) { + toName = QString(); + } + } else { + _photo->loadVideo(fileOrigin()); + _savePhotoVideoWhenLoaded = SavePhotoVideo::QuickSave; + } } else { if (!_photo || !_photoMedia->loaded()) { - _saveVisible = false; + _saveVisible = contentCanBeSaved(); update(_saveNav); } else { const auto image = _photoMedia->image( @@ -3685,6 +3752,7 @@ void OverlayWidget::setSession(not_null session) { ) | rpl::start_with_next([=] { if (!isHidden()) { updateControls(); + checkForSaveLoaded(); } }, _sessionLifetime); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 69902cfecf..5987609285 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -159,6 +159,11 @@ private: not_null> data; HistoryItem *item; }; + enum class SavePhotoVideo { + None, + QuickSave, + SaveAs, + }; void paintEvent(QPaintEvent *e) override; @@ -207,6 +212,9 @@ private: bool moveToNext(int delta); void preloadData(int delta); + bool contentCanBeSaved() const; + void checkForSaveLoaded(); + Entity entityForUserPhotos(int index) const; Entity entityForSharedMedia(int index) const; Entity entityForCollage(int index) const; @@ -502,6 +510,7 @@ private: QRect _saveMsg; QTimer _saveMsgUpdater; Ui::Text::String _saveMsgText; + SavePhotoVideo _savePhotoVideoWhenLoaded = SavePhotoVideo::None; base::flat_map _animations; base::flat_map _animationOpacities; diff --git a/Telegram/SourceFiles/storage/file_download.cpp b/Telegram/SourceFiles/storage/file_download.cpp index 629f2922bf..2a2e9cb59a 100644 --- a/Telegram/SourceFiles/storage/file_download.cpp +++ b/Telegram/SourceFiles/storage/file_download.cpp @@ -471,8 +471,9 @@ bool FileLoader::finalizeResult() { _cacheTag)); } } - _session->notifyDownloaderTaskFinished(); + const auto session = _session; _updates.fire_done(); + session->notifyDownloaderTaskFinished(); return true; }