mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-30 19:15:08 +01:00
Show a Loading... indicator for the gpodder, lazy load images properly
This commit is contained in:
parent
3a88d8fcda
commit
e8a879372d
@ -32,6 +32,7 @@ AddPodcastDialog::AddPodcastDialog(Application* app, QWidget* parent)
|
||||
{
|
||||
ui_->setupUi(this);
|
||||
ui_->details->SetApplication(app);
|
||||
ui_->results->SetExpandOnReset(false);
|
||||
ui_->results_stack->setCurrentWidget(ui_->results_page);
|
||||
|
||||
fader_ = new WidgetFadeHelper(ui_->details_scroll_area);
|
||||
|
@ -53,7 +53,7 @@
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="results_stack">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="results_page">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
@ -64,7 +64,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeView" name="results">
|
||||
<widget class="AutoExpandingTreeView" name="results">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
@ -80,9 +80,40 @@
|
||||
</widget>
|
||||
<widget class="QWidget" name="busy_page">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>192</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="BusyIndicator" name="widget" native="true">
|
||||
<property name="text" stdset="0">
|
||||
@ -90,6 +121,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
@ -97,8 +143,8 @@
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>367</height>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
@ -168,6 +214,11 @@
|
||||
<header>podcasts/podcastinfowidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AutoExpandingTreeView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>widgets/autoexpandingtreeview.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include <ApiRequest.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
GPodderTopTagsModel::GPodderTopTagsModel(mygpo::ApiRequest* api, Application* app,
|
||||
QObject* parent)
|
||||
: PodcastDiscoveryModel(app, parent),
|
||||
@ -57,24 +59,36 @@ void GPodderTopTagsModel::fetchMore(const QModelIndex& parent) {
|
||||
}
|
||||
setData(parent, true, Role_HasLazyLoaded);
|
||||
|
||||
qLog(Debug) << "Fetching podcasts for" << parent.data().toString();
|
||||
// Create a little Loading... item.
|
||||
itemFromIndex(parent)->appendRow(CreateLoadingIndicator());
|
||||
|
||||
mygpo::PodcastList* list =
|
||||
api_->podcastsOfTag(GPodderTopTagsPage::kMaxTagCount, parent.data().toString());
|
||||
|
||||
NewClosure(list, SIGNAL(finished()),
|
||||
this, SLOT(PodcastsOfTagFinished(QModelIndex,mygpo::PodcastList*)),
|
||||
parent, list);
|
||||
NewClosure(list, SIGNAL(parseError()),
|
||||
this, SLOT(PodcastsOfTagFailed(QModelIndex,mygpo::PodcastList*)),
|
||||
parent, list);
|
||||
NewClosure(list, SIGNAL(requestError(QNetworkReply::NetworkError)),
|
||||
this, SLOT(PodcastsOfTagFailed(QModelIndex,mygpo::PodcastList*)),
|
||||
parent, list);
|
||||
}
|
||||
|
||||
void GPodderTopTagsModel::PodcastsOfTagFinished(const QModelIndex& parent,
|
||||
mygpo::PodcastList* list) {
|
||||
list->deleteLater();
|
||||
qLog(Debug) << "Tag list finished";
|
||||
|
||||
QStandardItem* parent_item = itemFromIndex(parent);
|
||||
if (!parent_item)
|
||||
return;
|
||||
|
||||
// Remove the Loading... item.
|
||||
while (parent_item->hasChildren()) {
|
||||
parent_item->removeRow(0);
|
||||
}
|
||||
|
||||
foreach (mygpo::PodcastPtr gpo_podcast, list->list()) {
|
||||
Podcast podcast;
|
||||
podcast.InitFromGpo(gpo_podcast.data());
|
||||
@ -82,3 +96,29 @@ void GPodderTopTagsModel::PodcastsOfTagFinished(const QModelIndex& parent,
|
||||
parent_item->appendRow(CreatePodcastItem(podcast));
|
||||
}
|
||||
}
|
||||
|
||||
void GPodderTopTagsModel::PodcastsOfTagFailed(const QModelIndex& parent,
|
||||
mygpo::PodcastList* list) {
|
||||
list->deleteLater();
|
||||
|
||||
QStandardItem* parent_item = itemFromIndex(parent);
|
||||
if (!parent_item)
|
||||
return;
|
||||
|
||||
// Remove the Loading... item.
|
||||
while (parent_item->hasChildren()) {
|
||||
parent_item->removeRow(0);
|
||||
}
|
||||
|
||||
if (QMessageBox::warning(
|
||||
NULL, tr("Failed to fetch podcasts"),
|
||||
tr("There was a problem communicating with gpodder.net"),
|
||||
QMessageBox::Retry | QMessageBox::Close,
|
||||
QMessageBox::Retry) != QMessageBox::Retry) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try fetching the list again.
|
||||
setData(parent, false, Role_HasLazyLoaded);
|
||||
fetchMore(parent);
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ public:
|
||||
|
||||
private slots:
|
||||
void PodcastsOfTagFinished(const QModelIndex& parent, mygpo::PodcastList* list);
|
||||
void PodcastsOfTagFailed(const QModelIndex& parent, mygpo::PodcastList* list);
|
||||
|
||||
private:
|
||||
mygpo::ApiRequest* api_;
|
||||
|
@ -37,20 +37,23 @@ PodcastDiscoveryModel::PodcastDiscoveryModel(Application* app, QObject* parent)
|
||||
connect(this, SIGNAL(modelAboutToBeReset()), SLOT(CancelPendingImages()));
|
||||
}
|
||||
|
||||
QVariant PodcastDiscoveryModel::data(const QModelIndex& index, int role) const {
|
||||
if (index.isValid() &&
|
||||
role == Qt::DecorationRole &&
|
||||
QStandardItemModel::data(index, Role_Type).toInt() == Type_Podcast &&
|
||||
QStandardItemModel::data(index, Role_StartedLoadingImage).toBool() == false) {
|
||||
const_cast<PodcastDiscoveryModel*>(this)->LazyLoadImage(index);
|
||||
}
|
||||
|
||||
return QStandardItemModel::data(index, role);
|
||||
}
|
||||
|
||||
QStandardItem* PodcastDiscoveryModel::CreatePodcastItem(const Podcast& podcast) {
|
||||
QStandardItem* item = new QStandardItem;
|
||||
item->setIcon(default_icon_);
|
||||
item->setText(podcast.title());
|
||||
item->setData(QVariant::fromValue(podcast), Role_Podcast);
|
||||
item->setData(Type_Podcast, Role_Type);
|
||||
|
||||
if (podcast.image_url().isValid()) {
|
||||
// Start loading an image for this item.
|
||||
quint64 id = app_->album_cover_loader()->LoadImageAsync(
|
||||
cover_options_, podcast.image_url().toString(), QString());
|
||||
pending_covers_[id] = item;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@ -66,15 +69,37 @@ QStandardItem* PodcastDiscoveryModel::CreateFolder(const QString& name) {
|
||||
return item;
|
||||
}
|
||||
|
||||
void PodcastDiscoveryModel::LazyLoadImage(const QModelIndex& index) {
|
||||
QStandardItem* item = itemFromIndex(index);
|
||||
item->setData(true, Role_StartedLoadingImage);
|
||||
|
||||
Podcast podcast = index.data(Role_Podcast).value<Podcast>();
|
||||
|
||||
if (podcast.image_url().isValid()) {
|
||||
quint64 id = app_->album_cover_loader()->LoadImageAsync(
|
||||
cover_options_, podcast.image_url().toString(), QString());
|
||||
pending_covers_[id] = item;
|
||||
}
|
||||
}
|
||||
|
||||
void PodcastDiscoveryModel::ImageLoaded(quint64 id, const QImage& image) {
|
||||
QStandardItem* item = pending_covers_.take(id);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
if (!image.isNull()) {
|
||||
item->setIcon(QIcon(QPixmap::fromImage(image)));
|
||||
}
|
||||
}
|
||||
|
||||
void PodcastDiscoveryModel::CancelPendingImages() {
|
||||
app_->album_cover_loader()->CancelTasks(QSet<quint64>::fromList(pending_covers_.keys()));
|
||||
pending_covers_.clear();
|
||||
}
|
||||
|
||||
QStandardItem* PodcastDiscoveryModel::CreateLoadingIndicator() {
|
||||
QStandardItem* item = new QStandardItem;
|
||||
item->setText(tr("Loading..."));
|
||||
item->setData(Type_LoadingIndicator, Role_Type);
|
||||
return item;
|
||||
}
|
||||
|
@ -33,12 +33,14 @@ public:
|
||||
|
||||
enum Type {
|
||||
Type_Folder,
|
||||
Type_Podcast
|
||||
Type_Podcast,
|
||||
Type_LoadingIndicator
|
||||
};
|
||||
|
||||
enum Role {
|
||||
Role_Podcast = Qt::UserRole,
|
||||
Role_Type,
|
||||
Role_StartedLoadingImage,
|
||||
|
||||
RoleCount
|
||||
};
|
||||
@ -48,11 +50,17 @@ public:
|
||||
|
||||
QStandardItem* CreatePodcastItem(const Podcast& podcast);
|
||||
QStandardItem* CreateFolder(const QString& name);
|
||||
QStandardItem* CreateLoadingIndicator();
|
||||
|
||||
QVariant data(const QModelIndex& index, int role) const;
|
||||
|
||||
private slots:
|
||||
void CancelPendingImages();
|
||||
void ImageLoaded(quint64 id, const QImage& image);
|
||||
|
||||
private:
|
||||
void LazyLoadImage(const QModelIndex& index);
|
||||
|
||||
private:
|
||||
Application* app_;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user