diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 994614ad65..d41e7dada9 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -662,16 +662,10 @@ void HistoryWidget::scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId // And the scrollTop will be reset back to scrollTopItem + scrollTopOffset. notify_handlePendingHistoryUpdate(); - auto fromTop = _list->itemTop(from); auto toTop = _list->itemTop(to); - if (fromTop < 0 || toTop < 0) { - return; - } - - auto scrollTop = _scroll->scrollTop(); - auto scrollBottom = scrollTop + _scroll->height(); - auto fromBottom = fromTop + from->height(); - if (fromTop < scrollBottom && fromBottom > scrollTop) { + if (toTop >= 0 && !isItemCompletelyHidden(from)) { + auto scrollTop = _scroll->scrollTop(); + auto scrollBottom = scrollTop + _scroll->height(); auto toBottom = toTop + to->height(); if ((toTop < scrollTop && toBottom < scrollBottom) || (toTop > scrollTop && toBottom > scrollBottom)) { auto scrollTo = snap(itemTopForHighlight(to), 0, _scroll->scrollTopMax()); @@ -2636,10 +2630,22 @@ void HistoryWidget::onScroll() { } } +bool HistoryWidget::isItemCompletelyHidden(HistoryItem *item) const { + auto top = _list->itemTop(item); + if (top < 0) { + return true; + } + + auto bottom = top + item->height(); + auto scrollTop = _scroll->scrollTop(); + auto scrollBottom = scrollTop + _scroll->height(); + return (top >= scrollBottom || bottom <= scrollTop); +} + void HistoryWidget::visibleAreaUpdated() { if (_list && !_scroll->isHidden()) { - int scrollTop = _scroll->scrollTop(); - int scrollBottom = scrollTop + _scroll->height(); + auto scrollTop = _scroll->scrollTop(); + auto scrollBottom = scrollTop + _scroll->height(); _list->visibleAreaUpdated(scrollTop, scrollBottom); if (_history->loadedAtBottom() && (_history->unreadCount() > 0 || (_migrated && _migrated->unreadCount() > 0))) { auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr); @@ -2647,6 +2653,7 @@ void HistoryWidget::visibleAreaUpdated() { historyWasRead(ReadServerHistoryChecks::OnlyIfUnread); } } + controller()->floatPlayerAreaUpdated().notify(true); } } diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index ccbf41243c..6d2dce044a 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -180,6 +180,7 @@ public: void dragLeaveEvent(QDragLeaveEvent *e) override; void dropEvent(QDropEvent *e) override; + bool isItemCompletelyHidden(HistoryItem *item) const; void updateTopBarSelection(); bool paintTopBar(Painter &p, int decreaseWidth, TimeMs ms); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 9b32422b7f..e3a771fbea 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -152,6 +152,9 @@ MainWidget::MainWidget(QWidget *parent, gsl::not_null contr subscribe(_controller->dialogsWidthRatio(), [this](float64) { updateControlsGeometry(); }); + subscribe(_controller->floatPlayerAreaUpdated(), [this] { + checkFloatPlayerVisibility(); + }); QCoreApplication::instance()->installEventFilter(this); @@ -234,7 +237,7 @@ void MainWidget::checkCurrentFloatPlayer() { auto state = Media::Player::instance()->current(AudioMsgId::Type::Voice); auto fullId = state.contextId(); auto last = currentFloatPlayer(); - if (!last || last->widget->itemId() != fullId) { + if (!last || last->widget->detached() || last->widget->item()->fullId() != fullId) { if (last) { last->widget->detach(); } @@ -243,9 +246,10 @@ void MainWidget::checkCurrentFloatPlayer() { if (auto document = media->getDocument()) { if (document->isRoundVideo()) { _playerFloats.push_back(std::make_unique(this, item, [this](Float *instance, bool visible) { - toggleFloatPlayer(instance, visible); + instance->hiddenByWidget = !visible; + toggleFloatPlayer(instance); })); - toggleFloatPlayer(currentFloatPlayer(), true); + checkFloatPlayerVisibility(); } } } @@ -253,8 +257,10 @@ void MainWidget::checkCurrentFloatPlayer() { } } -void MainWidget::toggleFloatPlayer(Float *instance, bool visible) { +void MainWidget::toggleFloatPlayer(Float *instance) { + auto visible = !instance->hiddenByHistory && !instance->hiddenByWidget && !instance->widget->detached(); if (instance->visible != visible) { + instance->widget->resetMouseState(); instance->visible = visible; instance->visibleAnimation.start([this, instance] { updateFloatPlayerPosition(instance); @@ -263,6 +269,20 @@ void MainWidget::toggleFloatPlayer(Float *instance, bool visible) { } } +void MainWidget::checkFloatPlayerVisibility() { + auto instance = currentFloatPlayer(); + if (!instance) { + return; + } + + if (_history->isHidden() || _history->isItemCompletelyHidden(instance->widget->item())) { + instance->hiddenByHistory = false; + } else { + instance->hiddenByHistory = true; + } + toggleFloatPlayer(instance); +} + void MainWidget::updateFloatPlayerPosition(Float *instance) { auto visible = instance->visibleAnimation.current(instance->visible ? 1. : 0.); if (visible == 0. && !instance->visible) { @@ -755,6 +775,7 @@ void MainWidget::noHider(HistoryHider *destroyed) { } else { _history->showAnimated(Window::SlideDirection::FromRight, animationParams); } + checkFloatPlayerVisibility(); } } else { if (_forwardConfirm) { @@ -796,6 +817,7 @@ void MainWidget::hiderLayer(object_ptr h) { updateControlsGeometry(); _dialogs->activate(); } + checkFloatPlayerVisibility(); } void MainWidget::forwardLayer(int forwardSelected) { @@ -2498,6 +2520,8 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show } _dialogs->update(); } + + checkFloatPlayerVisibility(); } PeerData *MainWidget::ui_getPeerForMouseAction() { @@ -2625,6 +2649,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool _history->hide(); if (Adaptive::OneColumn()) _dialogs->hide(); + checkFloatPlayerVisibility(); orderWidgets(); } @@ -2784,6 +2809,7 @@ void MainWidget::showNewWideSection(const Window::SectionMemento *memento, bool _wideSection->showFast(); } + checkFloatPlayerVisibility(); orderWidgets(); } @@ -3128,6 +3154,9 @@ void MainWidget::hideAll() { _player->hide(); _playerHeight = 0; } + for (auto &instance : _playerFloats) { + instance->widget->hide(); + } } void MainWidget::showAll() { @@ -3199,6 +3228,12 @@ void MainWidget::showAll() { _playerHeight = _player->contentHeight(); } updateControlsGeometry(); + if (auto instance = currentFloatPlayer()) { + checkFloatPlayerVisibility(); + if (instance->visible) { + instance->widget->show(); + } + } App::wnd()->checkHistoryActivation(); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 2a5f12bf5c..4ae470d65a 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -466,6 +466,8 @@ private: template Float(QWidget *parent, HistoryItem *item, ToggleCallback callback); + bool hiddenByWidget = false; + bool hiddenByHistory = false; bool visible = false; Animation visibleAnimation; Window::Corner corner = Window::Corner::TopRight; @@ -574,7 +576,8 @@ private: void clearCachedBackground(); void checkCurrentFloatPlayer(); - void toggleFloatPlayer(Float *instance, bool visible); + void toggleFloatPlayer(Float *instance); + void checkFloatPlayerVisibility(); void updateFloatPlayerPosition(Float *instance); void removeFloatPlayer(Float *instance); Float *currentFloatPlayer() const { diff --git a/Telegram/SourceFiles/media/media_audio.cpp b/Telegram/SourceFiles/media/media_audio.cpp index 485a4bb6eb..5e5d6bc65f 100644 --- a/Telegram/SourceFiles/media/media_audio.cpp +++ b/Telegram/SourceFiles/media/media_audio.cpp @@ -887,7 +887,6 @@ void Mixer::seek(AudioMsgId::Type type, int64 position) { resetFadeStartPosition(type, position - current->bufferedPosition); } else { setStoppedState(current); - if (streamCreated) alSourceStop(current->stream.source); } switch (current->state.state) { case State::Pausing: @@ -1009,6 +1008,10 @@ TrackState Mixer::currentState(AudioMsgId::Type type) { void Mixer::setStoppedState(Track *current, State state) { current->state.state = state; current->state.position = 0; + if (current->isStreamCreated()) { + alSourceStop(current->stream.source); + alSourcef(current->stream.source, AL_GAIN, 1); + } } void Mixer::clearStoppedAtStart(const AudioMsgId &audio) { @@ -1209,18 +1212,14 @@ int32 Fader::updateOnePlayback(Mixer::Track *track, bool &hasPlaying, bool &hasF if (fading || playing) { fading = false; playing = false; - if (track->isStreamCreated()) { - alSourceStop(track->stream.source); - alSourcef(track->stream.source, AL_GAIN, 1); - if (errorHappened()) return EmitError; - } if (track->state.state == State::Pausing) { - track->state.state = State::PausedAtEnd; + setStoppedState(track, State::PausedAtEnd); } else if (track->state.state == State::Stopping) { setStoppedState(track, State::Stopped); } else { setStoppedState(track, State::StoppedAtEnd); } + if (errorHappened()) return EmitError; emitSignals |= EmitStopped; } } else if (fading && state == AL_PLAYING) { @@ -1232,9 +1231,6 @@ int32 Fader::updateOnePlayback(Mixer::Track *track, bool &hasPlaying, bool &hasF switch (track->state.state) { case State::Stopping: { - alSourceStop(track->stream.source); - if (errorHappened()) return EmitError; - setStoppedState(track); state = AL_STOPPED; } break; @@ -1284,8 +1280,7 @@ int32 Fader::updateOnePlayback(Mixer::Track *track, bool &hasPlaying, bool &hasF } void Fader::setStoppedState(Mixer::Track *track, State state) { - track->state.state = state; - track->state.position = 0; + mixer()->setStoppedState(track, state); } void Fader::onSuppressSong() { diff --git a/Telegram/SourceFiles/media/media_audio.h b/Telegram/SourceFiles/media/media_audio.h index 05c1906364..34778981bc 100644 --- a/Telegram/SourceFiles/media/media_audio.h +++ b/Telegram/SourceFiles/media/media_audio.h @@ -231,6 +231,7 @@ private: }; + // Thread: Any. Must be locked: AudioMutex. void setStoppedState(Track *current, State state = State::Stopped); Track *trackForType(AudioMsgId::Type type, int index = -1); // -1 uses currentIndex(type) diff --git a/Telegram/SourceFiles/media/media_audio_loaders.cpp b/Telegram/SourceFiles/media/media_audio_loaders.cpp index 05e356096b..ccd6e72585 100644 --- a/Telegram/SourceFiles/media/media_audio_loaders.cpp +++ b/Telegram/SourceFiles/media/media_audio_loaders.cpp @@ -125,8 +125,7 @@ AudioMsgId Loaders::clear(AudioMsgId::Type type) { } void Loaders::setStoppedState(Mixer::Track *track, State state) { - track->state.state = state; - track->state.position = 0; + mixer()->setStoppedState(track, state); } void Loaders::emitError(AudioMsgId::Type type) { diff --git a/Telegram/SourceFiles/media/player/media_player_float.h b/Telegram/SourceFiles/media/player/media_player_float.h index b67d39234a..c03c7f1cfa 100644 --- a/Telegram/SourceFiles/media/player/media_player_float.h +++ b/Telegram/SourceFiles/media/player/media_player_float.h @@ -31,8 +31,8 @@ class Float : public TWidget, private base::Subscriber { public: Float(QWidget *parent, HistoryItem *item, base::lambda toggleCallback); - FullMsgId itemId() const { - return _item ? _item->fullId() : FullMsgId(); + HistoryItem *item() const { + return _item; } void setOpacity(float64 opacity) { _opacity = opacity; diff --git a/Telegram/SourceFiles/window/window_controller.h b/Telegram/SourceFiles/window/window_controller.h index 69cbf78c8c..4fb289e44d 100644 --- a/Telegram/SourceFiles/window/window_controller.h +++ b/Telegram/SourceFiles/window/window_controller.h @@ -65,6 +65,9 @@ public: return _gifPauseLevelChanged; } bool isGifPausedAtLeastFor(GifPauseReason reason) const; + base::Observable &floatPlayerAreaUpdated() { + return _floatPlayerAreaUpdated; + } struct ColumnLayout { int bodyWidth; @@ -104,6 +107,7 @@ private: GifPauseReasons _gifPauseReasons = { 0 }; base::Observable _gifPauseLevelChanged; + base::Observable _floatPlayerAreaUpdated; base::Variable _dialogsWidthRatio = { kDefaultDialogsWidthRatio }; base::Variable _dialogsListFocused = { false };