[DeckStorage] Refresh the visibility column with a guarded timer instead of a latch counter

A dropped visibility reply used to leave the pendingVisibilityChanges
counter permanently positive, so the Public/Private column never refreshed
again and nothing reset it on disconnect. A restartable single-shot timer
with a boolean guard re-reads the tree whenever publishes quiet down and is
stopped on disconnect, so a lost reply costs one stale refresh instead of
killing the column for the session.
This commit is contained in:
Lukas Brübach 2026-09-19 07:46:51 +02:00
parent 8aedee2b4e
commit 3608e53453
2 changed files with 28 additions and 7 deletions

View file

@ -44,6 +44,12 @@
#include <libcockatrice/settings/paths_settings.h>
#include <libcockatrice/utility/string_limits.h>
namespace {
// How long to wait after the last visibility change before reading back the
// Public/Private column, in milliseconds.
constexpr int VISIBILITY_REFRESH_DELAY = 500;
} // namespace
TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
AbstractClient *_client,
const ServerInfo_User *currentUserInfo)
@ -120,6 +126,15 @@ TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
SettingsCache::instance().network().getKeepAlive() * 1000));
connect(shareTimeoutTimer, &QTimer::timeout, this, &TabDeckStorage::onShareFromTreeTimeout);
// Restartable single-shot refresh for the Public/Private column. A dropped
// visibility reply must not leave the widget permanently stale, so the tree
// is re-read whenever publishes quiet down instead of waiting on a count
// that can get stuck above zero.
visibilityRefreshTimer = new QTimer(this);
visibilityRefreshTimer->setSingleShot(true);
visibilityRefreshTimer->setInterval(VISIBILITY_REFRESH_DELAY);
connect(visibilityRefreshTimer, &QTimer::timeout, this, &TabDeckStorage::onVisibilityRefreshTimeout);
QVBoxLayout *rightVbox = new QVBoxLayout;
rightVbox->addWidget(shareBar);
rightVbox->addWidget(serverDirView);
@ -255,6 +270,8 @@ void TabDeckStorage::handleConnected(const ServerInfo_User &userInfo)
void TabDeckStorage::handleConnectionChanged(ClientStatus status)
{
if (status == StatusDisconnected) {
visibilityRefreshTimer->stop();
visibilityRefreshStarted = false;
setRemoteEnabled(false);
}
}
@ -847,7 +864,8 @@ void TabDeckStorage::actPublishDeck()
PendingCommand *pend = client->prepareSessionCommand(cmd);
connect(pend, &PendingCommand::finished, this, &TabDeckStorage::setVisibilityFinished);
++pendingVisibilityChanges;
visibilityRefreshStarted = true;
visibilityRefreshTimer->start();
client->sendCommand(pend);
}
}
@ -859,9 +877,10 @@ void TabDeckStorage::setVisibilityFinished(const Response &r, const CommandConta
tr("Failed to change deck visibility on server (response code %1).")
.arg(QString::number(static_cast<int>(r.response_code()))));
}
// Refresh once the last in-flight change has been acknowledged so the
// Public/Private column reflects every selected node.
if (--pendingVisibilityChanges == 0) {
serverDirView->refreshTree();
}
}
void TabDeckStorage::onVisibilityRefreshTimeout()
{
visibilityRefreshStarted = false;
serverDirView->refreshTree();
}

View file

@ -43,7 +43,8 @@ private:
QAction *aOpenLocalDeck, *aRenameLocal, *aUpload, *aNewLocalFolder, *aDeleteLocalDeck;
QAction *aOpenDecksFolder;
QAction *aOpenRemoteDeck, *aDownload, *aShareDecks, *aPublishDeck, *aNewFolder, *aDeleteRemoteDeck;
int pendingVisibilityChanges = 0;
bool visibilityRefreshStarted = false;
QTimer *visibilityRefreshTimer;
QString getTargetPath() const;
void setRemoteEnabled(bool enabled);
@ -93,6 +94,7 @@ private slots:
void actPublishDeck();
void setVisibilityFinished(const Response &r, const CommandContainer &commandContainer);
void onVisibilityRefreshTimeout();
void actDeleteRemoteDeck();
void deleteFolderFinished(const Response &response, const CommandContainer &commandContainer);