diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/remote_public_decks_model.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/remote_public_decks_model.cpp index 9fff594ac..1f5b453ab 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/remote_public_decks_model.cpp +++ b/cockatrice/src/interface/widgets/visual_deck_storage/remote_public_decks_model.cpp @@ -1,5 +1,8 @@ #include "remote_public_decks_model.h" +#include "../../../client/settings/cache_settings.h" + +#include #include #include #include @@ -7,10 +10,26 @@ #include #include #include +#include RemotePublicDecksModel::RemotePublicDecksModel(AbstractClient *_client, QObject *parent) : QAbstractListModel(parent), client(_client) { + // The ping sweep can drop a pending command without ever emitting finished, + // so loading must not be a latch: time it out and clear it when the client + // goes away, or the tab is stuck on the loading state for the session. + loadingTimeoutTimer = new QTimer(this); + loadingTimeoutTimer->setSingleShot(true); + loadingTimeoutTimer->setInterval( + static_cast((static_cast(SettingsCache::instance().network().getTimeOut()) + 1) * + SettingsCache::instance().network().getKeepAlive() * 1000)); + connect(loadingTimeoutTimer, &QTimer::timeout, this, &RemotePublicDecksModel::onLoadingTimeout); + connect(client, &AbstractClient::statusChanged, this, [this](ClientStatus status) { + if (status == StatusDisconnected) { + loadingTimeoutTimer->stop(); + setLoading(false); + } + }); } int RemotePublicDecksModel::rowCount(const QModelIndex &parent) const @@ -136,6 +155,7 @@ void RemotePublicDecksModel::refresh(const QString &userName) return; } setLoading(true); + loadingTimeoutTimer->start(); Command_DeckListOtherUser cmd; cmd.set_user_name(userName.toStdString()); PendingCommand *pend = client->prepareSessionCommand(cmd); @@ -143,6 +163,12 @@ void RemotePublicDecksModel::refresh(const QString &userName) client->sendCommand(pend); } +void RemotePublicDecksModel::onLoadingTimeout() +{ + setLoading(false); + emit loadFailed(tr("The server did not respond in time. Try again.")); +} + void RemotePublicDecksModel::clear() { decks.clear(); @@ -161,6 +187,7 @@ void RemotePublicDecksModel::setLoading(bool value) void RemotePublicDecksModel::decksReceived(const Response &response, const CommandContainer & /*commandContainer*/) { setLoading(false); + loadingTimeoutTimer->stop(); if (response.response_code() != Response::RespOk) { emit loadFailed(tr("Failed to load the user's public decks (server response code %1).") .arg(QString::number(static_cast(response.response_code())))); diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/remote_public_decks_model.h b/cockatrice/src/interface/widgets/visual_deck_storage/remote_public_decks_model.h index a9b4d62d0..3c562b847 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/remote_public_decks_model.h +++ b/cockatrice/src/interface/widgets/visual_deck_storage/remote_public_decks_model.h @@ -16,6 +16,7 @@ class AbstractClient; class CommandContainer; +class QTimer; class Response; class ServerInfo_DeckStorage_Folder; class ServerInfo_DeckStorage_TreeItem; @@ -103,6 +104,7 @@ signals: private slots: void decksReceived(const Response &response, const CommandContainer &commandContainer); + void onLoadingTimeout(); private: void addFolder(const ServerInfo_DeckStorage_Folder &folder); @@ -111,6 +113,7 @@ private: void setLoading(bool value); AbstractClient *client; + QTimer *loadingTimeoutTimer; QList decks; QList visibleIndices; ///< Row indices into `decks` that pass the current filters. bool loading = false;