diff --git a/plugins/media/CMakeLists.txt b/plugins/media/CMakeLists.txt new file mode 100644 index 000000000..792279e08 --- /dev/null +++ b/plugins/media/CMakeLists.txt @@ -0,0 +1,51 @@ + +set(PLUGIN_NAME "media") + +project(${PLUGIN_NAME}) + +generation_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/xml ${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/generation_dbus_interface) + +# Sources files +file(GLOB_RECURSE SRCS "*.h" "*.cpp" + "../../widgets/*.h" + "../../widgets/*.cpp" + "../../frame/util/imageutil.h" + "../../frame/util/imageutil.cpp" + "../../frame/util/statebutton.h" + "../../frame/util/statebutton.cpp" + "../../frame/util/horizontalseperator.h" + "../../frame/util/horizontalseperator.cpp" + "../../frame/qtdbusextended/*.h" + "../../frame/qtdbusextended/*.cpp") + +find_package(PkgConfig REQUIRED) +find_package(Qt5Widgets REQUIRED) +find_package(Qt5Svg REQUIRED) +find_package(Qt5DBus REQUIRED) +find_package(DtkWidget REQUIRED) + +pkg_check_modules(XCB_EWMH REQUIRED xcb-ewmh x11 xcursor) +pkg_check_modules(QGSettings REQUIRED gsettings-qt) + +add_definitions("${QT_DEFINITIONS} -DQT_PLUGIN") +add_library(${PLUGIN_NAME} SHARED ${SRCS}) +set_target_properties(${PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../quick-trays) +target_include_directories(${PLUGIN_NAME} PUBLIC ${DtkWidget_INCLUDE_DIRS} + ${QGSettings_INCLUDE_DIRS} + ../../interfaces + ../../widgets + ../../frame + ../../frame/qtdbusextended + ./dbusinterface/generation_dbus_interface + componments) + +target_link_libraries(${PLUGIN_NAME} PRIVATE + ${XCB_EWMH_LIBRARIES} + ${DtkWidget_LIBRARIES} + ${QGSettings_LIBRARIES} + ${Qt5DBus_LIBRARIES} + ${Qt5Widgets_LIBRARIES} + ${Qt5Svg_LIBRARIES} +) + +install(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION lib/dde-dock/plugins/quick-trays) diff --git a/plugins/media/media.json b/plugins/media/media.json new file mode 100644 index 000000000..bec81f0da --- /dev/null +++ b/plugins/media/media.json @@ -0,0 +1,3 @@ +{ + "api": "2.0.0" +} diff --git a/plugins/media/mediaplayermodel.cpp b/plugins/media/mediaplayermodel.cpp new file mode 100644 index 000000000..786e43508 --- /dev/null +++ b/plugins/media/mediaplayermodel.cpp @@ -0,0 +1,252 @@ +#include "mediaplayermodel.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MediaPlayerModel::MediaPlayerModel(QObject *parent) + : QObject(parent) + , m_isActived(false) + , m_mediaInter(nullptr) +{ + initMediaPlayer(); +} + +MediaPlayerModel::~MediaPlayerModel() +{ +} + +bool MediaPlayerModel::isActived() +{ + return m_isActived; +} + +bool MediaPlayerModel::canGoNext() +{ + return m_mediaInter ? m_mediaInter->canGoNext() : false; +} + +bool MediaPlayerModel::canGoPrevious() +{ + return m_mediaInter ? m_mediaInter->canGoPrevious() : false; +} + +bool MediaPlayerModel::canPause() +{ + return m_mediaInter ? m_mediaInter->canPause() : false; +} + +MediaPlayerModel::PlayStatus MediaPlayerModel::status() +{ + if (!m_isActived || !m_mediaInter) + return PlayStatus::Stop; + + return convertStatus(m_mediaInter->playbackStatus()); +} + +const QString MediaPlayerModel::name() +{ + if (m_mediaInter) { + Dict data = m_mediaInter->metadata(); + return data["xesam:title"].toString(); + } + + return QString(); +} + +const QString MediaPlayerModel::iconUrl() +{ + if (m_mediaInter) { + Dict data = m_mediaInter->metadata(); + return data["mpris:artUrl"].toString(); + } + + return QString(); +} + +const QString MediaPlayerModel::album() +{ + if (m_mediaInter) { + Dict data = m_mediaInter->metadata(); + return data["xesam:album"].toString(); + } + + return QString(); +} + +const QString MediaPlayerModel::artist() +{ + if (m_mediaInter) { + Dict data = m_mediaInter->metadata(); + return data["xesam:artist"].toString(); + } + + return QString(); +} + +void MediaPlayerModel::setStatus(const MediaPlayerModel::PlayStatus &stat) +{ + if (!m_mediaInter) + return; + + switch (stat) { + case MediaPlayerModel::PlayStatus::Play: { + m_mediaInter->Play(); + break; + } + case MediaPlayerModel::PlayStatus::Stop: { + m_mediaInter->Stop(); + break; + } + case MediaPlayerModel::PlayStatus::Pause: { + m_mediaInter->Pause(); + break; + } + default: break; + } +} + +void MediaPlayerModel::playNext() +{ + if (m_mediaInter) + m_mediaInter->Next(); +} + +void MediaPlayerModel::initMediaPlayer() +{ + QDBusInterface dbusInter("org.freedesktop.DBus", "/", "org.freedesktop.DBus", QDBusConnection::sessionBus(), this); + QDBusPendingCall call = dbusInter.asyncCall("ListNames"); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + connect(watcher, &QDBusPendingCallWatcher::finished, [ = ] { + m_serviceName.clear(); + if (call.isError()) + return; + + QDBusReply reply = call.reply(); + const QStringList &serviceList = reply.value(); + + for (const QString &serv : serviceList) { + if (!serv.startsWith("org.mpris.MediaPlayer2")) + continue; + + QDBusInterface serviceInterface(serv, "/org/mpris/MediaPlayer2", + "org.mpris.MediaPlayer2.Player", QDBusConnection::sessionBus(), this); + // 如果开启了谷歌浏览器的后台服务(org.mpris.MediaPlayer2.chromium.instance17352) + // 也符合名称要求,但是它不是音乐服务,此时需要判断是否存在这个属性 + QVariant v = serviceInterface.property("CanPlay"); + if (!v.isValid() || !v.value()) + continue; + + m_serviceName = serv; + break; + } + + if (!m_serviceName.isEmpty()) { + m_isActived = true; + + m_mediaInter = new MediaPlayerInterface(m_serviceName, "/org/mpris/MediaPlayer2", QDBusConnection::sessionBus(), this); + connect(m_mediaInter, &MediaPlayerInterface::PlaybackStatusChanged, this, [ this ] { + Q_EMIT statusChanged(convertStatus(m_mediaInter->playbackStatus())); + }); + connect(m_mediaInter, &MediaPlayerInterface::MetadataChanged, this, &MediaPlayerModel::metadataChanged); + Dict v = m_mediaInter->metadata(); + m_name = v.value("xesam:title").toString(); + m_icon = v.value("mpris:artUrl").toString(); + m_album = v.value("xesam:album").toString(); + m_artist = v.value("xesam:artist").toString(); + Q_EMIT startStop(m_isActived); + return; + } + + QDBusConnectionInterface *dbusInterface = QDBusConnection::sessionBus().interface(); + connect(dbusInterface, &QDBusConnectionInterface::serviceOwnerChanged, this, + [ = ](const QString &name, const QString &, const QString &newOwner) { + if (name.startsWith("org.mpris.MediaPlayer2")) { + // 启动了音乐播放 + m_isActived = !newOwner.isEmpty(); + if (m_isActived) { + m_serviceName = name; + m_mediaInter = new MediaPlayerInterface(m_serviceName, "/org/mpris/MediaPlayer2", QDBusConnection::sessionBus(), this); + connect(m_mediaInter, &MediaPlayerInterface::PlaybackStatusChanged, this, [ this ] { + Q_EMIT statusChanged(convertStatus(m_mediaInter->playbackStatus())); + }); + connect(m_mediaInter, &MediaPlayerInterface::MetadataChanged, this, &MediaPlayerModel::metadataChanged); + Dict v = m_mediaInter->metadata(); + m_name = v.value("xesam:title").toString(); + m_icon = v.value("mpris:artUrl").toString(); + m_album = v.value("xesam:album").toString(); + m_artist = v.value("xesam:artist").toString(); + } else { + if (!m_serviceName.isEmpty()) { + delete m_mediaInter; + m_mediaInter = nullptr; + } + m_serviceName.clear(); + } + Q_EMIT startStop(m_isActived); + } + }); + connect(dbusInterface, &QDBusConnectionInterface::serviceUnregistered, this, + [ = ](const QString &service) { + if (service.startsWith("org.mpris.MediaPlayer2")) { + // 启动了音乐播放 + m_serviceName.clear(); + m_isActived = false; + Q_EMIT startStop(m_isActived); + } + }); + }); + connect(watcher, &QDBusPendingCallWatcher::finished, watcher, &QDBusPendingCallWatcher::deleteLater); +} + +MediaPlayerModel::PlayStatus MediaPlayerModel::convertStatus(const QString &stat) +{ + if (stat == "Paused") + return PlayStatus::Pause; + if (stat == "Playing") + return PlayStatus::Play; + if (stat == "Stopped") + return PlayStatus::Stop; + + return PlayStatus::Unknow; +} + +MediaPlayerInterface::MediaPlayerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, "org.mpris.MediaPlayer2.Player", connection, parent) +{ + QDBusConnection::sessionBus().connect(this->service(), this->path(), "org.freedesktop.DBus.Properties", "PropertiesChanged", "sa{sv}as", this, SLOT(onPropertyChanged(const QDBusMessage &))); +} + +MediaPlayerInterface::~MediaPlayerInterface() +{ + QDBusConnection::sessionBus().disconnect(this->service(), this->path(), "org.freedesktop.DBus.Properties", "PropertiesChanged", "sa{sv}as", this, SLOT(onPropertyChanged(const QDBusMessage &))); +} + +void MediaPlayerInterface::onPropertyChanged(const QDBusMessage &msg) +{ + QList arguments = msg.arguments(); + if (3 != arguments.count()) + return; + + QString interfaceName = msg.arguments().at(0).toString(); + if (interfaceName !="org.mpris.MediaPlayer2.Player") + return; + + QVariantMap changedProps = qdbus_cast(arguments.at(1).value()); + QStringList keys = changedProps.keys(); + foreach(const QString &prop, keys) { + const QMetaObject* self = metaObject(); + for (int i = self->propertyOffset(); i < self->propertyCount(); ++i) { + QMetaProperty p = self->property(i); + if (p.name() == prop) { + Q_EMIT p.notifySignal().invoke(this); + } + } + } +} diff --git a/plugins/media/mediaplayermodel.h b/plugins/media/mediaplayermodel.h new file mode 100644 index 000000000..ce560d8a6 --- /dev/null +++ b/plugins/media/mediaplayermodel.h @@ -0,0 +1,124 @@ +#ifndef MEDIAPLAYERMODEL_H +#define MEDIAPLAYERMODEL_H + +#include +#include +#include + +typedef QMap Dict; +Q_DECLARE_METATYPE(Dict) + +class QDBusMessage; +class QDBusConnection; +class MediaPlayerInterface; + +class MediaPlayerModel : public QObject +{ + Q_OBJECT + +public: + enum PlayStatus { + Unknow = 0, + Play, + Pause, + Stop + }; + +public: + explicit MediaPlayerModel(QObject *parent = nullptr); + ~MediaPlayerModel(); + + bool isActived(); + bool canGoNext(); + bool canGoPrevious(); + bool canPause(); + + PlayStatus status(); + const QString name(); + const QString iconUrl(); + const QString album(); + const QString artist(); + + void setStatus(const PlayStatus &stat); + void playNext(); + +Q_SIGNALS: + void startStop(bool); + void statusChanged(const PlayStatus &); + void metadataChanged(); + +private: + void initMediaPlayer(); + PlayStatus convertStatus(const QString &stat); + +private: + bool m_isActived; + QString m_serviceName; + QString m_name; + QString m_icon; + QString m_album; + QString m_artist; + MediaPlayerInterface *m_mediaInter; +}; + +class MediaPlayerInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + MediaPlayerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr); + ~MediaPlayerInterface(); + +public: + inline QDBusPendingReply<> Play() { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Play"), argumentList); + } + + inline QDBusPendingReply<> Stop() { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Stop"), argumentList); + } + + inline QDBusPendingReply<> Pause() { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Pause"), argumentList); + } + + inline QDBusPendingReply<> Next() { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Next"), argumentList); + } + + Q_PROPERTY(Dict Metadata READ metadata NOTIFY MetadataChanged) + inline Dict metadata() const + { return qvariant_cast(property("Metadata")); } + + Q_PROPERTY(bool CanGoNext READ canGoNext NOTIFY CanGoNextChanged) + inline bool canGoNext() const + { return qvariant_cast< bool >(property("CanGoNext")); } + + Q_PROPERTY(bool CanGoPrevious READ canGoPrevious NOTIFY CanGoPreviousChanged) + inline bool canGoPrevious() const + { return qvariant_cast< bool >(property("CanGoPrevious")); } + + Q_PROPERTY(bool CanPause READ canPause NOTIFY CanPauseChanged) + inline bool canPause() const + { return qvariant_cast< bool >(property("CanPause")); } + + Q_PROPERTY(QString PlaybackStatus READ playbackStatus NOTIFY PlaybackStatusChanged) + inline QString playbackStatus() const + { return qvariant_cast< QString >(property("PlaybackStatus")); } + +Q_SIGNALS: + void MetadataChanged(); + void CanGoNextChanged(); + void CanGoPreviousChanged(); + void CanPauseChanged(); + void PlaybackStatusChanged(); + +private Q_SLOTS: + void onPropertyChanged(const QDBusMessage &msg); +}; + +#endif // MEDIAPLAYERLISTENER_H diff --git a/plugins/media/mediaplugin.cpp b/plugins/media/mediaplugin.cpp new file mode 100644 index 000000000..4a721302c --- /dev/null +++ b/plugins/media/mediaplugin.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd. + * + * Author: donghualin + * + * Maintainer: donghualin + * + * This program 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 + * any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mediaplugin.h" +#include "mediawidget.h" +#include "mediaplayermodel.h" + +MediaPlugin::MediaPlugin(QObject *parent) + : QObject(parent) + , m_mediaWidget(nullptr) + , m_model(nullptr) +{ +} + +const QString MediaPlugin::pluginName() const +{ + return "media"; +} + +const QString MediaPlugin::pluginDisplayName() const +{ + return tr("media"); +} + +void MediaPlugin::init(PluginProxyInterface *proxyInter) +{ + if (m_proxyInter == proxyInter) + return; + + m_proxyInter = proxyInter; + + m_model.reset(new MediaPlayerModel); + m_mediaWidget.reset(new MediaWidget(m_model.data())); + m_mediaWidget->setFixedHeight(60); + m_mediaWidget->setVisible(m_model->isActived()); + + if (m_model->isActived()) + m_proxyInter->itemAdded(this, pluginName()); + + connect(m_model.data(), &MediaPlayerModel::startStop, this, [ this ](bool visible) { + if (visible) + m_proxyInter->itemAdded(this, pluginName()); + else + m_proxyInter->itemRemoved(this, pluginName()); + }); +} + +QWidget *MediaPlugin::itemWidget(const QString &itemKey) +{ + if (itemKey == QUICK_ITEM_KEY) + return m_mediaWidget.data(); + + return nullptr; +} + +QWidget *MediaPlugin::itemTipsWidget(const QString &itemKey) +{ + return nullptr; +} + +QWidget *MediaPlugin::itemPopupApplet(const QString &itemKey) +{ + return nullptr; +} + +PluginFlags MediaPlugin::flags() const +{ + return PluginFlag::Type_Common | PluginFlag::Quick_Full; +} diff --git a/plugins/media/mediaplugin.h b/plugins/media/mediaplugin.h new file mode 100644 index 000000000..ec3bfeb77 --- /dev/null +++ b/plugins/media/mediaplugin.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. + * + * Author: donghualin + * + * Maintainer: donghualin + * + * This program 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 + * any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MEDIAPLUGIN_H +#define MEDIAPLUGIN_H + +#include "pluginsiteminterface.h" + +namespace Dock{ +class TipsWidget; +} +class MediaWidget; +class MediaPlayerModel; + +class MediaPlugin : public QObject, PluginsItemInterface +{ + Q_OBJECT + Q_INTERFACES(PluginsItemInterface) + Q_PLUGIN_METADATA(IID "com.deepin.dock.PluginsItemInterface" FILE "media.json") + +public: + explicit MediaPlugin(QObject *parent = nullptr); + + const QString pluginName() const override; + const QString pluginDisplayName() const override; + void init(PluginProxyInterface *proxyInter) override; + + QWidget *itemWidget(const QString &itemKey) override; + QWidget *itemTipsWidget(const QString &itemKey) override; + QWidget *itemPopupApplet(const QString &itemKey) override; + + PluginFlags flags() const override; + +private: + QScopedPointer m_mediaWidget; + QScopedPointer m_model; +}; + +#endif // DATETIMEPLUGIN_H diff --git a/plugins/media/mediawidget.cpp b/plugins/media/mediawidget.cpp new file mode 100644 index 000000000..b392f3a2a --- /dev/null +++ b/plugins/media/mediawidget.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. + * + * Author: donghualin + * + * Maintainer: donghualin + * + * This program 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 + * any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "mediawidget.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +DWIDGET_USE_NAMESPACE + +#define PAUSEHEIGHT 21 +#define PLAYHEIGHT 18 + +MediaWidget::MediaWidget(MediaPlayerModel *model, QWidget *parent) + : QWidget(parent) + , m_model(model) + , m_musicIcon(new QLabel(this)) + , m_musicName(new QLabel(this)) + , m_musicSinger(new QLabel(this)) + , m_pausePlayButton(new MusicButton(this)) + , m_nextButton(new MusicButton(this)) +{ + initUi(); + initConnection(); +} + +MediaWidget::~MediaWidget() +{ +} + +void MediaWidget::statusChanged(const MediaPlayerModel::PlayStatus &newStatus) +{ + switch (newStatus) { + case MediaPlayerModel::PlayStatus::Play: { + m_pausePlayButton->setButtonType(MusicButton::ButtonType::Pause); + break; + } + case MediaPlayerModel::PlayStatus::Stop: + case MediaPlayerModel::PlayStatus::Pause: { + m_pausePlayButton->setButtonType(MusicButton::ButtonType::Playing); + break; + } + default: break; + } +} + +void MediaWidget::onPlayClicked() +{ + // 设置当前的播放状态 + if (m_model->status() == MediaPlayerModel::PlayStatus::Play) + m_model->setStatus(MediaPlayerModel::PlayStatus::Pause); + else + m_model->setStatus(MediaPlayerModel::PlayStatus::Play); +} + +void MediaWidget::onNext() +{ + // 播放下一曲 + m_model->playNext(); +} + +void MediaWidget::initUi() +{ + m_pausePlayButton->setFixedWidth(20); + m_nextButton->setFixedWidth(20); + + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->setContentsMargins(20, 0, 20, 0); + mainLayout->addWidget(m_musicIcon); + + QWidget *infoWidget = new QWidget(this); + QVBoxLayout *infoLayout = new QVBoxLayout(infoWidget); + infoLayout->addWidget(m_musicName); + infoLayout->addWidget(m_musicSinger); + mainLayout->addWidget(infoWidget); + mainLayout->addStretch(); + mainLayout->addWidget(m_pausePlayButton); + mainLayout->addSpacing(25); + mainLayout->addWidget(m_nextButton); + + m_musicIcon->setFixedSize(32, 32); + m_musicName->setFont(DFontSizeManager::instance()->t8()); + m_musicSinger->setFont(DFontSizeManager::instance()->t10()); +} + +void MediaWidget::initConnection() +{ + connect(m_model, &MediaPlayerModel::startStop, this, [ this ](bool startOrStop) { + m_nextButton->setEnabled(m_model->canGoNext()); + onUpdateMediaInfo(); + statusChanged(m_model->status()); + }); + connect(m_model, &MediaPlayerModel::metadataChanged, this, &MediaWidget::onUpdateMediaInfo); + connect(m_model, &MediaPlayerModel::statusChanged, this, &MediaWidget::statusChanged); + connect(m_pausePlayButton, &MusicButton::clicked, this, &MediaWidget::onPlayClicked); + connect(m_nextButton, &MusicButton::clicked, this, &MediaWidget::onNext); + + m_pausePlayButton->setButtonType(m_model->status() == MediaPlayerModel::PlayStatus::Play ? + MusicButton::ButtonType::Pause : MusicButton::ButtonType::Playing); + m_nextButton->setButtonType(MusicButton::ButtonType::Next); +} + +void MediaWidget::onUpdateMediaInfo() +{ + m_musicName->setText(m_model->name()); + QString file = m_model->iconUrl(); + if (file.startsWith("file:///")) + file.replace("file:///", "/"); + m_musicIcon->setPixmap(QPixmap(file).scaled(m_musicIcon->size())); + m_musicSinger->setText(m_model->artist()); +} + +/** + * @brief 音乐播放的相关按钮 + * @param parent + */ + +MusicButton::MusicButton(QWidget *parent) + : QWidget(parent) +{ + installEventFilter(this); +} + +MusicButton::~MusicButton() +{ +} + +int MusicButton::getIconHeight() const +{ + switch (m_buttonType) { + case ButtonType::Pause: + return PAUSEHEIGHT; + case ButtonType::Next: + case ButtonType::Playing: + return PLAYHEIGHT; + } + + return PLAYHEIGHT; +} + +void MusicButton::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + +#define ICOMMARGIN 6 +#define ICONSPACE 2 + + int ctrlHeight = getIconHeight(); + + int width = this->width(); + int height = this->height(); + int startX = 2; + int startY = (height - ctrlHeight) / 2; + QPainter painter(this); + painter.save(); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(Qt::black); + painter.setBrush(Qt::black); + if (m_buttonType == ButtonType::Pause) { + painter.drawRect(QRect(startX, startY, ICOMMARGIN, ctrlHeight)); + painter.drawRect(QRect(width - ICOMMARGIN - ICONSPACE, startY, ICOMMARGIN, ctrlHeight)); + } else { + QPainterPath trianglePath; + trianglePath.moveTo(startX, startY); + trianglePath.lineTo(width - ICOMMARGIN, height / 2); + trianglePath.lineTo(startX, startY + ctrlHeight); + trianglePath.lineTo(startX, startY); + painter.drawPath(trianglePath); + if (m_buttonType == ButtonType::Next) + painter.drawRect(width - ICOMMARGIN, startY, 2, ctrlHeight); + } + painter.restore(); +} + +void MusicButton::mouseReleaseEvent(QMouseEvent *event) +{ + Q_UNUSED(event); + Q_EMIT clicked(); +} diff --git a/plugins/media/mediawidget.h b/plugins/media/mediawidget.h new file mode 100644 index 000000000..cad32072b --- /dev/null +++ b/plugins/media/mediawidget.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. + * + * Author: donghualin + * + * Maintainer: donghualin + * + * This program 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 + * any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef MEDIAWIDGET_H +#define MEDIAWIDGET_H + +#include "mediaplayermodel.h" + +#include + +class QLabel; +class MusicButton; +class MediaPlayerModel; + +DWIDGET_USE_NAMESPACE + +class MediaWidget : public QWidget +{ + Q_OBJECT + +public: + explicit MediaWidget(MediaPlayerModel *model, QWidget *parent = nullptr); + ~MediaWidget() override; + +private Q_SLOTS: + void statusChanged(const MediaPlayerModel::PlayStatus &newStatus); + void onPlayClicked(); + void onNext(); + void onUpdateMediaInfo(); + +private: + void initUi(); + void initConnection(); + +private: + MediaPlayerModel *m_model; + QLabel *m_musicIcon; + QLabel *m_musicName; + QLabel *m_musicSinger; + MusicButton *m_pausePlayButton; + MusicButton *m_nextButton; +}; + +// 音乐播放按钮 +class MusicButton : public QWidget +{ + Q_OBJECT + +Q_SIGNALS: + void clicked(); + +public: + enum ButtonType { Playing = 0, Pause, Next }; + +public: + MusicButton(QWidget *parent = Q_NULLPTR); + ~MusicButton() override; + + inline void setButtonType(const ButtonType &bt) { + m_buttonType = bt; + update(); + } + +protected: + void paintEvent(QPaintEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + +private: + int getIconHeight() const; + +private: + ButtonType m_buttonType; +}; + +#endif // MEDIAWIDGER_H