File indexing completed on 2024-05-19 05:04:05
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 #include <QAudioDevice> 0016 #include <QAudioOutput> 0017 #include <QComboBox> 0018 #include <QFontMetrics> 0019 #include <QHBoxLayout> 0020 #include <QLabel> 0021 #include <QMediaDevices> 0022 #include <QPushButton> 0023 #include <QSlider> 0024 #include <QStyle> 0025 #include <QTime> 0026 #include <QToolButton> 0027 0028 PlaySoundWidget::PlaySoundWidget(RocketChatAccount *account, QWidget *parent) 0029 : QWidget(parent) 0030 , mMediaPlayer(new QMediaPlayer(this)) 0031 , mPlayButton(new QPushButton(this)) 0032 , mSoundButton(new QToolButton(this)) 0033 , mSoundSlider(new QSlider(Qt::Horizontal, this)) 0034 , mPositionSlider(new QSlider(Qt::Horizontal, this)) 0035 , mLabelDuration(new QLabel(this)) 0036 , mMessageWidget(new KMessageWidget(this)) 0037 , mLabelPercentSound(new QLabel(this)) 0038 , mAudioOutput(new QAudioOutput(this)) 0039 , mDeviceComboBox(new QComboBox(this)) 0040 , mRocketChatAccount(account) 0041 { 0042 mMediaPlayer->setAudioOutput(mAudioOutput); 0043 mDeviceComboBox->setObjectName(QStringLiteral("mDeviceComboBox")); 0044 initializeAudioOutput(); 0045 0046 auto mainLayout = new QVBoxLayout(this); 0047 mainLayout->setObjectName(QStringLiteral("mainLayout")); 0048 mainLayout->setContentsMargins({}); 0049 mainLayout->addWidget(mDeviceComboBox); 0050 0051 auto playerLayout = new QHBoxLayout; 0052 playerLayout->setObjectName(QStringLiteral("playerLayout")); 0053 playerLayout->setContentsMargins({}); 0054 mainLayout->addLayout(playerLayout); 0055 mMessageWidget->setObjectName(QStringLiteral("mMessageWidget")); 0056 mainLayout->addWidget(mMessageWidget); 0057 mMessageWidget->setVisible(false); 0058 mMessageWidget->setCloseButtonVisible(false); 0059 mMessageWidget->setMessageType(KMessageWidget::Information); 0060 mMessageWidget->setWordWrap(true); 0061 mLabelDuration->setObjectName(QStringLiteral("mLabelDuration")); 0062 mLabelPercentSound->setObjectName(QStringLiteral("mLabelPercentSound")); 0063 0064 mLabelDuration->setTextFormat(Qt::PlainText); 0065 mLabelPercentSound->setTextFormat(Qt::PlainText); 0066 0067 mMediaPlayer->setObjectName(QStringLiteral("mMediaPlayer")); 0068 0069 mPositionSlider->setObjectName(QStringLiteral("mPositionSlider")); 0070 mPositionSlider->setRange(0, 100); 0071 mPositionSlider->setValue(100); 0072 connect(mPositionSlider, &QAbstractSlider::sliderMoved, this, &PlaySoundWidget::setPosition); 0073 0074 mSoundSlider->setObjectName(QStringLiteral("mSoundSlider")); 0075 mSoundSlider->setRange(0, 100); 0076 mSoundSlider->setValue(RuqolaGlobalConfig::self()->soundVolume()); 0077 mSoundSlider->setTickPosition(QSlider::TicksAbove); 0078 0079 connect(mSoundSlider, &QAbstractSlider::sliderMoved, this, &PlaySoundWidget::slotVolumeChanged); 0080 0081 connect(mMediaPlayer, &QMediaPlayer::positionChanged, this, &PlaySoundWidget::slotPositionChanged); 0082 connect(mMediaPlayer, &QMediaPlayer::durationChanged, this, &PlaySoundWidget::slotDurationChanged); 0083 0084 // Allow to change volume 0085 0086 connect(mMediaPlayer, &QMediaPlayer::playbackStateChanged, this, &PlaySoundWidget::mediaStateChanged); 0087 mPlayButton->setObjectName(QStringLiteral("mPlayButton")); 0088 mPlayButton->setEnabled(false); 0089 mPlayButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); 0090 playerLayout->addWidget(mPlayButton); 0091 connect(mPlayButton, &QAbstractButton::clicked, this, &PlaySoundWidget::play); 0092 0093 mSoundButton->setCheckable(true); 0094 mSoundButton->setObjectName(QStringLiteral("mSoundButton")); 0095 mSoundButton->setIcon(QIcon::fromTheme(QStringLiteral("player-volume"))); 0096 connect(mSoundButton, &QToolButton::clicked, mAudioOutput, &QAudioOutput::setMuted); 0097 connect(mAudioOutput, &QAudioOutput::mutedChanged, this, &PlaySoundWidget::muteChanged); 0098 playerLayout->addWidget(mPositionSlider); 0099 0100 playerLayout->addWidget(mSoundButton); 0101 0102 playerLayout->addWidget(mLabelDuration); 0103 0104 connect(mMediaPlayer, &QMediaPlayer::errorChanged, this, &PlaySoundWidget::handleError); 0105 0106 playerLayout->addWidget(mSoundSlider); 0107 playerLayout->addWidget(mLabelPercentSound); 0108 0109 QFontMetrics f(font()); 0110 mLabelPercentSound->setFixedWidth(f.horizontalAdvance(QStringLiteral("MMM"))); 0111 slotVolumeChanged(mSoundSlider->value()); 0112 } 0113 0114 PlaySoundWidget::~PlaySoundWidget() 0115 { 0116 RuqolaGlobalConfig::self()->setSoundVolume(mSoundSlider->value()); 0117 RuqolaGlobalConfig::self()->save(); 0118 } 0119 0120 void PlaySoundWidget::initializeAudioOutput() 0121 { 0122 mDeviceComboBox->addItem(i18n("Default"), QVariant::fromValue(QAudioDevice())); 0123 for (const auto &deviceInfo : QMediaDevices::audioOutputs()) { 0124 mDeviceComboBox->addItem(deviceInfo.description(), QVariant::fromValue(deviceInfo)); 0125 } 0126 connect(mDeviceComboBox, &QComboBox::activated, this, &PlaySoundWidget::audioOutputChanged); 0127 } 0128 0129 void PlaySoundWidget::audioOutputChanged(int index) 0130 { 0131 const auto device = mDeviceComboBox->itemData(index).value<QAudioDevice>(); 0132 mMediaPlayer->audioOutput()->setDevice(device); 0133 } 0134 0135 void PlaySoundWidget::slotPositionChanged(qint64 progress) 0136 { 0137 if (!mPositionSlider->isSliderDown()) 0138 mPositionSlider->setValue(progress / 1000); 0139 0140 updateDurationInfo(progress / 1000); 0141 } 0142 0143 void PlaySoundWidget::updateDurationInfo(qint64 currentInfo) 0144 { 0145 QString tStr; 0146 if (currentInfo || mDuration) { 0147 const QTime currentTime((currentInfo / 3600) % 60, (currentInfo / 60) % 60, currentInfo % 60, (currentInfo * 1000) % 1000); 0148 const QTime totalTime((mDuration / 3600) % 60, (mDuration / 60) % 60, mDuration % 60, (mDuration * 1000) % 1000); 0149 QString format = QStringLiteral("mm:ss"); 0150 if (mDuration > 3600) 0151 format = QStringLiteral("hh:mm:ss"); 0152 tStr = currentTime.toString(format) + QStringLiteral(" / ") + totalTime.toString(format); 0153 } 0154 mLabelDuration->setText(tStr); 0155 } 0156 0157 void PlaySoundWidget::slotVolumeChanged(int position) 0158 { 0159 mAudioOutput->setVolume(position / 100.0); 0160 mLabelPercentSound->setText(QStringLiteral("%1%").arg(position)); 0161 } 0162 0163 void PlaySoundWidget::slotDurationChanged(qint64 duration) 0164 { 0165 mDuration = duration / 1000; 0166 mPositionSlider->setMaximum(mDuration); 0167 } 0168 0169 void PlaySoundWidget::setPosition(int position) 0170 { 0171 mMediaPlayer->setPosition(position * 1000); 0172 } 0173 0174 void PlaySoundWidget::muteChanged(bool state) 0175 { 0176 mSoundButton->setIcon(state ? QIcon::fromTheme(QStringLiteral("player-volume-muted")) : QIcon::fromTheme(QStringLiteral("player-volume"))); 0177 } 0178 0179 QUrl PlaySoundWidget::audioUrl() const 0180 { 0181 return mMediaPlayer->source(); 0182 } 0183 0184 void PlaySoundWidget::slotAttachmentFileDownloadDone(const QString &url) 0185 { 0186 const QUrl localUrl = QUrl::fromLocalFile(url); 0187 Q_EMIT updateTitle(localUrl); 0188 // setWindowFilePath(localUrl); 0189 mMediaPlayer->setSource(localUrl); 0190 mPlayButton->setEnabled(true); 0191 } 0192 0193 void PlaySoundWidget::setAudioPath(const QString &url) 0194 { 0195 if (mRocketChatAccount) { 0196 MessageAttachmentDownloadAndSaveJob::MessageAttachmentDownloadJobInfo info; 0197 info.attachmentType = MessageAttachmentDownloadAndSaveJob::AttachmentType::Sound; 0198 info.actionType = MessageAttachmentDownloadAndSaveJob::ActionType::DownloadOnly; 0199 info.needToDownloadAttachment = !mRocketChatAccount->attachmentIsInLocalCache(url); 0200 info.parentWidget = this; 0201 info.attachmentPath = url; 0202 auto job = new MessageAttachmentDownloadAndSaveJob(this); 0203 connect(job, &MessageAttachmentDownloadAndSaveJob::attachmentFileDownloadDone, this, &PlaySoundWidget::slotAttachmentFileDownloadDone); 0204 job->setRocketChatAccount(mRocketChatAccount); 0205 job->setInfo(info); 0206 job->start(); 0207 } else { 0208 slotAttachmentFileDownloadDone(url); 0209 } 0210 } 0211 0212 void PlaySoundWidget::play() 0213 { 0214 switch (mMediaPlayer->playbackState()) { 0215 case QMediaPlayer::PlayingState: 0216 mMediaPlayer->pause(); 0217 break; 0218 default: 0219 mMediaPlayer->play(); 0220 break; 0221 } 0222 } 0223 0224 void PlaySoundWidget::mediaStateChanged(QMediaPlayer::PlaybackState state) 0225 { 0226 switch (state) { 0227 case QMediaPlayer::PlayingState: 0228 mPlayButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause)); 0229 break; 0230 default: 0231 mPlayButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); 0232 break; 0233 } 0234 } 0235 0236 void PlaySoundWidget::handleError() 0237 { 0238 mPlayButton->setEnabled(false); 0239 const QString errorString = mMediaPlayer->errorString(); 0240 QString message = i18n("Error: "); // i18n ? 0241 if (errorString.isEmpty()) { 0242 message += QStringLiteral(" #") + QString::number(int(mMediaPlayer->error())); 0243 } else { 0244 message += errorString; 0245 } 0246 mMessageWidget->setText(message); 0247 mMessageWidget->animatedShow(); 0248 } 0249 0250 #include "moc_playsoundwidget.cpp"