diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index cb4a0fed6..eec1d65b7 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -57,6 +57,7 @@ #include "chat/ChatDialog.h" #include "RetroShareLink.h" #include "SoundManager.h" +#include "PlayerPage.h" #include "notifyqt.h" #include "common/UserNotify.h" #include "gui/ServicePermissionDialog.h" @@ -189,6 +190,7 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) gxschannelDialog=NULL; gxsforumDialog=NULL; postedDialog=NULL; + playerDialog=NULL; /* Invoke the Qt Designer generated QObject setup routine */ ui->setupUi(this); @@ -416,6 +418,7 @@ void MainWindow::initStackedPage() addPage(gxschannelDialog = new GxsChannelDialog(ui->stackPages), grp, ¬ify); addPage(gxsforumDialog = new GxsForumsDialog(ui->stackPages), grp, ¬ify); addPage(postedDialog = new PostedDialog(ui->stackPages), grp, ¬ify); + addPage(playerDialog = new PlayerPage(ui->stackPages), grp, NULL); #ifdef RS_USE_NEW_PEOPLE_DIALOG PeopleDialog *peopleDialog = NULL; @@ -994,6 +997,9 @@ void SetForegroundWindowInternal(HWND hWnd) case Posted: _instance->ui->stackPages->setCurrentPage( _instance->postedDialog ); return true ; + case Player: + _instance->ui->stackPages->setCurrentPage( _instance->playerDialog ); + return true ; default: std::cerr << "Show page called on value that is not handled yet. Please code it! (value = " << page << ")" << std::endl; } @@ -1076,6 +1082,8 @@ void SetForegroundWindowInternal(HWND hWnd) return _instance->gxsforumDialog; case Posted: return _instance->postedDialog; + case Player: + return _instance->playerDialog; } return NULL; diff --git a/retroshare-gui/src/gui/MainWindow.h b/retroshare-gui/src/gui/MainWindow.h index 5240cdce3..53c5ea401 100644 --- a/retroshare-gui/src/gui/MainWindow.h +++ b/retroshare-gui/src/gui/MainWindow.h @@ -61,7 +61,7 @@ class TransfersDialog; class MessagesDialog; class PluginsPage; class HomePage; -//class ChannelFeed; +class PlayerPage; class BandwidthGraph; class MainPage; class NewsFeed; @@ -92,8 +92,9 @@ public: Forums = 7, /** Forums page. */ Search = 8, /** Search page. */ Posted = 11, /** Posted links */ - People = 12, /** People page. */ - Options = 13 /** People page. */ + People = 12, /** People page. */ + Options = 13, /** People page. */ + Player = 14 /** Player page. */ }; @@ -153,6 +154,7 @@ public: GxsChannelDialog *gxschannelDialog ; GxsForumsDialog *gxsforumDialog ; PostedDialog *postedDialog; + PlayerPage *playerDialog; // ForumsDialog *forumsDialog; // ChannelFeed *channelFeed; diff --git a/retroshare-gui/src/gui/PlayerPage.cpp b/retroshare-gui/src/gui/PlayerPage.cpp new file mode 100644 index 000000000..3a80202e8 --- /dev/null +++ b/retroshare-gui/src/gui/PlayerPage.cpp @@ -0,0 +1,209 @@ +/******************************************************************************* + * gui/PlayerPage.cpp * + * * + * Copyright (C) 2020 RetroShare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include "PlayerPage.h" +#include "ui_PlayerPage.h" + +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) +#include +#endif + +#include +#include + +#include +#include + + +PlayerPage::PlayerPage(QWidget *parent) : + MainPage(parent), + ui(new Ui::PlayerPage) +{ + ui->setupUi(this); + + mediaPlayer = new QMediaPlayer(this, QMediaPlayer::VideoSurface); + videoWidget = new QVideoWidget; + + videoWidget->show(); + videoWidget->setStyleSheet("background-color: #1f1f1f;"); + + playButton = new QPushButton; + playButton->setEnabled(false); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + + stopButton = new QPushButton; + stopButton->setIcon(style()->standardIcon(QStyle::SP_MediaStop)); + stopButton->setEnabled(false); + + fullScreenButton = new QPushButton(tr("FullScreen")); + fullScreenButton->setCheckable(true); + fullScreenButton->setEnabled(false); + + positionSlider = new QSlider(Qt::Horizontal); + positionSlider->setRange(0, mediaPlayer->duration() / 1000); + + labelDuration = new QLabel; + + errorLabel = new QLabel; + errorLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + + QBoxLayout *controlLayout = new QHBoxLayout; + controlLayout->setMargin(0); + + controlLayout->addWidget(playButton); + controlLayout->addWidget(stopButton); + controlLayout->addWidget(positionSlider); + controlLayout->addWidget(labelDuration); + controlLayout->addWidget(fullScreenButton); + + QBoxLayout *layout = new QVBoxLayout; + layout->addWidget(videoWidget); + layout->addLayout(controlLayout); + layout->addWidget(errorLabel); + + ui->widget->setLayout(layout); + + mediaPlayer->setVideoOutput(videoWidget); + + connect(playButton, &QAbstractButton::clicked,this, &PlayerPage::play); + connect(stopButton, &QAbstractButton::clicked,this, &PlayerPage::stopVideo); + connect(mediaPlayer, &QMediaPlayer::stateChanged,this, &PlayerPage::mediaStateChanged); + connect(mediaPlayer, &QMediaPlayer::positionChanged, this, &PlayerPage::positionChanged); + connect(mediaPlayer, &QMediaPlayer::durationChanged, this, &PlayerPage::durationChanged); + connect(mediaPlayer, QOverload::of(&QMediaPlayer::error),this, &PlayerPage::handleError); + connect(mediaPlayer, SIGNAL(videoAvailableChanged(bool)), this, SLOT(videoAvailableChanged(bool))); + connect(positionSlider, &QSlider::sliderMoved, this, &PlayerPage::seek); +} + +PlayerPage::~PlayerPage() +{ + delete ui; +} + +void PlayerPage::setUrl(const QUrl &url) +{ + errorLabel->setText(QString()); + mediaPlayer->setMedia(url); + playButton->setEnabled(true); + play(); +} + +void PlayerPage::play() +{ + switch (mediaPlayer->state()) { + //case QMediaPlayer::StoppedState: + case QMediaPlayer::PlayingState: + mediaPlayer->pause(); + break; + default: + mediaPlayer->play(); + break; + } +} + +void PlayerPage::stopVideo() +{ + mediaPlayer->stop(); +} + +void PlayerPage::mediaStateChanged(QMediaPlayer::State state) +{ + switch (state) { + case QMediaPlayer::StoppedState: + stopButton->setEnabled(false); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + break; + case QMediaPlayer::PlayingState: + stopButton->setEnabled(true); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause)); + break; + case QMediaPlayer::PausedState: + stopButton->setEnabled(true); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + break; + } +} + +void PlayerPage::positionChanged(qint64 progress) +{ + if (!positionSlider->isSliderDown()) + positionSlider->setValue(progress / 1000); + + updateDurationInfo(progress / 1000); +} + +void PlayerPage::durationChanged(qint64 duration) +{ + duration = duration / 1000; + positionSlider->setMaximum(duration); +} + +void PlayerPage::seek(int seconds) +{ + mediaPlayer->setPosition(seconds * 1000); +} + +void PlayerPage::handleError() +{ + playButton->setEnabled(false); + const QString errorString = mediaPlayer->errorString(); + QString message = "Error: "; + if (errorString.isEmpty()) + message += " #" + QString::number(int(mediaPlayer->error())); + else + message += errorString; + errorLabel->setText(message); +} + +void PlayerPage::videoAvailableChanged(bool available) +{ + if (!available) { + disconnect(fullScreenButton, SIGNAL(clicked(bool)), + videoWidget, SLOT(setFullScreen(bool))); + disconnect(videoWidget, SIGNAL(fullScreenChanged(bool)), + fullScreenButton, SLOT(setChecked(bool))); + videoWidget->setFullScreen(false); + } else { + connect(fullScreenButton, SIGNAL(clicked(bool)), + videoWidget, SLOT(setFullScreen(bool))); + connect(videoWidget, SIGNAL(fullScreenChanged(bool)), + fullScreenButton, SLOT(setChecked(bool))); + + if (fullScreenButton->isChecked()) + videoWidget->setFullScreen(true); + } + +} + +void PlayerPage::updateDurationInfo(qint64 currentInfo) +{ + QString tStr; + if (currentInfo || duration) { + QTime currentTime((currentInfo / 3600) % 60, (currentInfo / 60) % 60, + currentInfo % 60, (currentInfo * 1000) % 1000); + QTime totalTime((duration / 3600) % 60, (duration / 60) % 60, + duration % 60, (duration * 1000) % 1000); + QString format = "mm:ss"; + if (duration > 3600) + format = "hh:mm:ss"; + tStr = currentTime.toString(format) + " / " + totalTime.toString(format); + } + labelDuration->setText(tStr); +} diff --git a/retroshare-gui/src/gui/PlayerPage.h b/retroshare-gui/src/gui/PlayerPage.h new file mode 100644 index 000000000..3e6de8eb8 --- /dev/null +++ b/retroshare-gui/src/gui/PlayerPage.h @@ -0,0 +1,91 @@ +/******************************************************************************* + * gui/PlayerPage.h * + * * + * Copyright (C) 2020 RetroShare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#ifndef PLAYERPAGE_H +#define PLAYERPAGE_H + +#include +#include +#include + +#include +#include +#include + +class QAbstractButton; +class QPushButton; +class QSlider; +class QLabel; +class QUrl; + + +namespace Ui { +class PlayerPage; +} + +class PlayerPage : public MainPage +{ + Q_OBJECT + +public: + explicit PlayerPage(QWidget *parent); + ~PlayerPage(); + + virtual QIcon iconPixmap() const { return QIcon(":/icons/png/video-camera.png") ; } //MainPage + virtual QString pageName() const { return tr("Player") ; } //MainPage + virtual QString helpText() const { return ""; } //MainPage + + void setUrl(const QUrl &url); +protected: + //virtual void keyPressEvent(QKeyEvent *e) ; + +public slots: + + void play(); + void stopVideo(); + +private slots: + void mediaStateChanged(QMediaPlayer::State state); + void positionChanged(qint64 position); + void durationChanged(qint64 duration); + void handleError(); + void videoAvailableChanged(bool available); + + void seek(int seconds); + +private: + void updateDurationInfo(qint64 currentInfo); + + QMediaPlayer* mediaPlayer; + QVideoWidget *videoWidget; + QPushButton *playButton; + QPushButton *fullScreenButton; + QPushButton *stopButton; + QSlider *positionSlider; + QLabel *errorLabel; + QLabel *labelDuration; + qint64 duration; + + Ui::PlayerPage *ui; + + +}; + +#endif // PlayerPage_H diff --git a/retroshare-gui/src/gui/PlayerPage.ui b/retroshare-gui/src/gui/PlayerPage.ui new file mode 100644 index 000000000..16f1e9ef3 --- /dev/null +++ b/retroshare-gui/src/gui/PlayerPage.ui @@ -0,0 +1,27 @@ + + + PlayerPage + + + + 0 + 0 + 612 + 450 + + + + Form + + + + + + + + + + + + + diff --git a/retroshare-gui/src/gui/feeds/SubFileItem.cpp b/retroshare-gui/src/gui/feeds/SubFileItem.cpp index ba81ab9bf..76de6d7b9 100644 --- a/retroshare-gui/src/gui/feeds/SubFileItem.cpp +++ b/retroshare-gui/src/gui/feeds/SubFileItem.cpp @@ -24,6 +24,8 @@ #include #include "SubFileItem.h" +#include "gui/PlayerPage.h" +#include "gui/MainWindow.h" #include #include @@ -97,6 +99,7 @@ SubFileItem::SubFileItem(const RsFileHash &hash, const std::string &name, const void SubFileItem::Setup() { connect( playButton, SIGNAL( clicked( ) ), this, SLOT( play ( ) ) ); + connect( mediaplayerButton, SIGNAL( clicked( ) ), this, SLOT( playmedia ( ) ) ); connect( downloadButton, SIGNAL( clicked( ) ), this, SLOT( download ( ) ) ); connect( cancelButton, SIGNAL( clicked( ) ), this, SLOT( cancel( ) ) ); connect( deleteButton, SIGNAL( clicked( ) ), this, SLOT( del( ) ) ); @@ -604,6 +607,38 @@ void SubFileItem::play() } +void SubFileItem::playmedia() +{ + FileInfo info; + FileSearchFlags flags = RS_FILE_HINTS_DOWNLOAD | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_NETWORK_WIDE; + + + if (!rsFiles->FileDetails( mFileHash, flags, info)) + return; + + if (done()) { + + /* Play the Video with the Qt Mediaplayer */ + QFileInfo qinfo; + qinfo.setFile(info.path.c_str()); + if (qinfo.exists()) { + MainWindow::showWindow(MainWindow::Player); + PlayerPage *Player = dynamic_cast(MainWindow::getPage(MainWindow::Player)); + Player->setUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath())); + }else{ + QMessageBox::information(this, tr("Play File"), + tr("File %1 does not exist at location.").arg(info.path.c_str())); + return; + } + } else { + /* rise a message box for incompleted download file */ + QMessageBox::information(this, tr("Play File"), + tr("File %1 is not completed.").arg(info.fname.c_str())); + return; + } + +} + void SubFileItem::download() { #ifdef DEBUG_ITEM diff --git a/retroshare-gui/src/gui/feeds/SubFileItem.h b/retroshare-gui/src/gui/feeds/SubFileItem.h index 23f8e0f67..bf9988ecd 100644 --- a/retroshare-gui/src/gui/feeds/SubFileItem.h +++ b/retroshare-gui/src/gui/feeds/SubFileItem.h @@ -82,6 +82,7 @@ public slots: void play(); void mediatype(); void copyLink(); + void playmedia(); private slots: void toggle(); diff --git a/retroshare-gui/src/gui/feeds/SubFileItem.ui b/retroshare-gui/src/gui/feeds/SubFileItem.ui index 6717836b5..b1319dd49 100644 --- a/retroshare-gui/src/gui/feeds/SubFileItem.ui +++ b/retroshare-gui/src/gui/feeds/SubFileItem.ui @@ -70,12 +70,6 @@ 0 - - - 0 - 26 - - Qt::NoFocus @@ -96,12 +90,6 @@ 0 - - - 0 - 26 - - Qt::NoFocus @@ -117,6 +105,23 @@ + + + + Play in Qt Media Player + + + + :/icons/png/video-camera.png:/icons/png/video-camera.png + + + + 16 + 16 + + + + @@ -125,12 +130,6 @@ 0 - - - 0 - 26 - - Qt::NoFocus @@ -180,12 +179,6 @@ 0 - - - 0 - 26 - - Qt::NoFocus diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index f57a8726f..516783201 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -122,8 +122,9 @@ icons/png/thumbs-down.png icons/png/thumbs-neutral.png icons/png/thumbs-up.png - icons/png/typing.png + icons/png/typing.png icons/png/video.png + icons/png/video-camera.png icons/quit_128.png icons/search_red_128.png icons/security_high_128.png diff --git a/retroshare-gui/src/gui/icons/png/video-camera.png b/retroshare-gui/src/gui/icons/png/video-camera.png new file mode 100644 index 000000000..181bcf47f Binary files /dev/null and b/retroshare-gui/src/gui/icons/png/video-camera.png differ diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index f0a901e39..5c302e74a 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -19,7 +19,7 @@ !include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") TEMPLATE = app -QT += network xml +QT += network xml multimedia multimediawidgets CONFIG += qt gui uic qrc resources idle CONFIG += console TARGET = retroshare @@ -421,6 +421,7 @@ HEADERS += rshare.h \ gui/SoundManager.h \ gui/HelpDialog.h \ gui/LogoBar.h \ + gui/PlayerPage.h \ gui/common/AvatarDialog.h \ gui/FileTransfer/SearchDialog.h \ gui/FileTransfer/SharedFilesDialog.h \ @@ -676,6 +677,7 @@ FORMS += gui/StartDialog.ui \ # gui/ShareDialog.ui \ gui/help/browser/helpbrowser.ui \ gui/HelpDialog.ui \ + gui/PlayerPage.ui \ gui/ServicePermissionDialog.ui \ gui/profile/ProfileWidget.ui \ gui/profile/StatusMessage.ui \ @@ -798,6 +800,7 @@ SOURCES += main.cpp \ # gui/ShareDialog.cpp \ # gui/SFListDelegate.cpp \ gui/SoundManager.cpp \ + gui/PlayerPage.cpp \ gui/im_history/ImHistoryBrowser.cpp \ gui/im_history/IMHistoryItemDelegate.cpp \ gui/im_history/IMHistoryItemPainter.cpp \