Playlist appearance added to the new media player.

Also itemRemoved() now is fired as a global observable.
This commit is contained in:
John Preston 2016-10-14 20:10:15 +03:00
parent 4f0cff5467
commit 31a847fb9d
38 changed files with 677 additions and 271 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

View file

@ -2018,8 +2018,8 @@ namespace {
if (auto manager = Window::Notifications::manager()) {
manager->clearFromItem(item);
}
if (App::main() && !App::quitting()) {
App::main()->itemRemoved(item);
if (Global::started() && !App::quitting()) {
Global::RefItemRemoved().notify(item, true);
}
}

View file

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#include "core/vector_of_moveable.h"
#include "core/type_traits.h"
namespace base {
namespace internal {
@ -30,9 +31,12 @@ void RegisterPendingObservable(ObservableCallHandlers *handlers);
void UnregisterActiveObservable(ObservableCallHandlers *handlers);
void UnregisterObservable(ObservableCallHandlers *handlers);
template <typename EventType>
using EventParamType = typename base::type_traits<EventType>::parameter_type;
template <typename EventType>
struct SubscriptionHandlerHelper {
using type = base::lambda_unique<void(const EventType &)>;
using type = base::lambda_unique<void(EventParamType<EventType>)>;
};
template <>
@ -67,6 +71,9 @@ public:
qSwap(_removeMethod, other._removeMethod);
return *this;
}
explicit operator bool() const {
return (_node != nullptr);
}
void destroy() {
if (_node) {
(*_removeMethod)(_node);
@ -128,14 +135,26 @@ private:
template <typename EventType, typename Handler = internal::SubscriptionHandler<EventType>>
class Observable : public internal::CommonObservable<EventType, Handler> {
using SimpleEventType = typename base::type_traits<EventType>::is_fast_copy_type;
public:
template <typename = std_::enable_if_t<!SimpleEventType::value>>
void notify(EventType &&event, bool sync = false) {
if (this->_data) {
this->_data->notify(std_::move(event), sync);
}
}
template <typename = std_::enable_if_t<!SimpleEventType::value>>
void notify(const EventType &event, bool sync = false) {
notify(EventType(event));
if (this->_data) {
this->_data->notify(EventType(event), sync);
}
}
template <typename = std_::enable_if_t<SimpleEventType::value>>
void notify(EventType event, bool sync = false) {
if (this->_data) {
this->_data->notify(std_::move(event), sync);
}
}
};
@ -338,7 +357,7 @@ protected:
template <typename EventType, typename Handler, typename Lambda>
int subscribe(base::Observable<EventType, Handler> &observable, Lambda &&handler) {
_subscriptions.push_back(observable.add_subscription(std_::forward<Lambda>(handler)));
return _subscriptions.size() - 1;
return _subscriptions.size();
}
template <typename EventType, typename Handler, typename Lambda>
@ -347,8 +366,14 @@ protected:
}
void unsubscribe(int index) {
t_assert(index >= 0 && index < _subscriptions.size());
_subscriptions[index].destroy();
if (!index) return;
t_assert(index > 0 && index <= _subscriptions.size());
_subscriptions[index - 1].destroy();
if (index == _subscriptions.size()) {
while (index > 0 && !_subscriptions[--index]) {
_subscriptions.pop_back();
}
}
}
~Subscriber() {

View file

@ -139,6 +139,19 @@ struct enable_if<true, T> {
template <bool Test, typename T = void>
using enable_if_t = typename enable_if<Test, T>::type;
template <bool, typename First, typename Second>
struct conditional {
using type = Second;
};
template <typename First, typename Second>
struct conditional<true, First, Second> {
using type = First;
};
template <bool Test, typename First, typename Second>
using conditional_t = typename conditional<Test, First, Second>::type;
template <typename T>
struct add_const {
using type = const T;

View file

@ -0,0 +1,102 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "core/stl_subset.h"
namespace base {
template <typename T>
struct custom_is_fast_copy_type : public std_::false_type {
};
// To make your own type a fast copy type just write:
// template <>
// struct base::custom_is_fast_copy_type<MyTinyType> : public std_::true_type {
// };
namespace internal {
template <typename ...Types>
struct type_list_contains;
template <typename T>
struct type_list_contains<T> : public std_::false_type {
};
template <typename T, typename Head, typename ...Types>
struct type_list_contains<T, Head, Types...> : public std_::integral_constant<bool, std_::is_same<Head, T>::value || type_list_contains<T, Types...>::value> {
};
template <typename T>
using is_std_unsigned_int = type_list_contains<T, unsigned char, unsigned short int, unsigned int, unsigned long int>;
template <typename T>
using is_std_signed_int = type_list_contains<T, signed char, short int, int, long int>;
template <typename T>
using is_std_integral = std_::integral_constant<bool, is_std_unsigned_int<T>::value || is_std_signed_int<T>::value || type_list_contains<T, bool, char, wchar_t>::value>;
template <typename T>
using is_std_float = type_list_contains<T, float, double, long double>;
template <typename T>
using is_std_arith = std_::integral_constant<bool, is_std_integral<T>::value || is_std_float<T>::value>;
template <typename T>
using is_std_fundamental = std_::integral_constant<bool, is_std_arith<T>::value || std_::is_same<T, void>::value>;
template <typename T>
struct is_pointer : public std_::false_type {
};
template <typename T>
struct is_pointer<T*> : public std_::true_type {
};
template <typename T>
struct is_member_pointer : public std_::false_type {
};
template <typename T, typename C>
struct is_member_pointer<T C::*> : public std_::true_type {
};
template <typename T>
using is_fast_copy_type = std_::integral_constant<bool, is_std_arith<T>::value || is_pointer<T>::value || is_member_pointer<T>::value || custom_is_fast_copy_type<T>::value>;
} // namespace internal
template <typename T>
struct type_traits {
using is_std_unsigned_int = internal::is_std_unsigned_int<T>;
using is_std_signed_int = internal::is_std_signed_int<T>;
using is_std_integral = internal::is_std_integral<T>;
using is_std_float = internal::is_std_float<T>;
using is_std_arith = internal::is_std_arith<T>;
using is_std_fundamental = internal::is_std_fundamental<T>;
using is_pointer = internal::is_pointer<T>;
using is_member_pointer = internal::is_member_pointer<T>;
using is_fast_copy_type = internal::is_fast_copy_type<T>;
using parameter_type = std_::conditional_t<is_fast_copy_type::value, T, const T&>;
};
} // namespace base

View file

@ -55,6 +55,9 @@ DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(p
_cancelSearchInPeer.hide();
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) {
itemRemoved(item);
});
refresh();
}
@ -1900,10 +1903,6 @@ void DialogsWidget::onCancel() {
}
}
void DialogsWidget::itemRemoved(HistoryItem *item) {
_inner.itemRemoved(item);
}
void DialogsWidget::updateNotifySettings(PeerData *peer) {
_inner.updateNotifySettings(peer);
}

View file

@ -48,7 +48,6 @@ class DialogsInner : public SplittedWidget, public RPCSender, private base::Subs
Q_OBJECT
public:
DialogsInner(QWidget *parent, MainWidget *main);
void dialogsReceived(const QVector<MTPDialog> &dialogs);
@ -119,7 +118,6 @@ public:
void onFilterUpdate(QString newFilter, bool force = false);
void onHashtagFilterUpdate(QStringRef newFilter);
void itemRemoved(HistoryItem *item);
PeerData *updateFromParentDrag(QPoint globalPos);
@ -131,7 +129,6 @@ public:
~DialogsInner();
public slots:
void onUpdateSelected(bool force = false);
void onParentGeometryChanged();
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
@ -152,7 +149,6 @@ public slots:
void peerUpdated(PeerData *peer);
signals:
void mustScrollTo(int scrollToTop, int scrollToBottom);
void dialogMoved(int movedFrom, int movedTo);
void searchMessages();
@ -162,10 +158,10 @@ signals:
void refreshHashtags();
protected:
void paintRegion(Painter &p, const QRegion &region, bool paintingOther);
private:
void itemRemoved(HistoryItem *item);
int dialogsOffset() const;
int filteredOffset() const;
@ -288,8 +284,6 @@ public:
void searchMessages(const QString &query, PeerData *inPeer = 0);
void onSearchMore();
void itemRemoved(HistoryItem *item);
void updateNotifySettings(PeerData *peer);
void rpcClear() override {

View file

@ -661,6 +661,8 @@ struct Data {
bool LocalPasscode = false;
base::Observable<void> LocalPasscodeChanged;
base::Observable<HistoryItem*> ItemRemoved;
};
} // namespace internal
@ -774,4 +776,6 @@ DefineVar(Global, int, AutoLock);
DefineVar(Global, bool, LocalPasscode);
DefineRefVar(Global, base::Observable<void>, LocalPasscodeChanged);
DefineRefVar(Global, base::Observable<HistoryItem*>, ItemRemoved);
} // namespace Global

View file

@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "core/type_traits.h"
class LayerWidget;
namespace base {
template <typename Type, typename>
@ -170,6 +172,10 @@ inline bool IsTopCorner(ScreenCorner corner) {
} // namespace Notify
template <>
struct base::custom_is_fast_copy_type<Notify::ChangeType> : public std_::true_type {
};
#define DeclareReadOnlyVar(Type, Name) const Type &Name();
#define DeclareRefVar(Type, Name) DeclareReadOnlyVar(Type, Name) \
Type &Ref##Name();
@ -346,6 +352,8 @@ DeclareVar(int, AutoLock);
DeclareVar(bool, LocalPasscode);
DeclareRefVar(base::Observable<void>, LocalPasscodeChanged);
DeclareRefVar(base::Observable<HistoryItem*>, ItemRemoved);
} // namespace Global
namespace Adaptive {

View file

@ -132,6 +132,9 @@ HistoryInner::HistoryInner(HistoryWidget *historyWidget, ScrollArea *scroll, His
notifyIsBotChanged();
setMouseTracking(true);
subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) {
itemRemoved(item);
});
}
void HistoryInner::messagesReceived(PeerData *peer, const QVector<MTPMessage> &messages) {
@ -969,7 +972,11 @@ void HistoryInner::onDragExec() {
}
void HistoryInner::itemRemoved(HistoryItem *item) {
SelectedItems::iterator i = _selected.find(item);
if (_history != item->history() && _migrated != item->history()) {
return;
}
auto i = _selected.find(item);
if (i != _selected.cend()) {
_selected.erase(i);
_widget->updateTopBarSelection();
@ -3130,7 +3137,10 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
connect(&_updateEditTimeLeftDisplay, SIGNAL(timeout()), this, SLOT(updateField()));
subscribe(Adaptive::Changed(), [this]() { update(); });
subscribe(Adaptive::Changed(), [this] { update(); });
subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) {
itemRemoved(item);
});
}
void HistoryWidget::start() {
@ -7044,7 +7054,6 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
}
void HistoryWidget::itemRemoved(HistoryItem *item) {
if (_list) _list->itemRemoved(item);
if (item == _replyEditMsg) {
if (_editMsgId) {
cancelEdit();

View file

@ -46,11 +46,10 @@ class DragArea;
class EmojiPan;
class HistoryWidget;
class HistoryInner : public TWidget, public AbstractTooltipShower {
class HistoryInner : public TWidget, public AbstractTooltipShower, private base::Subscriber {
Q_OBJECT
public:
HistoryInner(HistoryWidget *historyWidget, ScrollArea *scroll, History *history);
void messagesReceived(PeerData *peer, const QVector<MTPMessage> &messages);
@ -92,8 +91,6 @@ public:
void fillSelectedItems(SelectedItemSet &sel, bool forDelete = true);
void selectItem(HistoryItem *item);
void itemRemoved(HistoryItem *item);
void updateBotInfo(bool recount = true);
bool wasSelectedText() const;
@ -126,7 +123,6 @@ protected:
bool focusNextPrevChild(bool next) override;
public slots:
void onUpdateSelected();
void onParentGeometryChanged();
@ -146,11 +142,11 @@ public slots:
void onDragExec();
private slots:
void onScrollDateCheck();
void onScrollDateHide();
private:
void itemRemoved(HistoryItem *item);
void touchResetSpeed();
void touchUpdateSpeed();
@ -633,7 +629,6 @@ public:
void stopAnimActive();
void fillSelectedItems(SelectedItemSet &sel, bool forDelete = true);
void itemRemoved(HistoryItem *item);
void itemEdited(HistoryItem *item);
void updateScrollColors();
@ -733,12 +728,10 @@ public:
~HistoryWidget();
signals:
void cancelled();
void historyShown(History *history, MsgId atMsgId);
public slots:
void onCancel();
void onReplyToMessage();
void onEditMessage();
@ -841,7 +834,6 @@ public slots:
void preloadHistoryIfNeeded();
private slots:
void onHashtagOrBotCommandInsert(QString str, FieldAutocomplete::ChooseMethod method);
void onMentionInsert(UserData *user);
void onInlineBotCancel();
@ -853,6 +845,7 @@ private slots:
void updateField();
private:
void itemRemoved(HistoryItem *item);
// Updates position of controls around the message field,
// like send button, emoji button and others.

View file

@ -73,6 +73,8 @@ MainWidget::MainWidget(MainWindow *window) : TWidget(window)
, _dialogs(this)
, _history(this)
, _topBar(this)
, _playerPlaylist(this, Media::Player::Panel::Layout::OnlyPlaylist)
, _playerPanel(this, Media::Player::Panel::Layout::Full)
, _mediaType(this)
, _api(new ApiWrap(this)) {
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
@ -120,6 +122,30 @@ MainWidget::MainWidget(MainWindow *window) : TWidget(window)
});
connect(&_cacheBackgroundTimer, SIGNAL(timeout()), this, SLOT(onCacheBackground()));
if (Media::Player::exists()) {
_playerPanel->setPinCallback([this] { switchToFixedPlayer(); });
subscribe(Media::Player::instance()->titleButtonOver(), [this](bool over) {
if (over) {
_playerPanel->showFromOther();
} else {
_playerPanel->hideFromOther();
}
});
subscribe(Media::Player::instance()->playerWidgetOver(), [this](bool over) {
if (over) {
if (_playerPlaylist->isHidden()) {
auto position = mapFromGlobal(QCursor::pos()).x();
auto bestPosition = _playerPlaylist->bestPositionFor(position);
if (rtl()) bestPosition = position + 2 * (position - bestPosition) - _playerPlaylist->width();
updateMediaPlaylistPosition(bestPosition);
}
_playerPlaylist->showFromOther();
} else {
_playerPlaylist->hideFromOther();
}
});
}
subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); });
_dialogs->show();
@ -175,6 +201,7 @@ bool MainWidget::onForward(const PeerId &peer, ForwardWhatMessages what) {
_toForward.insert(item->id, item);
}
}
updateForwardingItemRemovedSubscription();
updateForwardingTexts();
Ui::showPeerHistory(peer, ShowAtUnreadMsgId);
_history->onClearSelected();
@ -277,11 +304,31 @@ void MainWidget::updateForwardingTexts() {
_toForwardNameVersion = version;
}
void MainWidget::updateForwardingItemRemovedSubscription() {
if (_toForward.isEmpty()) {
unsubscribe(_forwardingItemRemovedSubscription);
_forwardingItemRemovedSubscription = 0;
} else if (!_forwardingItemRemovedSubscription) {
_forwardingItemRemovedSubscription = subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) {
auto i = _toForward.find(item->id);
if (i == _toForward.cend() || i.value() != item) {
i = _toForward.find(item->id - ServerMaxMsgId);
}
if (i != _toForward.cend() && i.value() == item) {
_toForward.erase(i);
updateForwardingItemRemovedSubscription();
updateForwardingTexts();
}
});
}
}
void MainWidget::cancelForwarding() {
if (_toForward.isEmpty()) return;
_toForward.clear();
_history->cancelForwarding();
updateForwardingItemRemovedSubscription();
}
void MainWidget::finishForwarding(History *history, bool silent) {
@ -489,9 +536,8 @@ void MainWidget::ui_repaintHistoryItem(const HistoryItem *item) {
if (item->history()->lastMsg == item) {
item->history()->updateChatListEntry();
}
if (_playerPanel && !_playerPanel->isHidden()) {
_playerPanel->ui_repaintHistoryItem(item);
}
_playerPlaylist->ui_repaintHistoryItem(item);
_playerPanel->ui_repaintHistoryItem(item);
if (_overview) _overview->ui_repaintHistoryItem(item);
}
@ -1359,32 +1405,6 @@ void MainWidget::changingMsgId(HistoryItem *row, MsgId newId) {
if (_overview) _overview->changingMsgId(row, newId);
}
void MainWidget::itemRemoved(HistoryItem *item) {
_dialogs->itemRemoved(item);
if (_history->peer() == item->history()->peer || (_history->peer() && _history->peer() == item->history()->peer->migrateTo())) {
_history->itemRemoved(item);
}
if (_overview && (_overview->peer() == item->history()->peer || (_overview->peer() && _overview->peer() == item->history()->peer->migrateTo()))) {
_overview->itemRemoved(item);
}
if (_playerPanel) {
_playerPanel->itemRemoved(item);
}
if (!_toForward.isEmpty()) {
SelectedItemSet::iterator i = _toForward.find(item->id);
if (i != _toForward.cend() && i.value() == item) {
_toForward.erase(i);
updateForwardingTexts();
} else {
i = _toForward.find(item->id - ServerMaxMsgId);
if (i != _toForward.cend() && i.value() == item) {
_toForward.erase(i);
updateForwardingTexts();
}
}
}
}
void MainWidget::itemEdited(HistoryItem *item) {
if (_history->peer() == item->history()->peer || (_history->peer() && _history->peer() == item->history()->peer->migrateTo())) {
_history->itemEdited(item);
@ -1558,7 +1578,7 @@ void MainWidget::handleAudioUpdate(const AudioMsgId &audioId) {
}
if (playing == audioId && audioId.type() == AudioMsgId::Type::Song) {
if (!_playerPanel && !_player && Media::Player::exists()) {
if (!_playerUsingPanel && !_player && Media::Player::exists()) {
createPlayer();
}
}
@ -1574,19 +1594,20 @@ void MainWidget::handleAudioUpdate(const AudioMsgId &audioId) {
}
void MainWidget::switchToPanelPlayer() {
if (_playerUsingPanel) return;
_playerUsingPanel = true;
_player->slideUp();
_playerVolume.destroyDelayed();
if (!_playerPanel) {
_playerPanel.create(this, Media::Player::Panel::Layout::Full);
_playerPanel->setPinCallback([this] { switchToFixedPlayer(); });
updateMediaPlayerPosition();
orderWidgets();
Media::Player::instance()->createdNotifier().notify(Media::Player::PanelEvent(_playerPanel), true);
}
_playerPlaylist->hideIgnoringEnterEvents();
Media::Player::instance()->usePanelPlayer().notify(true, true);
}
void MainWidget::switchToFixedPlayer() {
_playerPanel.destroyDelayed();
if (!_playerUsingPanel) return;
_playerUsingPanel = false;
if (!_player) {
createPlayer();
} else {
@ -1597,6 +1618,9 @@ void MainWidget::switchToFixedPlayer() {
updateMediaPlayerPosition();
}
}
Media::Player::instance()->usePanelPlayer().notify(false, true);
_playerPanel->hideIgnoringEnterEvents();
}
void MainWidget::createPlayer() {
@ -1623,7 +1647,7 @@ void MainWidget::playerHeightUpdated() {
_playerHeight = playerHeight;
updateControlsGeometry();
}
if (_playerPanel && !_playerHeight && _player->isHidden()) {
if (_playerUsingPanel && !_playerHeight && _player->isHidden()) {
_playerVolume.destroyDelayed();
_player.destroyDelayed();
}
@ -2319,6 +2343,15 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarS
if (playerVolumeVisible) {
_playerVolume->hide();
}
auto playerPanelVisible = !_playerPanel->isHidden();
if (playerPanelVisible) {
_playerPanel->hide();
}
auto playerPlaylistVisible = !_playerPlaylist->isHidden();
if (playerPlaylistVisible) {
_playerPlaylist->hide();
}
if (selectingPeer() && Adaptive::OneColumn()) {
result.oldContentCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
} else if (_wideSection) {
@ -2341,9 +2374,16 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarS
if (_overview) _overview->grabFinish();
_history->grabFinish();
}
if (playerVolumeVisible) {
_playerVolume->show();
}
if (playerPanelVisible) {
_playerPanel->show();
}
if (playerPlaylistVisible) {
_playerPlaylist->show();
}
if (_player) {
_player->showShadow();
}
@ -2452,7 +2492,8 @@ void MainWidget::orderWidgets() {
}
_mediaType->raise();
_sideShadow->raise();
if (_playerPanel) _playerPanel->raise();
_playerPlaylist->raise();
_playerPanel->raise();
if (_hider) _hider->raise();
}
@ -2473,6 +2514,15 @@ QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams &param
if (playerVolumeVisible) {
_playerVolume->hide();
}
auto playerPanelVisible = !_playerPanel->isHidden();
if (playerPanelVisible) {
_playerPanel->hide();
}
auto playerPlaylistVisible = !_playerPlaylist->isHidden();
if (playerPlaylistVisible) {
_playerPlaylist->hide();
}
if (Adaptive::OneColumn()) {
result = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
} else {
@ -2483,6 +2533,12 @@ QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams &param
if (playerVolumeVisible) {
_playerVolume->show();
}
if (playerPanelVisible) {
_playerPanel->show();
}
if (playerPlaylistVisible) {
_playerPlaylist->show();
}
if (_player) {
_player->showShadow();
}
@ -2762,20 +2818,34 @@ void MainWidget::updateControlsGeometry() {
}
if (_overview) _overview->setGeometry(_history->geometry());
updateMediaPlayerPosition();
updateMediaPlaylistPosition(_playerPlaylist->x());
_contentScrollAddToY = 0;
}
void MainWidget::updateMediaPlayerPosition() {
if (_playerPanel) {
_playerPanel->moveToRight(0, 0);
}
if (_playerVolume && _player) {
_playerPanel->moveToRight(0, 0);
if (_player && _playerVolume) {
auto relativePosition = _player->entity()->getPositionForVolumeWidget();
auto playerMargins = _playerVolume->getMargin();
_playerVolume->moveToLeft(_player->x() + relativePosition.x() - playerMargins.left(), _player->y() + relativePosition.y() - playerMargins.top());
}
}
void MainWidget::updateMediaPlaylistPosition(int x) {
if (_player) {
auto playlistLeft = x;
auto playlistWidth = _playerPlaylist->width();
auto playlistTop = _player->y() + _player->height();
auto rightEdge = width();
if (playlistLeft + playlistWidth > rightEdge) {
playlistLeft = rightEdge - playlistWidth;
} else if (playlistLeft < 0) {
playlistLeft = 0;
}
_playerPlaylist->move(playlistLeft, playlistTop);
}
}
int MainWidget::contentScrollAddToY() const {
return _contentScrollAddToY;
}
@ -3529,7 +3599,8 @@ void MainWidget::onSelfParticipantUpdated(ChannelData *channel) {
bool MainWidget::contentOverlapped(const QRect &globalRect) {
return (_history->contentOverlapped(globalRect) ||
(_playerPanel && _playerPanel->overlaps(globalRect)) ||
_playerPanel->overlaps(globalRect) ||
_playerPlaylist->overlaps(globalRect) ||
(_playerVolume && _playerVolume->overlaps(globalRect)) ||
_mediaType->overlaps(globalRect));
}

View file

@ -307,7 +307,6 @@ public:
void preloadOverviews(PeerData *peer);
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
void changingMsgId(HistoryItem *row, MsgId newId);
void itemRemoved(HistoryItem *item);
void itemEdited(HistoryItem *item);
void loadMediaBack(PeerData *peer, MediaOverviewType type, bool many = false);
@ -340,7 +339,6 @@ public:
bool hasForwardingItems();
void fillForwardingInfo(Text *&from, Text *&text, bool &serviceColor, ImagePtr &preview);
void updateForwardingTexts();
void cancelForwarding();
void finishForwarding(History *hist, bool silent); // send them
@ -484,8 +482,12 @@ private:
void updateAdaptiveLayout();
void handleAudioUpdate(const AudioMsgId &audioId);
void updateMediaPlayerPosition();
void updateMediaPlaylistPosition(int x);
void updateControlsGeometry();
void updateForwardingTexts();
void updateForwardingItemRemovedSubscription();
void createPlayer();
void switchToPanelPlayer();
void switchToFixedPlayer();
@ -520,6 +522,7 @@ private:
SelectedItemSet _toForward;
Text _toForwardFrom, _toForwardText;
int32 _toForwardNameVersion = 0;
int _forwardingItemRemovedSubscription = 0;
OrderedSet<WebPageId> _webPagesUpdated;
OrderedSet<GameId> _gamesUpdated;
@ -589,9 +592,13 @@ private:
ChildWidget<Window::SectionWidget> _wideSection = { nullptr };
ChildWidget<OverviewWidget> _overview = { nullptr };
ChildWidget<Window::TopBarWidget> _topBar;
ChildWidget<Window::PlayerWrapWidget> _player = { nullptr };
ChildWidget<Media::Player::VolumeWidget> _playerVolume = { nullptr };
ChildWidget<Media::Player::Panel> _playerPanel = { nullptr };
ChildWidget<Media::Player::Panel> _playerPlaylist;
ChildWidget<Media::Player::Panel> _playerPanel;
bool _playerUsingPanel = false;
ConfirmBox *_forwardConfirm = nullptr; // for single column layout
ChildWidget<HistoryHider> _hider = { nullptr };
std_::vector_of_moveable<std_::unique_ptr<StackItem>> _stack;

View file

@ -90,7 +90,7 @@ MainWindow::MainWindow() {
iconbig32 = iconbig256.scaledToWidth(32, Qt::SmoothTransformation);
iconbig64 = iconbig256.scaledToWidth(64, Qt::SmoothTransformation);
subscribe(Global::RefNotifySettingsChanged(), [this](const Notify::ChangeType &type) {
subscribe(Global::RefNotifySettingsChanged(), [this](Notify::ChangeType type) {
if (type == Notify::ChangeType::DesktopEnabled) {
updateTrayMenu();
notifyClear();

View file

@ -239,13 +239,20 @@ mediaPlayerScroll: flatScroll(solidScroll) {
}
mediaPlayerListHeightMax: 280px;
mediaPlayerListMarginBottom: 10px;
mediaPlayerScrollShadow: icon {{ "player_playlist_shadow", #000000 }};
mediaPlayerScrollShadow: icon {{ "playlist_shadow", #000000 }};
mediaPlayerListMarginTop: 8px;
mediaPlayerListIconFg: #ffffff;
mediaPlayerFileLayout: OverviewFileLayout(overviewFileLayout) {
maxWidth: 344px;
songPadding: margins(17px, 7px, 10px, 6px);
songThumbSize: 36px;
songNameTop: 7px;
songStatusTop: 25px;
songIconBg: mediaPlayerActiveFg;
songOverBg: mediaPlayerActiveFg;
songPause: icon {{ "playlist_pause", mediaPlayerListIconFg }};
songPlay: icon {{ "playlist_play", mediaPlayerListIconFg }};
songCancel: icon {{ "playlist_cancel", mediaPlayerListIconFg }};
songDownload: icon {{ "playlist_download", mediaPlayerListIconFg }};
}

View file

@ -80,6 +80,7 @@ CoverWidget::CoverWidget(QWidget *parent) : TWidget(parent)
, _pinPlayer(this, st::mediaPlayerPanelPinButton)
, _repeatTrack(this, st::mediaPlayerRepeatButton) {
setAttribute(Qt::WA_OpaquePaintEvent);
resize(width(), st::mediaPlayerCoverHeight);
_playback->setChangeProgressCallback([this](float64 value) {
handleSeekProgress(value);
@ -315,12 +316,14 @@ void CoverWidget::handlePlaylistUpdate() {
void CoverWidget::createPrevNextButtons() {
if (!_previousTrack) {
_previousTrack.create(this, st::mediaPlayerPanelPreviousButton);
_nextTrack.create(this, st::mediaPlayerPanelNextButton);
_previousTrack->show();
_previousTrack->setClickedCallback([this]() {
if (exists()) {
instance()->previous();
}
});
_nextTrack.create(this, st::mediaPlayerPanelNextButton);
_nextTrack->show();
_nextTrack->setClickedCallback([this]() {
if (exists()) {
instance()->next();

View file

@ -40,12 +40,6 @@ bool exists();
class Instance;
Instance *instance();
class Panel;
struct PanelEvent {
explicit PanelEvent(Panel *panel) : panel(panel) {
}
Panel *panel;
};
struct UpdatedEvent {
UpdatedEvent(const AudioMsgId *audioId, const AudioPlaybackState *playbackState) : audioId(audioId), playbackState(playbackState) {
}
@ -87,11 +81,14 @@ public:
return _playlist;
}
base::Observable<PanelEvent> &createdNotifier() {
return _createdNotifier;
base::Observable<bool> &usePanelPlayer() {
return _usePanelPlayer;
}
base::Observable<PanelEvent> &destroyedNotifier() {
return _destroyedNotifier;
base::Observable<bool> &titleButtonOver() {
return _titleButtonOver;
}
base::Observable<bool> &playerWidgetOver() {
return _playerWidgetOver;
}
base::Observable<UpdatedEvent> &updatedNotifier() {
return _updatedNotifier;
@ -133,8 +130,9 @@ private:
QList<FullMsgId> _playlist;
bool _isPlaying = false;
base::Observable<PanelEvent> _createdNotifier;
base::Observable<PanelEvent> _destroyedNotifier;
base::Observable<bool> _usePanelPlayer;
base::Observable<bool> _titleButtonOver;
base::Observable<bool> _playerWidgetOver;
base::Observable<UpdatedEvent> _updatedNotifier;
base::Observable<void> _playlistChangedNotifier;
base::Observable<void> _songChangedNotifier;

View file

@ -34,6 +34,9 @@ ListWidget::ListWidget() {
if (exists()) {
subscribe(instance()->playlistChangedNotifier(), [this] { playlistUpdated(); });
}
subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) {
itemRemoved(item);
});
}
ListWidget::~ListWidget() {
@ -143,10 +146,32 @@ void ListWidget::itemRemoved(HistoryItem *item) {
if (layoutIt != _layouts.cend()) {
auto layout = layoutIt.value();
_layouts.erase(layoutIt);
for (int i = 0, count = _list.size(); i != count; ++i) {
if (_list[i] == layout) {
_list.removeAt(i);
break;
}
}
delete layout;
}
}
QRect ListWidget::getCurrentTrackGeometry() const {
if (exists()) {
auto top = marginTop();
auto current = instance()->current();
for_const (auto layout, _list) {
auto layoutHeight = layout->height();
if (layout->getItem()->fullId() == current.contextId()) {
return QRect(0, top, width(), layoutHeight);
}
top += layoutHeight;
}
}
return QRect(0, height(), width(), 0);
}
int ListWidget::resizeGetHeight(int newWidth) {
auto result = 0;
for_const (auto layout, _list) {

View file

@ -34,7 +34,8 @@ public:
ListWidget();
void ui_repaintHistoryItem(const HistoryItem *item);
void itemRemoved(HistoryItem *item);
QRect getCurrentTrackGeometry() const;
~ListWidget();
@ -47,6 +48,7 @@ protected:
int resizeGetHeight(int newWidth) override;
private:
void itemRemoved(HistoryItem *item);
int marginTop() const;
void repaintItem(const HistoryItem *item);
void playlistUpdated();

View file

@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "media/player/media_player_cover.h"
#include "media/player/media_player_list.h"
#include "media/player/media_player_instance.h"
#include "styles/style_overview.h"
#include "styles/style_media_player.h"
#include "ui/widgets/shadow.h"
#include "mainwindow.h"
@ -32,36 +33,25 @@ namespace Media {
namespace Player {
Panel::Panel(QWidget *parent, Layout layout) : TWidget(parent)
, _layout(layout)
, _shadow(st::defaultInnerDropdown.shadow)
, _scroll(this, st::mediaPlayerScroll)
, _scrollShadow(this, st::mediaPlayerScrollShadow) {
if (layout == Layout::Full) {
_cover.create(this);
}
, _scroll(this, st::mediaPlayerScroll) {
_hideTimer.setSingleShot(true);
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart()));
auto list = std_::make_unique<ListWidget>();
connect(list.get(), SIGNAL(heightUpdated()), this, SLOT(onListHeightUpdated()));
_scroll->setOwnedWidget(list.release());
_showTimer.setSingleShot(true);
connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShowStart()));
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged()));
}
hide();
onListHeightUpdated();
updateSize();
}
bool Panel::overlaps(const QRect &globalRect) {
if (isHidden() || _a_appearance.animating()) return false;
auto marginLeft = rtl() ? 0 : contentLeft();
auto marginRight = rtl() ? contentLeft() : 0;
return rect().marginsRemoved(QMargins(marginLeft, 0, marginRight, st::mediaPlayerPanelMarginBottom)).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
auto marginLeft = rtl() ? contentRight() : contentLeft();
auto marginRight = rtl() ? contentLeft() : contentRight();
return rect().marginsRemoved(QMargins(marginLeft, contentTop(), marginRight, contentBottom())).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
void Panel::onWindowActiveChanged() {
@ -71,16 +61,28 @@ void Panel::onWindowActiveChanged() {
}
void Panel::resizeEvent(QResizeEvent *e) {
auto width = contentWidth();
_cover->resize(width, st::mediaPlayerCoverHeight);
_cover->moveToRight(0, 0);
updateControlsGeometry();
}
auto scrollTop = _cover->height();
auto scrollHeight = qMax(contentHeight() - scrollTop - st::mediaPlayerListMarginBottom, 0);
void Panel::onListHeightUpdated() {
updateSize();
}
void Panel::updateControlsGeometry() {
auto scrollTop = contentTop();
auto width = contentWidth();
if (_cover) {
_cover->resizeToWidth(width);
_cover->moveToRight(contentRight(), scrollTop);
scrollTop += _cover->height();
if (_scrollShadow) {
_scrollShadow->resizeToWidth(width);
_scrollShadow->moveToRight(contentRight(), scrollTop);
}
}
auto scrollHeight = qMax(height() - scrollTop - contentBottom() - scrollMarginBottom(), 0);
if (scrollHeight > 0) {
_scroll->setGeometryToRight(0, scrollTop, width, scrollHeight);
_scrollShadow->resizeToWidth(width);
_scrollShadow->moveToRight(0, scrollTop);
_scroll->setGeometryToRight(contentRight(), scrollTop, width, scrollHeight);
}
if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
widget->resizeToWidth(width);
@ -88,19 +90,28 @@ void Panel::resizeEvent(QResizeEvent *e) {
}
}
void Panel::onListHeightUpdated() {
updateSize();
}
void Panel::ui_repaintHistoryItem(const HistoryItem *item) {
if (auto list = static_cast<ListWidget*>(_scroll->widget())) {
list->ui_repaintHistoryItem(item);
}
}
void Panel::itemRemoved(HistoryItem *item) {
int Panel::bestPositionFor(int left) const {
left -= contentLeft();
left -= st::mediaPlayerFileLayout.songPadding.left();
left -= st::mediaPlayerFileLayout.songThumbSize / 2;
return left;
}
void Panel::scrollPlaylistToCurrentTrack() {
if (auto list = static_cast<ListWidget*>(_scroll->widget())) {
list->itemRemoved(item);
auto rect = list->getCurrentTrackGeometry();
auto top = _scroll->scrollTop(), bottom = top + _scroll->height();
_scroll->scrollToY(rect.y());
//if (top > rect.y()) {
//} else if (bottom < rect.y() + rect.height()) {
// _scroll->scrollToY(rect.y() + rect.height() - _scroll->height());
//}
}
}
@ -113,17 +124,23 @@ void Panel::onScroll() {
}
void Panel::updateSize() {
auto width = contentLeft() + st::mediaPlayerPanelWidth + contentRight();
auto height = contentTop();
if (_cover) {
height += _cover->height();
}
auto listHeight = 0;
if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
listHeight = widget->height();
}
auto scrollVisible = (listHeight > 0);
auto scrollHeight = scrollVisible ? (qMin(listHeight, st::mediaPlayerListHeightMax) + st::mediaPlayerListMarginBottom) : 0;
auto width = contentLeft() + st::mediaPlayerPanelWidth;
auto height = st::mediaPlayerCoverHeight + scrollHeight + st::mediaPlayerPanelMarginBottom;
height += scrollHeight + contentBottom();
resize(width, height);
_scroll->setVisible(scrollVisible);
_scrollShadow->setVisible(scrollVisible);
if (_scrollShadow) {
_scrollShadow->setVisible(scrollVisible);
}
}
void Panel::paintEvent(QPaintEvent *e) {
@ -146,13 +163,19 @@ void Panel::paintEvent(QPaintEvent *e) {
}
// draw shadow
auto shadowedRect = myrtlrect(contentLeft(), 0, contentWidth(), height() - st::mediaPlayerPanelMarginBottom);
auto shadowedSides = (rtl() ? Ui::RectShadow::Side::Right : Ui::RectShadow::Side::Left) | Ui::RectShadow::Side::Bottom;
using Side = Ui::RectShadow::Side;
auto shadowedRect = myrtlrect(contentLeft(), contentTop(), contentWidth(), contentHeight());
auto shadowedSides = (rtl() ? Side::Right : Side::Left) | Side::Bottom;
if (_layout != Layout::Full) {
shadowedSides |= (rtl() ? Side::Left : Side::Right) | Side::Top;
}
_shadow.paint(p, shadowedRect, st::defaultInnerDropdown.shadowShift, shadowedSides);
p.fillRect(shadowedRect, st::windowBg);
}
void Panel::enterEvent(QEvent *e) {
if (_ignoringEnterEvents) return;
_hideTimer.stop();
if (_a_appearance.animating(getms())) {
onShowStart();
@ -172,7 +195,7 @@ void Panel::leaveEvent(QEvent *e) {
return TWidget::leaveEvent(e);
}
void Panel::otherEnter() {
void Panel::showFromOther() {
_hideTimer.stop();
if (_a_appearance.animating(getms())) {
onShowStart();
@ -181,7 +204,7 @@ void Panel::otherEnter() {
}
}
void Panel::otherLeave() {
void Panel::hideFromOther() {
_showTimer.stop();
if (_a_appearance.animating(getms())) {
onHideStart();
@ -190,20 +213,56 @@ void Panel::otherLeave() {
}
}
void Panel::setPinCallback(PinCallback &&callback) {
if (_cover) {
_cover->setPinCallback(std_::move(callback));
void Panel::ensureCreated() {
if (_scroll->widget()) return;
if (_layout == Layout::Full) {
_cover.create(this);
setPinCallback(std_::move(_pinCallback));
_scrollShadow.create(this, st::mediaPlayerScrollShadow);
}
auto list = std_::make_unique<ListWidget>();
connect(list.get(), SIGNAL(heightUpdated()), this, SLOT(onListHeightUpdated()));
_scroll->setOwnedWidget(list.release());
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
if (auto window = App::wnd()) {
connect(window->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged()));
}
}
updateSize();
updateControlsGeometry();
_ignoringEnterEvents = false;
}
void Panel::performDestroy() {
if (!_scroll->widget()) return;
_cover.destroy();
auto list = _scroll->takeWidget();
list->hide();
list->deleteLater();
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
if (auto window = App::wnd()) {
disconnect(window->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged()));
}
}
}
Panel::~Panel() {
if (exists()) {
instance()->destroyedNotifier().notify(Media::Player::PanelEvent(this), true);
void Panel::setPinCallback(PinCallback &&callback) {
_pinCallback = std_::move(callback);
if (_cover) {
_cover->setPinCallback(PinCallback(_pinCallback));
}
}
void Panel::onShowStart() {
ensureCreated();
if (isHidden()) {
scrollPlaylistToCurrentTrack();
show();
} else if (!_hiding) {
return;
@ -212,8 +271,17 @@ void Panel::onShowStart() {
startAnimation();
}
void Panel::hideIgnoringEnterEvents() {
_ignoringEnterEvents = true;
if (isHidden()) {
hidingFinished();
} else {
onHideStart();
}
}
void Panel::onHideStart() {
if (_hiding) return;
if (_hiding || isHidden()) return;
_hiding = true;
startAnimation();
@ -242,23 +310,27 @@ void Panel::appearanceCallback() {
void Panel::hidingFinished() {
hide();
_cache = QPixmap();
performDestroy();
}
int Panel::contentLeft() const {
return st::mediaPlayerPanelMarginLeft;
}
int Panel::contentHeight() const {
return height() - st::mediaPlayerPanelMarginBottom;
int Panel::contentTop() const {
return (_layout == Layout::Full) ? 0 : st::mediaPlayerPanelMarginLeft;
}
bool Panel::eventFilter(QObject *obj, QEvent *e) {
if (e->type() == QEvent::Enter) {
otherEnter();
} else if (e->type() == QEvent::Leave) {
otherLeave();
}
return false;
int Panel::contentRight() const {
return (_layout == Layout::Full) ? 0 : st::mediaPlayerPanelMarginLeft;
}
int Panel::contentBottom() const {
return st::mediaPlayerPanelMarginBottom;
}
int Panel::scrollMarginBottom() const {
return st::mediaPlayerPanelMarginBottom;
}
} // namespace Player

View file

@ -34,7 +34,7 @@ namespace Player {
class CoverWidget;
class ListWidget;
class Panel : public TWidget, private base::Subscriber {
class Panel : public TWidget {
Q_OBJECT
public:
@ -44,19 +44,19 @@ public:
};
Panel(QWidget *parent, Layout layout);
void setLayout(Layout layout);
bool overlaps(const QRect &globalRect);
void otherEnter();
void otherLeave();
void hideIgnoringEnterEvents();
using PinCallback = base::lambda_unique<void()>;
void showFromOther();
void hideFromOther();
using PinCallback = base::lambda_wrap<void()>;
void setPinCallback(PinCallback &&callback);
void ui_repaintHistoryItem(const HistoryItem *item);
void itemRemoved(HistoryItem *item);
~Panel();
int bestPositionFor(int left) const;
protected:
void resizeEvent(QResizeEvent *e) override;
@ -64,40 +64,53 @@ protected:
void enterEvent(QEvent *e) override;
void leaveEvent(QEvent *e) override;
bool eventFilter(QObject *obj, QEvent *e) override;
private slots:
void onShowStart();
void onHideStart();
void onScroll();
void onListHeightUpdated();
void onWindowActiveChanged();
private:
void ensureCreated();
void performDestroy();
void updateControlsGeometry();
void updateSize();
void appearanceCallback();
void hidingFinished();
int contentLeft() const;
int contentTop() const;
int contentRight() const;
int contentBottom() const;
int scrollMarginBottom() const;
int contentWidth() const {
return width() - contentLeft();
return width() - contentLeft() - contentRight();
}
int contentHeight() const {
return height() - contentTop() - contentBottom();;
}
int contentHeight() const;
void startAnimation();
void scrollPlaylistToCurrentTrack();
Layout _layout;
bool _hiding = false;
QPixmap _cache;
FloatAnimation _a_appearance;
bool _ignoringEnterEvents = false;
QTimer _hideTimer, _showTimer;
Ui::RectShadow _shadow;
PinCallback _pinCallback;
ChildWidget<CoverWidget> _cover = { nullptr };
ChildWidget<ScrollArea> _scroll;
ChildWidget<Ui::GradientShadow> _scrollShadow;
ChildWidget<Ui::GradientShadow> _scrollShadow = { nullptr };
};

View file

@ -102,6 +102,20 @@ void TitleButton::paintIcon(Painter &p) {
_layout->paint(p, icon);
}
void TitleButton::enterEvent(QEvent *e) {
if (exists()) {
instance()->titleButtonOver().notify(true, true);
}
return Button::enterEvent(e);
}
void TitleButton::leaveEvent(QEvent *e) {
if (exists()) {
instance()->titleButtonOver().notify(false, true);
}
return Button::leaveEvent(e);
}
TitleButton::~TitleButton() = default;
} // namespace Player

View file

@ -37,6 +37,8 @@ public:
protected:
void paintEvent(QPaintEvent *e) override;
void enterEvent(QEvent *e) override;
void leaveEvent(QEvent *e) override;
void onStateChanged(int oldState, ButtonStateChangeSource source) override;

View file

@ -81,8 +81,12 @@ Widget::Widget(QWidget *parent) : TWidget(parent)
, _shadow(this, st::shadowColor)
, _playback(new Ui::FilledSlider(this, st::mediaPlayerPlayback)) {
setAttribute(Qt::WA_OpaquePaintEvent);
setMouseTracking(true);
resize(st::wndMinWidth, st::mediaPlayerHeight + st::lineWidth);
_nameLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
_timeLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
_playback->setChangeProgressCallback([this](float64 value) {
handleSeekProgress(value);
});
@ -226,6 +230,28 @@ void Widget::paintEvent(QPaintEvent *e) {
}
}
void Widget::leaveEvent(QEvent *e) {
updateOverLabelsState(false);
}
void Widget::mouseMoveEvent(QMouseEvent *e) {
updateOverLabelsState(e->pos());
}
void Widget::updateOverLabelsState(QPoint pos) {
auto left = getLabelsLeft();
auto right = getLabelsRight();
auto labels = myrtlrect(left, 0, width() - right - left, height() - st::mediaPlayerPlayback.fullWidth);
auto over = labels.contains(pos);
updateOverLabelsState(over);
}
void Widget::updateOverLabelsState(bool over) {
if (exists()) {
instance()->playerWidgetOver().notify(over, true);
}
}
void Widget::updatePlayPrevNextPositions() {
auto left = st::mediaPlayerPlayLeft;
auto top = st::mediaPlayerPlayTop;
@ -238,15 +264,24 @@ void Widget::updatePlayPrevNextPositions() {
}
}
void Widget::updateLabelsGeometry() {
auto left = st::mediaPlayerPlayLeft + _playPause->width();
int Widget::getLabelsLeft() const {
auto result = st::mediaPlayerPlayLeft + _playPause->width();
if (_previousTrack) {
left += _previousTrack->width() + st::mediaPlayerPlaySkip + _nextTrack->width() + st::mediaPlayerPlaySkip;
result += _previousTrack->width() + st::mediaPlayerPlaySkip + _nextTrack->width() + st::mediaPlayerPlaySkip;
}
left += st::mediaPlayerPadding;
result += st::mediaPlayerPadding;
return result;
}
auto right = st::mediaPlayerCloseRight + _close->width() + _repeatTrack->width() + _volumeToggle->width();
right += st::mediaPlayerPadding;
int Widget::getLabelsRight() const {
auto result = st::mediaPlayerCloseRight + _close->width() + _repeatTrack->width() + _volumeToggle->width();
result += st::mediaPlayerPadding;
return result;
}
void Widget::updateLabelsGeometry() {
auto left = getLabelsLeft();
auto right = getLabelsRight();
auto widthForName = width() - left - right;
widthForName -= _timeLabel->width() + 2 * st::normalFont->spacew;
@ -367,12 +402,14 @@ void Widget::handlePlaylistUpdate() {
void Widget::createPrevNextButtons() {
if (!_previousTrack) {
_previousTrack.create(this, st::mediaPlayerPreviousButton);
_nextTrack.create(this, st::mediaPlayerNextButton);
_previousTrack->show();
_previousTrack->setClickedCallback([this]() {
if (exists()) {
instance()->previous();
}
});
_nextTrack.create(this, st::mediaPlayerNextButton);
_nextTrack->show();
_nextTrack->setClickedCallback([this]() {
if (exists()) {
instance()->next();

View file

@ -59,10 +59,18 @@ protected:
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void leaveEvent(QEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
private:
void handleSeekProgress(float64 progress);
void handleSeekFinished(float64 progress);
int getLabelsLeft() const;
int getLabelsRight() const;
void updateOverLabelsState(QPoint pos);
void updateOverLabelsState(bool over);
void updatePlayPrevNextPositions();
void updateLabelsGeometry();
void updateRepeatTrackIcon();
@ -81,6 +89,7 @@ private:
int64 _seekPositionMs = -1;
int64 _lastDurationMs = 0;
QString _time;
bool _mouseOverLabels = false;
class PlayButton;
ChildWidget<FlatLabel> _nameLabel;

View file

@ -33,7 +33,9 @@ Playback::Playback(Ui::ContinuousSlider *slider) : _slider(slider) {
void Playback::updateState(const AudioPlaybackState &playbackState) {
qint64 position = 0, duration = playbackState.duration;
setDisabled(false);
auto wasDisabled = _slider->isDisabled();
if (wasDisabled) setDisabled(false);
_playing = !(playbackState.state & AudioPlayerStoppedMask);
if (_playing || playbackState.state == AudioPlayerStopped) {
position = playbackState.position;
@ -49,7 +51,7 @@ void Playback::updateState(const AudioPlaybackState &playbackState) {
} else if (duration) {
progress = duration ? snap(float64(position) / duration, 0., 1.) : 0.;
}
if (duration != _duration || position != _position) {
if (duration != _duration || position != _position || wasDisabled) {
auto animated = (duration && _duration && progress > _slider->value());
_slider->setValue(progress, animated);
_position = position;

View file

@ -19,6 +19,7 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
using "basic.style";
using "history/history.style";
OverviewFileLayout {
maxWidth: pixels;
@ -26,6 +27,13 @@ OverviewFileLayout {
songThumbSize: pixels;
songNameTop: pixels;
songStatusTop: pixels;
songIconBg: color;
songOverBg: color;
songPause: icon;
songPlay: icon;
songCancel: icon;
songDownload: icon;
filePadding: margins;
fileThumbSize: pixels;
fileNameTop: pixels;
@ -61,6 +69,13 @@ overviewFileLayout: OverviewFileLayout {
songThumbSize: msgFileSize;
songNameTop: msgFileNameTop;
songStatusTop: msgFileStatusTop;
songIconBg: msgFileInBg;
songOverBg: msgFileInBgOver;
songPause: historyFileInPause;
songPlay: historyFileInPlay;
songCancel: historyFileInCancel;
songDownload: historyFileInDownload;
filePadding: margins(0px, 3px, 16px, 3px);
fileThumbSize: 70px;
fileNameTop: 7px;

View file

@ -667,10 +667,10 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
} else if (_a_iconOver.animating()) {
_a_iconOver.step(context->ms);
float64 over = a_iconOver.current();
p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over));
p.setBrush(style::interpolate(_st.songIconBg, _st.songOverBg, over));
} else {
bool over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _openl));
p.setBrush(over ? st::msgFileInBgOver : st::msgFileInBg);
p.setBrush(over ? _st.songOverBg : _st.songIconBg);
}
p.setRenderHint(QPainter::HighQualityAntialiasing);
@ -685,13 +685,13 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
auto icon = ([showPause, loaded, this, selected] {
if (showPause) {
return &(selected ? st::historyFileInPauseSelected : st::historyFileInPause);
return &(selected ? st::historyFileInPauseSelected : _st.songPause);
} else if (loaded) {
return &(selected ? st::historyFileInPlaySelected : st::historyFileInPlay);
return &(selected ? st::historyFileInPlaySelected : _st.songPlay);
} else if (_data->loading()) {
return &(selected ? st::historyFileInCancelSelected : st::historyFileInCancel);
return &(selected ? st::historyFileInCancelSelected : _st.songCancel);
}
return &(selected ? st::historyFileInDownloadSelected : st::historyFileInDownload);
return &(selected ? st::historyFileInDownloadSelected : _st.songDownload);
})();
icon->paintInCenter(p, inner);
}

View file

@ -38,59 +38,24 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerData *peer, MediaOverviewType type) : QWidget(0)
OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerData *peer, MediaOverviewType type) : TWidget(nullptr)
, _overview(overview)
, _scroll(scroll)
, _resizeIndex(-1)
, _resizeSkip(0)
, _peer(peer->migrateTo() ? peer->migrateTo() : peer)
, _type(type)
, _reversed(_type != OverviewFiles && _type != OverviewLinks)
, _migrated(_peer->migrateFrom() ? App::history(_peer->migrateFrom()->id) : 0)
, _history(App::history(_peer->id))
, _channel(peerToChannel(_peer->id))
, _selMode(false)
, _rowsLeft(0)
, _rowWidth(st::msgMinWidth)
, _search(this, st::dlgFilter, lang(lng_dlg_filter))
, _cancelSearch(this, st::btnCancelSearch)
, _itemsToBeLoaded(LinksOverviewPerPage * 2)
, _photosInRow(1)
, _inSearch(false)
, _searchFull(false)
, _searchFullMigrated(false)
, _searchRequest(0)
, _lastSearchId(0)
, _lastSearchMigratedId(0)
, _searchedCount(0)
, _width(st::wndMinWidth)
, _height(0)
, _minHeight(0)
, _marginTop(0)
, _marginBottom(0)
, _cursor(style::cur_default)
, _cursorState(HistoryDefaultCursorState)
, _dragAction(NoDrag)
, _dragItem(0)
, _selectedMsgId(0)
, _dragItemIndex(-1)
, _mousedItem(0)
, _mousedItemIndex(-1)
, _dragWasInactive(false)
, _dragSelFrom(0)
, _dragSelTo(0)
, _dragSelecting(false)
, _touchScroll(false)
, _touchSelect(false)
, _touchInProgress(false)
, _touchScrollState(TouchScrollManual)
, _touchPrevPosValid(false)
, _touchWaitingAcceleration(false)
, _touchSpeedTime(0)
, _touchAccelerationTime(0)
, _touchTime(0)
, _menu(0) {
, _width(st::wndMinWidth) {
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) {
itemRemoved(item);
});
resize(_width, st::wndMinHeight);
@ -1733,6 +1698,10 @@ void OverviewInner::changingMsgId(HistoryItem *row, MsgId newId) {
}
void OverviewInner::itemRemoved(HistoryItem *item) {
if (_history != item->history() && _migrated != item->history()) {
return;
}
MsgId msgId = (item->history() == _migrated) ? -item->id : item->id;
if (_dragItem == msgId) {
dragActionCancel();
@ -1741,13 +1710,13 @@ void OverviewInner::itemRemoved(HistoryItem *item) {
_selectedMsgId = 0;
}
SelectedItems::iterator i = _selected.find(msgId);
auto i = _selected.find(msgId);
if (i != _selected.cend()) {
_selected.erase(i);
_overview->updateTopBarSelection();
}
LayoutItems::iterator j = _layoutItems.find(item);
auto j = _layoutItems.find(item);
if (j != _layoutItems.cend()) {
int32 index = _items.indexOf(j.value());
if (index >= 0) {
@ -2218,10 +2187,6 @@ void OverviewWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {
}
}
void OverviewWidget::itemRemoved(HistoryItem *row) {
_inner.itemRemoved(row);
}
void OverviewWidget::fillSelectedItems(SelectedItemSet &sel, bool forDelete) {
_inner.fillSelectedItems(sel, forDelete);
}

View file

@ -36,7 +36,7 @@ class PlainShadow;
} // namespace Ui
class OverviewWidget;
class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender, private base::Subscriber {
class OverviewInner : public TWidget, public AbstractTooltipShower, public RPCSender, private base::Subscriber {
Q_OBJECT
public:
@ -73,7 +73,6 @@ public:
void mediaOverviewUpdated();
void changingMsgId(HistoryItem *row, MsgId newId);
void repaintItem(const HistoryItem *msg);
void itemRemoved(HistoryItem *item);
void getSelectionState(int32 &selectedForForward, int32 &selectedForDelete) const;
void clearSelectedItems(bool onlyTextSelection = false);
@ -124,6 +123,7 @@ public slots:
void onNeedSearchMessages();
private:
void itemRemoved(HistoryItem *item);
MsgId complexMsgId(const HistoryItem *item) const;
bool itemMigrated(MsgId msgId) const;
@ -152,7 +152,8 @@ private:
OverviewWidget *_overview;
ScrollArea *_scroll;
int32 _resizeIndex, _resizeSkip;
int _resizeIndex = -1;
int _resizeSkip = 0;
PeerData *_peer;
MediaOverviewType _type;
@ -160,10 +161,11 @@ private:
History *_migrated, *_history;
ChannelId _channel;
bool _selMode;
bool _selMode = false;
TextSelection itemSelectedValue(int32 index) const;
int32 _rowsLeft, _rowWidth;
int _rowsLeft = 0;
int _rowWidth = 0;
typedef QVector<Overview::Layout::AbstractItem*> Items;
Items _items;
@ -181,15 +183,18 @@ private:
int32 _itemsToBeLoaded;
// photos
int32 _photosInRow;
int32 _photosInRow = 1;
QTimer _searchTimer;
QString _searchQuery;
bool _inSearch, _searchFull, _searchFullMigrated;
mtpRequestId _searchRequest;
bool _inSearch = false;
bool _searchFull = false;
bool _searchFullMigrated = false;
mtpRequestId _searchRequest = 0;
History::MediaOverview _searchResults;
MsgId _lastSearchId, _lastSearchMigratedId;
int32 _searchedCount;
MsgId _lastSearchId = 0;
MsgId _lastSearchMigratedId = 0;
int _searchedCount = 0;
enum SearchRequestType {
SearchFromStart,
SearchFromOffset,
@ -205,13 +210,17 @@ private:
typedef QMap<mtpRequestId, QString> SearchQueries;
SearchQueries _searchQueries;
int32 _width, _height, _minHeight, _marginTop, _marginBottom;
int _width = 0;
int _height = 0;
int _minHeight = 0;
int _marginTop = 0;
int _marginBottom = 0;
QTimer _linkTipTimer;
// selection support, like in HistoryWidget
Qt::CursorShape _cursor;
HistoryCursorState _cursorState;
style::cursor _cursor = style::cur_default;
HistoryCursorState _cursorState = HistoryDefaultCursorState;
using SelectedItems = QMap<MsgId, TextSelection>;
SelectedItems _selected;
enum DragAction {
@ -221,32 +230,40 @@ private:
PrepareSelect = 0x03,
Selecting = 0x04,
};
DragAction _dragAction;
DragAction _dragAction = NoDrag;
QPoint _dragStartPos, _dragPos;
MsgId _dragItem, _selectedMsgId;
int32 _dragItemIndex;
MsgId _mousedItem;
int32 _mousedItemIndex;
MsgId _dragItem = 0;
MsgId _selectedMsgId = 0;
int _dragItemIndex = -1;
MsgId _mousedItem = 0;
int _mousedItemIndex = -1;
uint16 _dragSymbol;
bool _dragWasInactive;
bool _dragWasInactive = false;
ClickHandlerPtr _contextMenuLnk;
MsgId _dragSelFrom, _dragSelTo;
int32 _dragSelFromIndex, _dragSelToIndex;
bool _dragSelecting;
MsgId _dragSelFrom = 0;
MsgId _dragSelTo = 0;
int _dragSelFromIndex = -1;
int _dragSelToIndex = -1;
bool _dragSelecting = false;
bool _touchScroll, _touchSelect, _touchInProgress;
bool _touchScroll = false;
bool _touchSelect = false;
bool _touchInProgress = false;
QPoint _touchStart, _touchPrevPos, _touchPos;
QTimer _touchSelectTimer;
TouchScrollState _touchScrollState;
bool _touchPrevPosValid, _touchWaitingAcceleration;
TouchScrollState _touchScrollState = TouchScrollManual;
bool _touchPrevPosValid = false;
bool _touchWaitingAcceleration = false;
QPoint _touchSpeed;
uint64 _touchSpeedTime, _touchAccelerationTime, _touchTime;
uint64 _touchSpeedTime = 0;
uint64 _touchAccelerationTime = 0;
uint64 _touchTime = 0;
QTimer _touchScrollTimer;
PopupMenu *_menu;
PopupMenu *_menu = nullptr;
};
class OverviewWidget : public TWidget, public RPCSender {

View file

@ -35,7 +35,7 @@ namespace Settings {
NotificationsWidget::NotificationsWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_notify)) {
createControls();
subscribe(Global::RefNotifySettingsChanged(), [this](const Notify::ChangeType &type) {
subscribe(Global::RefNotifySettingsChanged(), [this](Notify::ChangeType type) {
if (type == Notify::ChangeType::DesktopEnabled) {
desktopEnabledUpdated();
} else if (type == Notify::ChangeType::ViewParams) {

View file

@ -103,18 +103,8 @@ TitleWidget::TitleWidget(QWidget *parent) : TWidget(parent)
subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); });
if (Media::Player::exists()) {
subscribe(Media::Player::instance()->createdNotifier(), [this](const Media::Player::PanelEvent &e) {
if (!_player) {
_player.create(this);
updateControlsVisibility();
}
_player->installEventFilter(e.panel);
});
subscribe(Media::Player::instance()->destroyedNotifier(), [this](const Media::Player::PanelEvent &e) {
if (_player) {
_player.destroyDelayed();
updateControlsVisibility();
}
subscribe(Media::Player::instance()->usePanelPlayer(), [this](bool usePanel) {
updatePlayerButton(usePanel);
});
}
@ -179,6 +169,15 @@ void TitleWidget::onAbout() {
Ui::showLayer(new AboutBox());
}
void TitleWidget::updatePlayerButton(bool usePanel) {
if (usePanel && !_player) {
_player.create(this);
} else if (!usePanel && _player) {
_player.destroyDelayed();
}
updateControlsVisibility();
}
void TitleWidget::updateControlsPosition() {
QPoint p(width() - ((cPlatform() == dbipWindows && lastMaximized) ? 0 : st::sysBtnDelta), 0);

View file

@ -27,7 +27,6 @@ class MainWindow;
namespace Media {
namespace Player {
class TitleButton;
class PanelEvent;
} // namespace Player
} // namespace Media
class AudioMsgId;
@ -65,6 +64,7 @@ protected:
void resizeEvent(QResizeEvent *e) override;
private:
void updatePlayerButton(bool usePanel);
void updateAdaptiveLayout();
void updateRestartButtonVisibility();
void updateMenuButtonsVisibility();

View file

@ -39,6 +39,9 @@ public:
void setValue(float64 value, bool animated);
void setFadeOpacity(float64 opacity);
void setDisabled(bool disabled);
bool isDisabled() const {
return _disabled;
}
using Callback = base::lambda_unique<void(float64)>;
void setChangeProgressCallback(Callback &&callback) {
@ -71,9 +74,6 @@ protected:
float64 getCurrentOverFactor(uint64 ms) {
return _disabled ? 0. : _a_over.current(ms, _over ? 1. : 0.);
}
bool isDisabled() const {
return _disabled;
}
Direction getDirection() const {
return _direction;
}

View file

@ -74,7 +74,7 @@ Manager::Manager() {
notification->updatePeerPhoto();
}
});
subscribe(Global::RefNotifySettingsChanged(), [this](const Notify::ChangeType &change) {
subscribe(Global::RefNotifySettingsChanged(), [this](Notify::ChangeType change) {
settingsChanged(change);
});
_inputCheckTimer.setTimeoutHandler([this] { checkLastInput(); });
@ -89,7 +89,7 @@ bool Manager::hasReplyingNotification() const {
return false;
}
void Manager::settingsChanged(const Notify::ChangeType &change) {
void Manager::settingsChanged(Notify::ChangeType change) {
if (change == Notify::ChangeType::Corner) {
auto startPosition = notificationStartPosition();
auto shiftDirection = notificationShiftDirection();

View file

@ -82,7 +82,7 @@ private:
void moveWidgets();
void changeNotificationHeight(Notification *widget, int newHeight);
void settingsChanged(const Notify::ChangeType &change);
void settingsChanged(Notify::ChangeType change);
bool hasReplyingNotification() const;

View file

@ -209,6 +209,7 @@
'<(src_loc)/core/single_timer.cpp',
'<(src_loc)/core/single_timer.h',
'<(src_loc)/core/stl_subset.h',
'<(src_loc)/core/type_traits.h',
'<(src_loc)/core/utils.cpp',
'<(src_loc)/core/utils.h',
'<(src_loc)/core/vector_of_moveable.h',