From c3224459db0ff4a058cb35cb73ab5eff76af3070 Mon Sep 17 00:00:00 2001 From: skomerko <168652295+skomerko@users.noreply.github.com> Date: Sun, 22 Sep 2024 08:12:44 +0200 Subject: [PATCH] WebUI: Add 'Confirm torrent recheck' option This PR adds setting & confirmation dialog for torrent recheck. Closes #19557. PR #21348. --- src/webui/api/appcontroller.cpp | 5 ++ src/webui/www/private/css/style.css | 19 ++++-- src/webui/www/private/scripts/mocha-init.js | 64 ++++++++++++++----- .../www/private/views/confirmRecheck.html | 59 +++++++++++++++++ .../www/private/views/confirmdeletion.html | 2 +- src/webui/www/private/views/preferences.html | 10 +++ src/webui/www/webui.qrc | 1 + 7 files changed, 136 insertions(+), 24 deletions(-) create mode 100644 src/webui/www/private/views/confirmRecheck.html diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index b4ce1bc7d..fd6cd442c 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -368,6 +368,8 @@ void AppController::preferencesAction() data[u"save_statistics_interval"_s] = static_cast(session->saveStatisticsInterval().count()); // .torrent file size limit data[u"torrent_file_size_limit"_s] = pref->getTorrentFileSizeLimit(); + // Confirm torrent recheck + data[u"confirm_torrent_recheck"_s] = pref->confirmTorrentRecheck(); // Recheck completed torrents data[u"recheck_completed_torrents"_s] = pref->recheckTorrentsOnCompletion(); // Customize application instance name @@ -977,6 +979,9 @@ void AppController::setPreferencesAction() // .torrent file size limit if (hasKey(u"torrent_file_size_limit"_s)) pref->setTorrentFileSizeLimit(it.value().toLongLong()); + // Confirm torrent recheck + if (hasKey(u"confirm_torrent_recheck"_s)) + pref->setConfirmTorrentRecheck(it.value().toBool()); // Recheck completed torrents if (hasKey(u"recheck_completed_torrents"_s)) pref->recheckTorrentsOnCompletion(it.value().toBool()); diff --git a/src/webui/www/private/css/style.css b/src/webui/www/private/css/style.css index 6613dcad5..db7917cef 100644 --- a/src/webui/www/private/css/style.css +++ b/src/webui/www/private/css/style.css @@ -755,23 +755,23 @@ td.statusBarSeparator { color: var(--color-text-white); } -/* Confirm deletion dialog */ +/* Modals */ -#confirmDeletionPage * { +.modalDialog * { box-sizing: border-box; } -#confirmDeletionPage_content { +.modalDialog .mochaContent.pad { display: flex !important; /* override for default mocha inline style */ flex-direction: column; height: 100%; } -#confirmDeletionPage_content > :last-child { +.modalDialog .mochaContent.pad > :last-child { align-self: flex-end; } -#confirmDeletionDialog { +.modalDialog .mochaContent.pad > :first-child { margin: auto 0; } @@ -792,10 +792,11 @@ td.statusBarSeparator { vertical-align: -1px; } -#deleteTorrentMessage { +.dialogMessage { overflow-wrap: anywhere; } +.genericConfirmGrid, .confirmDeletionGrid { align-items: center; display: grid; @@ -804,6 +805,7 @@ td.statusBarSeparator { margin-bottom: 10px; } +.confirmGridItem, .deletionGridItem { padding: 3px; } @@ -812,8 +814,13 @@ td.statusBarSeparator { justify-self: center; } +.confirmWarning, .confirmDialogWarning { background: url("../images/dialog-warning.svg") center center no-repeat; height: 38px; width: 38px; } + +.confirmWarning { + background-image: url("../images/help-about.svg"); +} diff --git a/src/webui/www/private/scripts/mocha-init.js b/src/webui/www/private/scripts/mocha-init.js index 9620ac38e..337f704c5 100644 --- a/src/webui/www/private/scripts/mocha-init.js +++ b/src/webui/www/private/scripts/mocha-init.js @@ -48,14 +48,24 @@ window.qBittorrent.Dialog ??= (() => { const deepFreeze = (obj) => { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#examples + // accounts for circular refs + const frozen = new WeakSet(); + const deepFreezeSafe = (obj) => { + if (frozen.has(obj)) + return; - const keys = Reflect.ownKeys(obj); - for (const key of keys) { - const value = obj[key]; - if ((value && (typeof value === "object")) || (typeof value === "function")) - deepFreeze(value); - } - Object.freeze(obj); + frozen.add(obj); + + const keys = Reflect.ownKeys(obj); + for (const key of keys) { + const value = obj[key]; + if ((value && (typeof value === "object")) || (typeof value === "function")) + deepFreezeSafe(value); + } + Object.freeze(obj); + }; + + deepFreezeSafe(obj); }; const baseModalOptions = Object.assign(Object.create(null), { @@ -76,7 +86,11 @@ window.qBittorrent.Dialog ??= (() => { left: 5 }, resizable: true, - width: 480 + width: 480, + onCloseComplete: function() { + // make sure overlay is properly hidden upon modal closing + document.getElementById("modalOverlay").style.display = "none"; + } }); deepFreeze(baseModalOptions); @@ -541,15 +555,31 @@ const initializeWindows = function() { recheckFN = function() { const hashes = torrentsTable.selectedRowsIds(); - if (hashes.length) { - new Request({ - url: "api/v2/torrents/recheck", - method: "post", - data: { - hashes: hashes.join("|"), - } - }).send(); - updateMainData(); + if (hashes.length > 0) { + if (window.qBittorrent.Cache.preferences.get().confirm_torrent_recheck) { + new MochaUI.Modal({ + ...window.qBittorrent.Dialog.baseModalOptions, + id: "confirmRecheckDialog", + title: "QBT_TR(Recheck confirmation)QBT_TR[CONTEXT=confirmRecheckDialog]", + data: { hashes: hashes }, + contentURL: "views/confirmRecheck.html" + }); + } + else { + new Request({ + url: "api/v2/torrents/recheck", + method: "post", + data: { + "hashes": hashes.join("|"), + }, + onSuccess: function() { + updateMainData(); + }, + onFailure: function() { + alert("QBT_TR(Unable to recheck torrents.)QBT_TR[CONTEXT=HttpServer]"); + } + }).send(); + } } }; diff --git a/src/webui/www/private/views/confirmRecheck.html b/src/webui/www/private/views/confirmRecheck.html new file mode 100644 index 000000000..06a8409bd --- /dev/null +++ b/src/webui/www/private/views/confirmRecheck.html @@ -0,0 +1,59 @@ +
+
+ + +
+
+
+ + +
+ + diff --git a/src/webui/www/private/views/confirmdeletion.html b/src/webui/www/private/views/confirmdeletion.html index 122709b3f..5b0d7dbc6 100644 --- a/src/webui/www/private/views/confirmdeletion.html +++ b/src/webui/www/private/views/confirmdeletion.html @@ -1,7 +1,7 @@
- + diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index fefb1e00c..31febeb83 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -1168,6 +1168,14 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD   QBT_TR(MiB)QBT_TR[CONTEXT=OptionsDialog] + + + + + + + + @@ -2464,6 +2472,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD $("saveResumeDataInterval").value = pref.save_resume_data_interval; $("saveStatisticsInterval").value = pref.save_statistics_interval; $("torrentFileSizeLimit").value = (pref.torrent_file_size_limit / 1024 / 1024); + document.getElementById("confirmTorrentRecheck").checked = pref.confirm_torrent_recheck; $("recheckTorrentsOnCompletion").checked = pref.recheck_completed_torrents; $("appInstanceName").value = pref.app_instance_name; $("refreshInterval").value = pref.refresh_interval; @@ -2920,6 +2929,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["save_resume_data_interval"] = Number($("saveResumeDataInterval").value); settings["save_statistics_interval"] = Number($("saveStatisticsInterval").value); settings["torrent_file_size_limit"] = ($("torrentFileSizeLimit").value * 1024 * 1024); + settings["confirm_torrent_recheck"] = document.getElementById("confirmTorrentRecheck").checked; settings["recheck_completed_torrents"] = $("recheckTorrentsOnCompletion").checked; settings["app_instance_name"] = $("appInstanceName").value; settings["refresh_interval"] = Number($("refreshInterval").value); diff --git a/src/webui/www/webui.qrc b/src/webui/www/webui.qrc index 9b5a256c4..df27f335e 100644 --- a/src/webui/www/webui.qrc +++ b/src/webui/www/webui.qrc @@ -421,6 +421,7 @@ private/views/about.html private/views/aboutToolbar.html private/views/confirmdeletion.html + private/views/confirmRecheck.html private/views/filters.html private/views/installsearchplugin.html private/views/log.html