From 5cae57601a1aabf7ccd4561820130763cf992057 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 14 Mar 2019 16:03:02 +0400 Subject: [PATCH] Allow video download from media viewer. --- .../media/view/media_view_overlay_widget.cpp | 259 +++++++++--------- .../media/view/media_view_overlay_widget.h | 5 +- 2 files changed, 141 insertions(+), 123 deletions(-) diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 46442bf5d2..bf690b8724 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -282,24 +282,27 @@ void OverlayWidget::refreshLang() { InvokeQueued(this, [this] { updateThemePreviewGeometry(); }); } -void OverlayWidget::moveToScreen() { - auto widgetScreen = [&](auto &&widget) -> QScreen* { +void OverlayWidget::moveToScreen(bool force) { + const auto widgetScreen = [&](auto &&widget) -> QScreen* { if (auto handle = widget ? widget->windowHandle() : nullptr) { return handle->screen(); } return nullptr; }; - auto activeWindow = Core::App().getActiveWindow(); - auto activeWindowScreen = widgetScreen(activeWindow); - auto myScreen = widgetScreen(this); + const auto activeWindow = Core::App().getActiveWindow(); + const auto activeWindowScreen = widgetScreen(activeWindow); + const auto myScreen = widgetScreen(this); if (activeWindowScreen && myScreen && myScreen != activeWindowScreen) { windowHandle()->setScreen(activeWindowScreen); } - const auto screen = activeWindowScreen ? activeWindowScreen : QApplication::primaryScreen(); + const auto screen = activeWindowScreen + ? activeWindowScreen + : QApplication::primaryScreen(); const auto available = screen->geometry(); - if (geometry() != available) { - setGeometry(available); + if (!force && geometry() == available) { + return; } + setGeometry(available); auto navSkip = 2 * st::mediaviewControlMargin + st::mediaviewControlSize; _closeNav = myrtlrect(width() - st::mediaviewControlMargin - st::mediaviewControlSize, st::mediaviewControlMargin, st::mediaviewControlSize, st::mediaviewControlSize); @@ -310,6 +313,10 @@ void OverlayWidget::moveToScreen() { _rightNavIcon = centerrect(_rightNav, st::mediaviewRight); _saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2); + _photoRadialRect = QRect(QPoint((width() - st::radialSize.width()) / 2, (height() - st::radialSize.height()) / 2), st::radialSize); + + resizeContentByScreenSize(); + update(); } bool OverlayWidget::videoShown() const { @@ -490,8 +497,7 @@ void OverlayWidget::updateControls() { updateThemePreviewGeometry(); _saveVisible = (_photo && _photo->loaded()) - || (_doc && (_doc->loaded(DocumentData::FilePathResolve::Checked) - || !documentContentShown())); + || (_doc && _doc->filepath(DocumentData::FilePathResolve::Checked).isEmpty()); _saveNav = myrtlrect(width() - st::mediaviewIconSize.width() * 2, height() - st::mediaviewIconSize.height(), st::mediaviewIconSize.width(), st::mediaviewIconSize.height()); _saveNavIcon = centerrect(_saveNav, st::mediaviewSave); _moreNav = myrtlrect(width() - st::mediaviewIconSize.width(), height() - st::mediaviewIconSize.height(), st::mediaviewIconSize.width(), st::mediaviewIconSize.height()); @@ -720,6 +726,10 @@ QRect OverlayWidget::contentRect() const { void OverlayWidget::contentSizeChanged() { _width = _w; _height = _h; + resizeContentByScreenSize(); +} + +void OverlayWidget::resizeContentByScreenSize() { if (_w > 0 && _h > 0) { _zoomToScreen = float64(width()) / _w; if (_h * _zoomToScreen > height()) { @@ -742,9 +752,10 @@ void OverlayWidget::contentSizeChanged() { _w = qRound(_w / (-_zoomToScreen + 1)); _h = qRound(_h / (-_zoomToScreen + 1)); } - snapXY(); } else { _zoom = 0; + _w = _width; + _h = _height; } _x = (width() - _w) / 2; _y = (height() - _h) / 2; @@ -808,19 +819,18 @@ void OverlayWidget::step_radial(crl::time ms, bool timer) { update(radialRect()); } const auto ready = _doc && _doc->loaded(); - const auto streamVideo = ready && (_doc->isAnimation() || _doc->isVideoFile()); + const auto streamVideo = ready && _doc->canBePlayed(); const auto tryOpenImage = ready && (_doc->size < App::kImageSizeLimit); if (ready && ((tryOpenImage && !_radial.animating()) || streamVideo)) { - _streamingStartPaused = false; - if (!_doc->data().isEmpty() && streamVideo) { - displayDocument(_doc, App::histItemById(_msgid)); + _streamingStartPaused = true; + if (streamVideo) { + redisplayContent(); } else { auto &location = _doc->location(true); if (location.accessEnable()) { - if (streamVideo - || _doc->isTheme() + if (_doc->isTheme() || QImageReader(location.name()).canRead()) { - displayDocument(_doc, App::histItemById(_msgid)); + redisplayContent(); } location.accessDisable(); } @@ -996,25 +1006,19 @@ void OverlayWidget::dropdownHidden() { } void OverlayWidget::onScreenResized(int screen) { - if (isHidden()) return; - - bool ignore = false; - auto screens = QApplication::screens(); - if (screen >= 0 && screen < screens.size()) { - if (auto screenHandle = windowHandle()->screen()) { - if (screens.at(screen) != screenHandle) { - ignore = true; - } - } + if (isHidden()) { + return; } - if (!ignore) { + + const auto screens = QApplication::screens(); + const auto changed = (screen >= 0 && screen < screens.size()) + ? screens[screen] + : nullptr; + if (!windowHandle() + || !windowHandle()->screen() + || !changed + || windowHandle()->screen() == changed) { moveToScreen(); - const auto item = App::histItemById(_msgid); - if (_photo) { - displayPhoto(_photo, item); - } else if (_doc) { - displayDocument(_doc, item); - } } } @@ -1062,16 +1066,11 @@ void OverlayWidget::onSaveAs() { if (_doc->data().isEmpty()) location.accessDisable(); } else { - if (!documentContentShown()) { - DocumentSaveClickHandler::Save( - fileOrigin(), - _doc, - DocumentSaveClickHandler::Mode::ToNewFile); - updateControls(); - } else { - _saveVisible = false; - update(_saveNav); - } + DocumentSaveClickHandler::Save( + fileOrigin(), + _doc, + DocumentSaveClickHandler::Mode::ToNewFile); + updateControls(); updateOver(_lastMouseMovePos); } } else { @@ -1136,7 +1135,7 @@ void OverlayWidget::onDownload() { } QString toName; if (_doc) { - const FileLocation &location(_doc->location(true)); + const auto &location = _doc->location(true); if (location.accessEnable()) { if (!QDir().exists(path)) QDir().mkpath(path); toName = filedialogNextFilename( @@ -1151,7 +1150,7 @@ void OverlayWidget::onDownload() { } location.accessDisable(); } else { - if (!documentContentShown()) { + if (_doc->filepath(DocumentData::FilePathResolve::Checked).isEmpty()) { DocumentSaveClickHandler::Save( fileOrigin(), _doc, @@ -1186,6 +1185,9 @@ void OverlayWidget::onDownload() { void OverlayWidget::onSaveCancel() { if (_doc && _doc->loading()) { _doc->cancel(); + if (_doc->canBePlayed()) { + redisplayContent(); + } } } @@ -1450,7 +1452,7 @@ std::optional OverlayWidget::collageKey() const { if (const auto item = App::histItemById(_msgid)) { if (const auto media = item->media()) { if (const auto page = media->webpage()) { - for (const auto item : page->collage.items) { + for (const auto &item : page->collage.items) { if (item == _photo || item == _doc) { return item; } @@ -1695,6 +1697,10 @@ void OverlayWidget::displayPhoto(not_null photo, HistoryItem *item) displayDocument(nullptr, item); return; } + if (isHidden()) { + moveToScreen(); + } + clearStreaming(); destroyThemePreview(); _doc = nullptr; @@ -1703,13 +1709,9 @@ void OverlayWidget::displayPhoto(not_null photo, HistoryItem *item) _radial.stop(); refreshMediaViewer(); - - _photoRadialRect = QRect(QPoint((width() - st::radialSize.width()) / 2, (height() - st::radialSize.height()) / 2), st::radialSize); - - _zoom = 0; - refreshCaption(item); + _zoom = 0; _zoomToScreen = 0; Auth().downloader().clearPriorities(); _blurred = true; @@ -1717,9 +1719,6 @@ void OverlayWidget::displayPhoto(not_null photo, HistoryItem *item) _down = OverNone; _w = ConvertScale(photo->width()); _h = ConvertScale(photo->height()); - if (isHidden()) { - moveToScreen(); - } contentSizeChanged(); if (_msgid && item) { _from = item->senderOriginal(); @@ -1738,30 +1737,33 @@ void OverlayWidget::destroyThemePreview() { _themeCancel.destroy(); } +void OverlayWidget::redisplayContent() { + if (isHidden()) { + return; + } + const auto item = App::histItemById(_msgid); + if (_photo) { + displayPhoto(_photo, item); + } else { + displayDocument(_doc, item); + } +} + // Empty messages shown as docs: doc can be nullptr. void OverlayWidget::displayDocument(DocumentData *doc, HistoryItem *item) { - const auto documentChanged = !doc - || (doc != _doc) - || (item && item->fullId() != _msgid); - if (documentChanged - || (!doc->isAnimation() && !doc->isVideoFile()) - || !doc->canBePlayed()) { - _fullScreenVideo = false; - _current = QPixmap(); - clearStreaming(); - } else if (videoShown()) { - _current = QPixmap(); - } - if (documentChanged || !doc->isTheme()) { - destroyThemePreview(); + if (isHidden()) { + moveToScreen(); } + _fullScreenVideo = false; + _current = QPixmap(); + clearStreaming(); + destroyThemePreview(); _doc = doc; _photo = nullptr; _radial.stop(); refreshMediaViewer(); - - if (documentChanged) { + if ((item ? item->fullId() : FullMsgId()) != _msgid) { refreshCaption(item); } if (_doc) { @@ -1778,7 +1780,11 @@ void OverlayWidget::displayDocument(DocumentData *doc, HistoryItem *item) { _doc->automaticLoad(fileOrigin(), item); if (_doc->canBePlayed()) { - initStreaming(); + if (_doc->loading()) { + initStreamingThumbnail(); + } else { + initStreaming(); + } } else if (_doc->isTheme()) { initThemePreview(); } else { @@ -1857,9 +1863,6 @@ void OverlayWidget::displayDocument(DocumentData *doc, HistoryItem *item) { _w = contentSize.width(); _h = contentSize.height(); } - if (isHidden()) { - moveToScreen(); - } contentSizeChanged(); if (_msgid && item) { _from = item->senderOriginal(); @@ -2085,8 +2088,7 @@ void OverlayWidget::handleStreamingError(Streaming::Error &&error) { _doc->setInappPlaybackFailed(); } if (!_doc->canBePlayed()) { - clearStreaming(); - displayDocument(_doc, App::histItemById(_msgid)); + redisplayContent(); } else { _streamed->lastError = std::move(error); playbackWaitingChange(false); @@ -2134,51 +2136,52 @@ void OverlayWidget::initThemePreview() { Assert(_doc && _doc->isTheme()); auto &location = _doc->location(); - if (!location.isEmpty() && location.accessEnable()) { - _themePreviewShown = true; - - Window::Theme::CurrentData current; - current.backgroundId = Window::Theme::Background()->id(); - current.backgroundImage = Window::Theme::Background()->createCurrentImage(); - current.backgroundTiled = Window::Theme::Background()->tile(); - - const auto path = _doc->location().name(); - const auto id = _themePreviewId = rand_value(); - const auto weak = make_weak(this); - crl::async([=, data = std::move(current)]() mutable { - auto preview = Window::Theme::GeneratePreview( - path, - std::move(data)); - crl::on_main(weak, [=, result = std::move(preview)]() mutable { - if (id != _themePreviewId) { - return; - } - _themePreviewId = 0; - _themePreview = std::move(result); - if (_themePreview) { - _themeApply.create( - this, - langFactory(lng_theme_preview_apply), - st::themePreviewApplyButton); - _themeApply->show(); - _themeApply->setClickedCallback([this] { - auto preview = std::move(_themePreview); - close(); - Window::Theme::Apply(std::move(preview)); - }); - _themeCancel.create( - this, - langFactory(lng_cancel), - st::themePreviewCancelButton); - _themeCancel->show(); - _themeCancel->setClickedCallback([this] { close(); }); - updateControls(); - } - update(); - }); - }); - location.accessDisable(); + if (location.isEmpty() || !location.accessEnable()) { + return; } + _themePreviewShown = true; + + Window::Theme::CurrentData current; + current.backgroundId = Window::Theme::Background()->id(); + current.backgroundImage = Window::Theme::Background()->createCurrentImage(); + current.backgroundTiled = Window::Theme::Background()->tile(); + + const auto path = _doc->location().name(); + const auto id = _themePreviewId = rand_value(); + const auto weak = make_weak(this); + crl::async([=, data = std::move(current)]() mutable { + auto preview = Window::Theme::GeneratePreview( + path, + std::move(data)); + crl::on_main(weak, [=, result = std::move(preview)]() mutable { + if (id != _themePreviewId) { + return; + } + _themePreviewId = 0; + _themePreview = std::move(result); + if (_themePreview) { + _themeApply.create( + this, + langFactory(lng_theme_preview_apply), + st::themePreviewApplyButton); + _themeApply->show(); + _themeApply->setClickedCallback([this] { + auto preview = std::move(_themePreview); + close(); + Window::Theme::Apply(std::move(preview)); + }); + _themeCancel.create( + this, + langFactory(lng_cancel), + st::themePreviewCancelButton); + _themeCancel->show(); + _themeCancel->setClickedCallback([this] { close(); }); + updateControls(); + } + update(); + }); + }); + location.accessDisable(); } void OverlayWidget::refreshClipControllerGeometry() { @@ -2393,7 +2396,19 @@ void OverlayWidget::validatePhotoCurrentImage() { } } +void OverlayWidget::checkLoadingWhileStreaming() { + if (_streamed && _doc->loading()) { + crl::on_main(this, [=, doc = _doc] { + if (!isHidden() && _doc == doc) { + redisplayContent(); + } + }); + } +} + void OverlayWidget::paintEvent(QPaintEvent *e) { + checkLoadingWhileStreaming(); + const auto r = e->rect(); const auto ®ion = e->region(); const auto rects = region.rects(); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index bda534a81e..6e9e3ce1e5 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -174,7 +174,7 @@ private: void playbackWaitingChange(bool waiting); void updateOver(QPoint mpos); - void moveToScreen(); + void moveToScreen(bool force = false); bool moveToNext(int delta); void preloadData(int delta); @@ -227,10 +227,13 @@ private: void updateControls(); void updateActions(); void resizeCenteredControls(); + void resizeContentByScreenSize(); + void checkLoadingWhileStreaming(); void displayPhoto(not_null photo, HistoryItem *item); void displayDocument(DocumentData *document, HistoryItem *item); void displayFinished(); + void redisplayContent(); void findCurrent(); void updateCursor();