diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 185ac995c..e4cc15cc8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -263,6 +263,7 @@ set(SOURCES internet/podcasts/addpodcastbyurl.cpp internet/podcasts/addpodcastdialog.cpp internet/podcasts/addpodcastpage.cpp + internet/podcasts/episodeinfowidget.cpp internet/podcasts/fixedopmlpage.cpp internet/podcasts/gpoddersearchpage.cpp internet/podcasts/gpoddersync.cpp @@ -560,6 +561,7 @@ set(HEADERS internet/podcasts/addpodcastbyurl.h internet/podcasts/addpodcastdialog.h internet/podcasts/addpodcastpage.h + internet/podcasts/episodeinfowidget.h internet/podcasts/fixedopmlpage.h internet/podcasts/gpoddersearchpage.h internet/podcasts/gpoddersync.h @@ -715,6 +717,7 @@ set(UI internet/podcasts/addpodcastbyurl.ui internet/podcasts/addpodcastdialog.ui + internet/podcasts/episodeinfowidget.ui internet/podcasts/gpoddersearchpage.ui internet/podcasts/itunessearchpage.ui internet/podcasts/podcastinfodialog.ui diff --git a/src/core/utilities.cpp b/src/core/utilities.cpp index 35e15c1aa..fc300a005 100644 --- a/src/core/utilities.cpp +++ b/src/core/utilities.cpp @@ -89,7 +89,7 @@ QString PrettyTimeDelta(int seconds) { return (seconds >= 0 ? "+" : "-") + PrettyTime(seconds); } -QString PrettyTime(int seconds) { +QString PrettyTime(int seconds, bool always_show_hours) { // last.fm sometimes gets the track length wrong, so you end up with // negative times. seconds = qAbs(seconds); @@ -99,7 +99,7 @@ QString PrettyTime(int seconds) { seconds %= 60; QString ret; - if (hours) + if (hours || always_show_hours) ret.sprintf("%d:%02d:%02d", hours, minutes, seconds); // NOLINT(runtime/printf) else @@ -108,8 +108,8 @@ QString PrettyTime(int seconds) { return ret; } -QString PrettyTimeNanosec(qint64 nanoseconds) { - return PrettyTime(nanoseconds / kNsecPerSec); +QString PrettyTimeNanosec(qint64 nanoseconds, bool always_show_hours) { + return PrettyTime(nanoseconds / kNsecPerSec, always_show_hours); } QString WordyTime(quint64 seconds) { diff --git a/src/core/utilities.h b/src/core/utilities.h index 6d1a8972d..7345a1140 100644 --- a/src/core/utilities.h +++ b/src/core/utilities.h @@ -39,9 +39,9 @@ class QXmlStreamReader; struct QMetaObject; namespace Utilities { -QString PrettyTime(int seconds); +QString PrettyTime(int seconds, bool always_show_hours = false); QString PrettyTimeDelta(int seconds); -QString PrettyTimeNanosec(qint64 nanoseconds); +QString PrettyTimeNanosec(qint64 nanoseconds, bool always_show_hours = false); QString PrettySize(quint64 bytes); QString PrettySize(const QSize& size); QString WordyTime(quint64 seconds); diff --git a/src/internet/podcasts/episodeinfowidget.cpp b/src/internet/podcasts/episodeinfowidget.cpp new file mode 100644 index 000000000..7cf8bde12 --- /dev/null +++ b/src/internet/podcasts/episodeinfowidget.cpp @@ -0,0 +1,40 @@ +/* This file is part of Clementine. + Copyright 2018, Jim Broadus + + Clementine 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 + (at your option) any later version. + + Clementine 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 Clementine. If not, see . +*/ + +#include "core/utilities.h" +#include "episodeinfowidget.h" +#include "ui_episodeinfowidget.h" + +#include + +EpisodeInfoWidget::EpisodeInfoWidget(QWidget* parent) + : QWidget(parent), ui_(new Ui_EpisodeInfoWidget), app_(nullptr) { + ui_->setupUi(this); +} + +EpisodeInfoWidget::~EpisodeInfoWidget() { delete ui_; } + +void EpisodeInfoWidget::SetApplication(Application* app) { app_ = app; } + +void EpisodeInfoWidget::SetEpisode(const PodcastEpisode& episode) { + episode_ = episode; + ui_->title->setText(episode.title()); + ui_->description->setText(episode.description()); + ui_->author->setText(episode.author()); + ui_->date->setText(episode.publication_date().toString("d MMMM yyyy")); + ui_->duration->setText(Utilities::PrettyTime(episode.duration_secs(), true)); +} diff --git a/src/internet/podcasts/episodeinfowidget.h b/src/internet/podcasts/episodeinfowidget.h new file mode 100644 index 000000000..b228ad4ec --- /dev/null +++ b/src/internet/podcasts/episodeinfowidget.h @@ -0,0 +1,46 @@ +/* This file is part of Clementine. + Copyright 2018, Jim Broadus + + Clementine 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 + (at your option) any later version. + + Clementine 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 Clementine. If not, see . +*/ + +#ifndef INTERNET_PODCASTS_EPISODEINFOWIDGET_H_ +#define INTERNET_PODCASTS_EPISODEINFOWIDGET_H_ + +#include "podcastepisode.h" + +#include + +class Application; +class Ui_EpisodeInfoWidget; + +class EpisodeInfoWidget : public QWidget { + Q_OBJECT + + public: + explicit EpisodeInfoWidget(QWidget* parent = nullptr); + ~EpisodeInfoWidget(); + + void SetApplication(Application* app); + + void SetEpisode(const PodcastEpisode& episode); + + private: + Ui_EpisodeInfoWidget* ui_; + + Application* app_; + PodcastEpisode episode_; +}; + +#endif // INTERNET_PODCASTS_EPISODEINFOWIDGET_H_ diff --git a/src/internet/podcasts/episodeinfowidget.ui b/src/internet/podcasts/episodeinfowidget.ui new file mode 100644 index 000000000..e4945a45a --- /dev/null +++ b/src/internet/podcasts/episodeinfowidget.ui @@ -0,0 +1,137 @@ + + + EpisodeInfoWidget + + + + 0 + 0 + 398 + 551 + + + + Form + + + #title { + font-weight: bold; +} + +#description { + font-size: smaller; +} + +QLineEdit { + background: transparent; +} + + + + QLayout::SetMinAndMaxSize + + + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + QLayout::SetMinAndMaxSize + + + + + Author + + + true + + + + + + + false + + + true + + + + + + + false + + + true + + + + + + + Date + + + true + + + + + + + Duration + + + true + + + + + + + false + + + true + + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + diff --git a/src/internet/podcasts/podcastinfodialog.cpp b/src/internet/podcasts/podcastinfodialog.cpp index 33db8cde9..ae398a6b6 100644 --- a/src/internet/podcasts/podcastinfodialog.cpp +++ b/src/internet/podcasts/podcastinfodialog.cpp @@ -24,7 +24,8 @@ PodcastInfoDialog::PodcastInfoDialog(Application* app, QWidget* parent) app_(app), ui_(new Ui_PodcastInfoDialog) { ui_->setupUi(this); - ui_->details->SetApplication(app); + ui_->podcast_details->SetApplication(app); + ui_->episode_details->SetApplication(app); } PodcastInfoDialog::~PodcastInfoDialog() { @@ -32,8 +33,19 @@ PodcastInfoDialog::~PodcastInfoDialog() { } void PodcastInfoDialog::ShowPodcast(const Podcast& podcast) { - show(); + ui_->episode_info_scroll_area->hide(); ui_->podcast_url->setText(podcast.url().toString()); ui_->podcast_url->setReadOnly(true); - ui_->details->SetPodcast(podcast); + ui_->podcast_details->SetPodcast(podcast); + show(); +} + +void PodcastInfoDialog::ShowEpisode(const PodcastEpisode& episode, + const Podcast& podcast) { + ui_->episode_info_scroll_area->show(); + ui_->podcast_url->setText(episode.url().toString()); + ui_->podcast_url->setReadOnly(true); + ui_->podcast_details->SetPodcast(podcast); + ui_->episode_details->SetEpisode(episode); + show(); } diff --git a/src/internet/podcasts/podcastinfodialog.h b/src/internet/podcasts/podcastinfodialog.h index 3643d8007..93540175a 100644 --- a/src/internet/podcasts/podcastinfodialog.h +++ b/src/internet/podcasts/podcastinfodialog.h @@ -22,6 +22,7 @@ class Application; class Podcast; +class PodcastEpisode; class Ui_PodcastInfoDialog; class PodcastInfoDialog : public QDialog { @@ -32,6 +33,7 @@ class PodcastInfoDialog : public QDialog { ~PodcastInfoDialog(); void ShowPodcast(const Podcast& podcast); + void ShowEpisode(const PodcastEpisode& episode, const Podcast& podcast); private: Application* app_; diff --git a/src/internet/podcasts/podcastinfodialog.ui b/src/internet/podcasts/podcastinfodialog.ui index e0cbb0970..573dddff6 100644 --- a/src/internet/podcasts/podcastinfodialog.ui +++ b/src/internet/podcasts/podcastinfodialog.ui @@ -7,7 +7,7 @@ 0 0 493 - 395 + 415 @@ -18,7 +18,36 @@ - + + + true + + + + 250 + 100 + + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 473 + 163 + + + + + + + 250 @@ -37,13 +66,13 @@ true - + 0 0 473 - 313 + 162 @@ -68,6 +97,12 @@
internet/podcasts/podcastinfowidget.h
1 + + EpisodeInfoWidget + QWidget +
internet/podcasts/episodeinfowidget.h
+ 1 +
diff --git a/src/internet/podcasts/podcastservice.cpp b/src/internet/podcasts/podcastservice.cpp index 6b196aaab..2258038a8 100644 --- a/src/internet/podcasts/podcastservice.cpp +++ b/src/internet/podcasts/podcastservice.cpp @@ -528,8 +528,15 @@ void PodcastService::ShowContextMenu(const QPoint& global_pos) { } if (selected_podcasts_.count() == 1) { - info_selected_action_->setEnabled(true); + if (selected_episodes_.count() == 1) { + info_selected_action_->setText(tr("Episode information")); + info_selected_action_->setEnabled(true); + } else { + info_selected_action_->setText(tr("Podcast information")); + info_selected_action_->setEnabled(true); + } } else { + info_selected_action_->setText(tr("Podcast information")); info_selected_action_->setEnabled(false); } @@ -699,10 +706,19 @@ void PodcastService::DownloadSelectedEpisode() { } void PodcastService::PodcastInfo() { - if (selected_podcasts_.count() > 0) { - const Podcast podcast = - selected_podcasts_[0].data(Role_Podcast).value(); - podcast_info_dialog_.reset(new PodcastInfoDialog(app_)); + if (selected_podcasts_.isEmpty()) { + // Should never happen. + return; + } + const Podcast podcast = + selected_podcasts_[0].data(Role_Podcast).value(); + podcast_info_dialog_.reset(new PodcastInfoDialog(app_)); + + if (selected_episodes_.count() == 1) { + const PodcastEpisode episode = + selected_episodes_[0].data(Role_Episode).value(); + podcast_info_dialog_->ShowEpisode(episode, podcast); + } else { podcast_info_dialog_->ShowPodcast(podcast); } }