File indexing completed on 2024-05-12 16:27:15
0001 /* 0002 SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "playsoundwidget.h" 0008 #include "misc/messageattachmentdownloadandsavejob.h" 0009 #include "rocketchataccount.h" 0010 #include "ruqolaglobalconfig.h" 0011 0012 #include <KLocalizedString> 0013 #include <KMessageWidget> 0014 0015 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0016 #include <QAudioDevice> 0017 #endif 0018 #include <QComboBox> 0019 #include <QFontMetrics> 0020 #include <QHBoxLayout> 0021 #include <QLabel> 0022 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0023 #include <QMediaDevices> 0024 #endif 0025 #include <QPushButton> 0026 #include <QSlider> 0027 #include <QStyle> 0028 #include <QTime> 0029 #include <QToolButton> 0030 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0031 #include <QAudioOutput> 0032 #endif 0033 0034 PlaySoundWidget::PlaySoundWidget(RocketChatAccount *account, QWidget *parent) 0035 : QWidget(parent) 0036 , mMediaPlayer(new QMediaPlayer(this)) 0037 , mPlayButton(new QPushButton(this)) 0038 , mSoundButton(new QToolButton(this)) 0039 , mSoundSlider(new QSlider(Qt::Horizontal, this)) 0040 , mPositionSlider(new QSlider(Qt::Horizontal, this)) 0041 , mLabelDuration(new QLabel(this)) 0042 , mMessageWidget(new KMessageWidget(this)) 0043 , mLabelPercentSound(new QLabel(this)) 0044 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0045 , mAudioOutput(new QAudioOutput(this)) 0046 , mDeviceComboBox(new QComboBox(this)) 0047 #endif 0048 , mRocketChatAccount(account) 0049 { 0050 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0051 mMediaPlayer->setAudioOutput(mAudioOutput); 0052 mDeviceComboBox->setObjectName(QStringLiteral("mDeviceComboBox")); 0053 initializeAudioOutput(); 0054 #endif 0055 0056 auto mainLayout = new QVBoxLayout(this); 0057 mainLayout->setObjectName(QStringLiteral("mainLayout")); 0058 mainLayout->setContentsMargins({}); 0059 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0060 mainLayout->addWidget(mDeviceComboBox); 0061 #endif 0062 0063 auto playerLayout = new QHBoxLayout; 0064 playerLayout->setObjectName(QStringLiteral("playerLayout")); 0065 playerLayout->setContentsMargins({}); 0066 mainLayout->addLayout(playerLayout); 0067 mMessageWidget->setObjectName(QStringLiteral("mMessageWidget")); 0068 mainLayout->addWidget(mMessageWidget); 0069 mMessageWidget->setVisible(false); 0070 mMessageWidget->setCloseButtonVisible(false); 0071 mMessageWidget->setMessageType(KMessageWidget::Information); 0072 mMessageWidget->setWordWrap(true); 0073 mLabelDuration->setObjectName(QStringLiteral("mLabelDuration")); 0074 mLabelPercentSound->setObjectName(QStringLiteral("mLabelPercentSound")); 0075 0076 mLabelDuration->setTextFormat(Qt::PlainText); 0077 mLabelPercentSound->setTextFormat(Qt::PlainText); 0078 0079 mMediaPlayer->setObjectName(QStringLiteral("mMediaPlayer")); 0080 0081 mPositionSlider->setObjectName(QStringLiteral("mPositionSlider")); 0082 mPositionSlider->setRange(0, 100); 0083 mPositionSlider->setValue(100); 0084 connect(mPositionSlider, &QAbstractSlider::sliderMoved, this, &PlaySoundWidget::setPosition); 0085 0086 mSoundSlider->setObjectName(QStringLiteral("mSoundSlider")); 0087 mSoundSlider->setRange(0, 100); 0088 mSoundSlider->setValue(RuqolaGlobalConfig::self()->soundVolume()); 0089 mSoundSlider->setTickPosition(QSlider::TicksAbove); 0090 0091 connect(mSoundSlider, &QAbstractSlider::sliderMoved, this, &PlaySoundWidget::slotVolumeChanged); 0092 0093 connect(mMediaPlayer, &QMediaPlayer::positionChanged, this, &PlaySoundWidget::slotPositionChanged); 0094 connect(mMediaPlayer, &QMediaPlayer::durationChanged, this, &PlaySoundWidget::slotDurationChanged); 0095 0096 // Allow to change volume 0097 0098 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0099 connect(mMediaPlayer, &QMediaPlayer::stateChanged, this, &PlaySoundWidget::mediaStateChanged); 0100 #else 0101 connect(mMediaPlayer, &QMediaPlayer::playbackStateChanged, this, &PlaySoundWidget::mediaStateChanged); 0102 #endif 0103 mPlayButton->setObjectName(QStringLiteral("mPlayButton")); 0104 mPlayButton->setEnabled(false); 0105 mPlayButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); 0106 playerLayout->addWidget(mPlayButton); 0107 connect(mPlayButton, &QAbstractButton::clicked, this, &PlaySoundWidget::play); 0108 0109 mSoundButton->setCheckable(true); 0110 mSoundButton->setObjectName(QStringLiteral("mSoundButton")); 0111 mSoundButton->setIcon(QIcon::fromTheme(QStringLiteral("player-volume"))); 0112 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0113 connect(mSoundButton, &QToolButton::clicked, mMediaPlayer, &QMediaPlayer::setMuted); 0114 connect(mMediaPlayer, &QMediaPlayer::mutedChanged, this, &PlaySoundWidget::muteChanged); 0115 #else 0116 connect(mSoundButton, &QToolButton::clicked, mAudioOutput, &QAudioOutput::setMuted); 0117 connect(mAudioOutput, &QAudioOutput::mutedChanged, this, &PlaySoundWidget::muteChanged); 0118 #endif 0119 playerLayout->addWidget(mPositionSlider); 0120 0121 playerLayout->addWidget(mSoundButton); 0122 0123 playerLayout->addWidget(mLabelDuration); 0124 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0125 connect(mSoundSlider, &QAbstractSlider::valueChanged, mMediaPlayer, &QMediaPlayer::setVolume); 0126 #endif 0127 0128 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0129 connect(mMediaPlayer, qOverload<QMediaPlayer::Error>(&QMediaPlayer::error), this, &PlaySoundWidget::handleError); 0130 #else 0131 connect(mMediaPlayer, &QMediaPlayer::errorChanged, this, &PlaySoundWidget::handleError); 0132 #endif 0133 0134 playerLayout->addWidget(mSoundSlider); 0135 playerLayout->addWidget(mLabelPercentSound); 0136 0137 QFontMetrics f(font()); 0138 mLabelPercentSound->setFixedWidth(f.horizontalAdvance(QStringLiteral("MMM"))); 0139 slotVolumeChanged(mSoundSlider->value()); 0140 } 0141 0142 PlaySoundWidget::~PlaySoundWidget() 0143 { 0144 RuqolaGlobalConfig::self()->setSoundVolume(mSoundSlider->value()); 0145 RuqolaGlobalConfig::self()->save(); 0146 } 0147 0148 void PlaySoundWidget::initializeAudioOutput() 0149 { 0150 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0151 mDeviceComboBox->addItem(i18n("Default"), QVariant::fromValue(QAudioDevice())); 0152 for (const auto &deviceInfo : QMediaDevices::audioOutputs()) { 0153 mDeviceComboBox->addItem(deviceInfo.description(), QVariant::fromValue(deviceInfo)); 0154 } 0155 connect(mDeviceComboBox, &QComboBox::activated, this, &PlaySoundWidget::audioOutputChanged); 0156 #endif 0157 } 0158 0159 void PlaySoundWidget::audioOutputChanged(int index) 0160 { 0161 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0162 const auto device = mDeviceComboBox->itemData(index).value<QAudioDevice>(); 0163 mMediaPlayer->audioOutput()->setDevice(device); 0164 #endif 0165 } 0166 0167 void PlaySoundWidget::slotPositionChanged(qint64 progress) 0168 { 0169 if (!mPositionSlider->isSliderDown()) 0170 mPositionSlider->setValue(progress / 1000); 0171 0172 updateDurationInfo(progress / 1000); 0173 } 0174 0175 void PlaySoundWidget::updateDurationInfo(qint64 currentInfo) 0176 { 0177 QString tStr; 0178 if (currentInfo || mDuration) { 0179 const QTime currentTime((currentInfo / 3600) % 60, (currentInfo / 60) % 60, currentInfo % 60, (currentInfo * 1000) % 1000); 0180 const QTime totalTime((mDuration / 3600) % 60, (mDuration / 60) % 60, mDuration % 60, (mDuration * 1000) % 1000); 0181 QString format = QStringLiteral("mm:ss"); 0182 if (mDuration > 3600) 0183 format = QStringLiteral("hh:mm:ss"); 0184 tStr = currentTime.toString(format) + QStringLiteral(" / ") + totalTime.toString(format); 0185 } 0186 mLabelDuration->setText(tStr); 0187 } 0188 0189 void PlaySoundWidget::slotVolumeChanged(int position) 0190 { 0191 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0192 mMediaPlayer->setVolume(position); 0193 #else 0194 mAudioOutput->setVolume(position / 100.0); 0195 #endif 0196 mLabelPercentSound->setText(QStringLiteral("%1%").arg(position)); 0197 } 0198 0199 void PlaySoundWidget::slotDurationChanged(qint64 duration) 0200 { 0201 mDuration = duration / 1000; 0202 mPositionSlider->setMaximum(mDuration); 0203 } 0204 0205 void PlaySoundWidget::setPosition(int position) 0206 { 0207 mMediaPlayer->setPosition(position * 1000); 0208 } 0209 0210 void PlaySoundWidget::muteChanged(bool state) 0211 { 0212 mSoundButton->setIcon(state ? QIcon::fromTheme(QStringLiteral("player-volume-muted")) : QIcon::fromTheme(QStringLiteral("player-volume"))); 0213 } 0214 0215 QUrl PlaySoundWidget::audioUrl() const 0216 { 0217 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0218 // Code not used in qt5 :) 0219 return {}; 0220 #else 0221 return mMediaPlayer->source(); 0222 #endif 0223 } 0224 0225 void PlaySoundWidget::slotAttachmentFileDownloadDone(const QString &url) 0226 { 0227 const QUrl localUrl = QUrl::fromLocalFile(url); 0228 Q_EMIT updateTitle(localUrl); 0229 // setWindowFilePath(localUrl); 0230 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0231 mMediaPlayer->setMedia(localUrl); 0232 #else 0233 mMediaPlayer->setSource(localUrl); 0234 #endif 0235 mPlayButton->setEnabled(true); 0236 } 0237 0238 void PlaySoundWidget::setAudioPath(const QString &url) 0239 { 0240 if (mRocketChatAccount) { 0241 MessageAttachmentDownloadAndSaveJob::MessageAttachmentDownloadJobInfo info; 0242 info.attachmentType = MessageAttachmentDownloadAndSaveJob::AttachmentType::Sound; 0243 info.actionType = MessageAttachmentDownloadAndSaveJob::ActionType::DownloadOnly; 0244 info.needToDownloadAttachment = !mRocketChatAccount->attachmentIsInLocalCache(url); 0245 info.parentWidget = this; 0246 info.attachmentPath = url; 0247 auto job = new MessageAttachmentDownloadAndSaveJob(this); 0248 connect(job, &MessageAttachmentDownloadAndSaveJob::attachmentFileDownloadDone, this, &PlaySoundWidget::slotAttachmentFileDownloadDone); 0249 job->setRocketChatAccount(mRocketChatAccount); 0250 job->setInfo(info); 0251 job->start(); 0252 } else { 0253 slotAttachmentFileDownloadDone(url); 0254 } 0255 } 0256 0257 void PlaySoundWidget::play() 0258 { 0259 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0260 switch (mMediaPlayer->state()) { 0261 case QMediaPlayer::PlayingState: 0262 mMediaPlayer->pause(); 0263 break; 0264 default: 0265 mMediaPlayer->play(); 0266 break; 0267 } 0268 #else 0269 switch (mMediaPlayer->playbackState()) { 0270 case QMediaPlayer::PlayingState: 0271 mMediaPlayer->pause(); 0272 break; 0273 default: 0274 mMediaPlayer->play(); 0275 break; 0276 } 0277 #endif 0278 } 0279 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0280 void PlaySoundWidget::mediaStateChanged(QMediaPlayer::State state) 0281 #else 0282 void PlaySoundWidget::mediaStateChanged(QMediaPlayer::PlaybackState state) 0283 #endif 0284 { 0285 switch (state) { 0286 case QMediaPlayer::PlayingState: 0287 mPlayButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause)); 0288 break; 0289 default: 0290 mPlayButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); 0291 break; 0292 } 0293 } 0294 0295 void PlaySoundWidget::handleError() 0296 { 0297 mPlayButton->setEnabled(false); 0298 const QString errorString = mMediaPlayer->errorString(); 0299 QString message = i18n("Error: "); // i18n ? 0300 if (errorString.isEmpty()) { 0301 message += QStringLiteral(" #") + QString::number(int(mMediaPlayer->error())); 0302 } else { 0303 message += errorString; 0304 } 0305 mMessageWidget->setText(message); 0306 mMessageWidget->animatedShow(); 0307 } 0308 0309 #include "moc_playsoundwidget.cpp"