From 0791828b84c150ce11170ea88f848fc77658cd06 Mon Sep 17 00:00:00 2001 From: tehcneko Date: Tue, 29 Apr 2025 20:16:00 +0800 Subject: [PATCH 1/2] WebUI: fix virtual list defects Fixes https://github.com/qbittorrent/qBittorrent/pull/22502#issuecomment-2822201721 and https://github.com/qbittorrent/qBittorrent/pull/22502#issuecomment-2822253388. PR #22597. --- src/webui/www/private/scripts/dynamicTable.js | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 59a52e5c5..3b6cc19de 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -911,6 +911,9 @@ window.qBittorrent.DynamicTable ??= (() => { // set the scrollable height this.table.style.height = `${rows.length * this.rowHeight}px`; + if (this.dynamicTableDiv.offsetHeight === 0) + return; + this.renderedHeight = this.dynamicTableDiv.offsetHeight; // show extra 6 rows at top/bottom to reduce flickering const extraRowCount = 6; // how many rows can be shown in the visible area @@ -947,17 +950,22 @@ window.qBittorrent.DynamicTable ??= (() => { this.updateRow(row, true); // refresh row height based on first row - setTimeout(() => { - if (this.tableBody.firstChild === null) - return; - const tr = this.tableBody.firstChild; - if (this.rowHeight !== tr.offsetHeight) { - this.rowHeight = tr.offsetHeight; - // rerender on row height change - this.rerender(); - } - - }); + const tr = this.tableBody.firstChild; + if (tr !== null) { + const updateRowHeight = () => { + if (tr.offsetHeight === 0) + return; + if (this.rowHeight !== tr.offsetHeight) { + this.rowHeight = tr.offsetHeight; + // rerender on row height change + this.rerender(); + } + }; + if (tr.offsetHeight === 0) + setTimeout(updateRowHeight); + else + updateRowHeight(); + } }, createRowElement: function(row, top = -1) { @@ -2650,8 +2658,18 @@ window.qBittorrent.DynamicTable ??= (() => { this._updateNodeCollapseIcon(node, shouldCollapse); - for (const child of node.children) - this._updateNodeVisibility(child, shouldCollapse); + this._updateNodeChildVisibility(node, shouldCollapse); + }, + + _updateNodeChildVisibility: function(root, shouldHide) { + const stack = [...root.children]; + while (stack.length > 0) { + const node = stack.pop(); + + this._updateNodeVisibility(node, (shouldHide ? shouldHide : this.isCollapsed(node.root.rowId))); + + stack.push(...node.children); + } }, clear: function() { @@ -2914,7 +2932,7 @@ window.qBittorrent.DynamicTable ??= (() => { _filterNodes: function(node, filterTerms, filteredRows) { if (node.isFolder && (!this.useVirtualList || !this.isCollapsed(node.rowId))) { - const childAdded = node.children.reduce((acc, child) => { + const childAdded = node.children.toReversed().reduce((acc, child) => { // we must execute the function before ORing w/ acc or we'll stop checking child nodes after the first successful match return (this._filterNodes(child, filterTerms, filteredRows) || acc); }, false); From e7dee969e1fb2e7dfa2965ea6562702ce2f47070 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Thu, 1 May 2025 08:57:10 +0300 Subject: [PATCH 2/2] Remove dubious seeding time max value PR #22624. --- src/base/bittorrent/sessionimpl.cpp | 18 +++++++++--------- src/base/bittorrent/torrent.cpp | 2 -- src/base/bittorrent/torrent.h | 2 -- src/base/bittorrent/torrentimpl.cpp | 4 ---- src/webui/www/private/shareratio.html | 4 ++-- src/webui/www/private/views/preferences.html | 8 ++++---- 6 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index f3d68cf5f..a6bf947f8 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -472,11 +472,11 @@ SessionImpl::SessionImpl(QObject *parent) , m_additionalTrackers(BITTORRENT_SESSION_KEY(u"AdditionalTrackers"_s)) , m_isAddTrackersFromURLEnabled(BITTORRENT_SESSION_KEY(u"AddTrackersFromURLEnabled"_s), false) , m_additionalTrackersURL(BITTORRENT_SESSION_KEY(u"AdditionalTrackersURL"_s)) - , m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_s), -1, [](qreal r) { return r < 0 ? -1. : r;}) - , m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_s), Torrent::NO_SEEDING_TIME_LIMIT - , clampValue(Torrent::NO_SEEDING_TIME_LIMIT, Torrent::MAX_SEEDING_TIME)) - , m_globalMaxInactiveSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxInactiveSeedingMinutes"_s), Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT - , clampValue(Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, Torrent::MAX_INACTIVE_SEEDING_TIME)) + , m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_s), -1, [](qreal r) { return r < 0 ? -1. : r; }) + , m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_s) + , Torrent::NO_SEEDING_TIME_LIMIT, lowerLimited(Torrent::NO_SEEDING_TIME_LIMIT)) + , m_globalMaxInactiveSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxInactiveSeedingMinutes"_s) + , Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, lowerLimited(Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT)) , m_isAddTorrentToQueueTop(BITTORRENT_SESSION_KEY(u"AddTorrentToTopOfQueue"_s), false) , m_isAddTorrentStopped(BITTORRENT_SESSION_KEY(u"AddTorrentStopped"_s), false) , m_torrentStopCondition(BITTORRENT_SESSION_KEY(u"TorrentStopCondition"_s), Torrent::StopCondition::None) @@ -1258,7 +1258,7 @@ int SessionImpl::globalMaxSeedingMinutes() const void SessionImpl::setGlobalMaxSeedingMinutes(int minutes) { - minutes = std::clamp(minutes, Torrent::NO_SEEDING_TIME_LIMIT, Torrent::MAX_SEEDING_TIME); + minutes = std::max(minutes, Torrent::NO_SEEDING_TIME_LIMIT); if (minutes != globalMaxSeedingMinutes()) { @@ -1274,7 +1274,7 @@ int SessionImpl::globalMaxInactiveSeedingMinutes() const void SessionImpl::setGlobalMaxInactiveSeedingMinutes(int minutes) { - minutes = std::clamp(minutes, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, Torrent::MAX_INACTIVE_SEEDING_TIME); + minutes = std::max(minutes, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT); if (minutes != globalMaxInactiveSeedingMinutes()) { @@ -2337,13 +2337,13 @@ void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent) description = tr("Torrent reached the share ratio limit."); } else if (const qlonglong seedingTimeInMinutes = torrent->finishedTime() / 60; - (seedingTimeLimit >= 0) && (seedingTimeInMinutes <= Torrent::MAX_SEEDING_TIME) && (seedingTimeInMinutes >= seedingTimeLimit)) + (seedingTimeLimit >= 0) && (seedingTimeInMinutes >= seedingTimeLimit)) { reached = true; description = tr("Torrent reached the seeding time limit."); } else if (const qlonglong inactiveSeedingTimeInMinutes = torrent->timeSinceActivity() / 60; - (inactiveSeedingTimeLimit >= 0) && (inactiveSeedingTimeInMinutes <= Torrent::MAX_INACTIVE_SEEDING_TIME) && (inactiveSeedingTimeInMinutes >= inactiveSeedingTimeLimit)) + (inactiveSeedingTimeLimit >= 0) && (inactiveSeedingTimeInMinutes >= inactiveSeedingTimeLimit)) { reached = true; description = tr("Torrent reached the inactive seeding time limit."); diff --git a/src/base/bittorrent/torrent.cpp b/src/base/bittorrent/torrent.cpp index c92fb9aea..1fdf52f61 100644 --- a/src/base/bittorrent/torrent.cpp +++ b/src/base/bittorrent/torrent.cpp @@ -52,8 +52,6 @@ namespace BitTorrent const int Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT = -1; const qreal Torrent::MAX_RATIO = 9999; - const int Torrent::MAX_SEEDING_TIME = 525600; - const int Torrent::MAX_INACTIVE_SEEDING_TIME = 525600; TorrentID Torrent::id() const { diff --git a/src/base/bittorrent/torrent.h b/src/base/bittorrent/torrent.h index fc817b86c..644af158b 100644 --- a/src/base/bittorrent/torrent.h +++ b/src/base/bittorrent/torrent.h @@ -134,8 +134,6 @@ namespace BitTorrent static const int NO_INACTIVE_SEEDING_TIME_LIMIT; static const qreal MAX_RATIO; - static const int MAX_SEEDING_TIME; - static const int MAX_INACTIVE_SEEDING_TIME; using TorrentContentHandler::TorrentContentHandler; diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index f4ae0e0fa..fb27c44dc 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -2692,8 +2692,6 @@ void TorrentImpl::setSeedingTimeLimit(int limit) { if (limit < USE_GLOBAL_SEEDING_TIME) limit = NO_SEEDING_TIME_LIMIT; - else if (limit > MAX_SEEDING_TIME) - limit = MAX_SEEDING_TIME; if (m_seedingTimeLimit != limit) { @@ -2707,8 +2705,6 @@ void TorrentImpl::setInactiveSeedingTimeLimit(int limit) { if (limit < USE_GLOBAL_INACTIVE_SEEDING_TIME) limit = NO_INACTIVE_SEEDING_TIME_LIMIT; - else if (limit > MAX_INACTIVE_SEEDING_TIME) - limit = MAX_SEEDING_TIME; if (m_inactiveSeedingTimeLimit != limit) { diff --git a/src/webui/www/private/shareratio.html b/src/webui/www/private/shareratio.html index 9205b7f76..56b70f25d 100644 --- a/src/webui/www/private/shareratio.html +++ b/src/webui/www/private/shareratio.html @@ -177,12 +177,12 @@
- +
- +
diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index ec27db3a3..c8ef9de78 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -2923,8 +2923,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD let maxSeedingTime = -1; if (document.getElementById("maxSeedingTimeCheckbox").checked) { maxSeedingTime = Number(document.getElementById("maxSeedingTimeValue").value); - if (Number.isNaN(maxSeedingTime) || (maxSeedingTime < 0) || (maxSeedingTime > 525600)) { - alert("QBT_TR(Seeding time limit must be between 0 and 525600 minutes.)QBT_TR[CONTEXT=HttpServer]"); + if (Number.isNaN(maxSeedingTime) || (maxSeedingTime < 0)) { + alert("QBT_TR(Seeding time limit must not have a negative value.)QBT_TR[CONTEXT=HttpServer]"); return; } } @@ -2934,8 +2934,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD let maxInactiveSeedingTime = -1; if (document.getElementById("maxInactiveSeedingTimeCheckbox").checked) { maxInactiveSeedingTime = Number(document.getElementById("maxInactiveSeedingTimeValue").value); - if (Number.isNaN(maxInactiveSeedingTime) || (maxInactiveSeedingTime < 0) || (maxInactiveSeedingTime > 525600)) { - alert("QBT_TR(Seeding time limit must be between 0 and 525600 minutes.)QBT_TR[CONTEXT=HttpServer]"); + if (Number.isNaN(maxInactiveSeedingTime) || (maxInactiveSeedingTime < 0)) { + alert("QBT_TR(Seeding time limit must not have a negative value.)QBT_TR[CONTEXT=HttpServer]"); return; } }