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