mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-11 08:48:14 +00:00
Playlist appearance added to the new media player.
Also itemRemoved() now is fired as a global observable.
This commit is contained in:
parent
4f0cff5467
commit
31a847fb9d
BIN
Telegram/Resources/icons/playlist_shadow.png
Normal file
BIN
Telegram/Resources/icons/playlist_shadow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 B |
BIN
Telegram/Resources/icons/playlist_shadow@2x.png
Normal file
BIN
Telegram/Resources/icons/playlist_shadow@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 91 B |
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
102
Telegram/SourceFiles/core/type_traits.h
Normal file
102
Telegram/SourceFiles/core/type_traits.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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 ®ion, 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 {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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 ¶m
|
||||
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 ¶m
|
||||
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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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 }};
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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 };
|
||||
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user