WebUI: Add 'Confirm torrent recheck' option

This PR adds setting & confirmation dialog for torrent recheck.

Closes #19557.
PR #21348.
This commit is contained in:
skomerko 2024-09-22 08:12:44 +02:00 committed by GitHub
parent 183c7c75b1
commit c3224459db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 136 additions and 24 deletions

View file

@ -368,6 +368,8 @@ void AppController::preferencesAction()
data[u"save_statistics_interval"_s] = static_cast<int>(session->saveStatisticsInterval().count()); data[u"save_statistics_interval"_s] = static_cast<int>(session->saveStatisticsInterval().count());
// .torrent file size limit // .torrent file size limit
data[u"torrent_file_size_limit"_s] = pref->getTorrentFileSizeLimit(); data[u"torrent_file_size_limit"_s] = pref->getTorrentFileSizeLimit();
// Confirm torrent recheck
data[u"confirm_torrent_recheck"_s] = pref->confirmTorrentRecheck();
// Recheck completed torrents // Recheck completed torrents
data[u"recheck_completed_torrents"_s] = pref->recheckTorrentsOnCompletion(); data[u"recheck_completed_torrents"_s] = pref->recheckTorrentsOnCompletion();
// Customize application instance name // Customize application instance name
@ -977,6 +979,9 @@ void AppController::setPreferencesAction()
// .torrent file size limit // .torrent file size limit
if (hasKey(u"torrent_file_size_limit"_s)) if (hasKey(u"torrent_file_size_limit"_s))
pref->setTorrentFileSizeLimit(it.value().toLongLong()); pref->setTorrentFileSizeLimit(it.value().toLongLong());
// Confirm torrent recheck
if (hasKey(u"confirm_torrent_recheck"_s))
pref->setConfirmTorrentRecheck(it.value().toBool());
// Recheck completed torrents // Recheck completed torrents
if (hasKey(u"recheck_completed_torrents"_s)) if (hasKey(u"recheck_completed_torrents"_s))
pref->recheckTorrentsOnCompletion(it.value().toBool()); pref->recheckTorrentsOnCompletion(it.value().toBool());

View file

@ -755,23 +755,23 @@ td.statusBarSeparator {
color: var(--color-text-white); color: var(--color-text-white);
} }
/* Confirm deletion dialog */ /* Modals */
#confirmDeletionPage * { .modalDialog * {
box-sizing: border-box; box-sizing: border-box;
} }
#confirmDeletionPage_content { .modalDialog .mochaContent.pad {
display: flex !important; /* override for default mocha inline style */ display: flex !important; /* override for default mocha inline style */
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
} }
#confirmDeletionPage_content > :last-child { .modalDialog .mochaContent.pad > :last-child {
align-self: flex-end; align-self: flex-end;
} }
#confirmDeletionDialog { .modalDialog .mochaContent.pad > :first-child {
margin: auto 0; margin: auto 0;
} }
@ -792,10 +792,11 @@ td.statusBarSeparator {
vertical-align: -1px; vertical-align: -1px;
} }
#deleteTorrentMessage { .dialogMessage {
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
.genericConfirmGrid,
.confirmDeletionGrid { .confirmDeletionGrid {
align-items: center; align-items: center;
display: grid; display: grid;
@ -804,6 +805,7 @@ td.statusBarSeparator {
margin-bottom: 10px; margin-bottom: 10px;
} }
.confirmGridItem,
.deletionGridItem { .deletionGridItem {
padding: 3px; padding: 3px;
} }
@ -812,8 +814,13 @@ td.statusBarSeparator {
justify-self: center; justify-self: center;
} }
.confirmWarning,
.confirmDialogWarning { .confirmDialogWarning {
background: url("../images/dialog-warning.svg") center center no-repeat; background: url("../images/dialog-warning.svg") center center no-repeat;
height: 38px; height: 38px;
width: 38px; width: 38px;
} }
.confirmWarning {
background-image: url("../images/help-about.svg");
}

View file

@ -48,16 +48,26 @@ window.qBittorrent.Dialog ??= (() => {
const deepFreeze = (obj) => { const deepFreeze = (obj) => {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#examples // 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;
frozen.add(obj);
const keys = Reflect.ownKeys(obj); const keys = Reflect.ownKeys(obj);
for (const key of keys) { for (const key of keys) {
const value = obj[key]; const value = obj[key];
if ((value && (typeof value === "object")) || (typeof value === "function")) if ((value && (typeof value === "object")) || (typeof value === "function"))
deepFreeze(value); deepFreezeSafe(value);
} }
Object.freeze(obj); Object.freeze(obj);
}; };
deepFreezeSafe(obj);
};
const baseModalOptions = Object.assign(Object.create(null), { const baseModalOptions = Object.assign(Object.create(null), {
addClass: "modalDialog", addClass: "modalDialog",
collapsible: false, collapsible: false,
@ -76,7 +86,11 @@ window.qBittorrent.Dialog ??= (() => {
left: 5 left: 5
}, },
resizable: true, 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); deepFreeze(baseModalOptions);
@ -541,15 +555,31 @@ const initializeWindows = function() {
recheckFN = function() { recheckFN = function() {
const hashes = torrentsTable.selectedRowsIds(); const hashes = torrentsTable.selectedRowsIds();
if (hashes.length) { 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({ new Request({
url: "api/v2/torrents/recheck", url: "api/v2/torrents/recheck",
method: "post", method: "post",
data: { data: {
hashes: hashes.join("|"), "hashes": hashes.join("|"),
},
onSuccess: function() {
updateMainData();
},
onFailure: function() {
alert("QBT_TR(Unable to recheck torrents.)QBT_TR[CONTEXT=HttpServer]");
} }
}).send(); }).send();
updateMainData(); }
} }
}; };

View file

@ -0,0 +1,59 @@
<div id="confirmRecheckDialog">
<div class="genericConfirmGrid">
<span class="confirmGridItem confirmWarning"></span>
<span class="confirmGridItem dialogMessage" id="confirmRecheckMessage"></span>
</div>
</div>
<div>
<input type="button" value="QBT_TR(Yes)QBT_TR[CONTEXT=MainWindow]" id="confirmRecheckButton">
<input type="button" value="QBT_TR(No)QBT_TR[CONTEXT=MainWindow]" id="cancelRecheckButton">
</div>
<script>
"use strict";
(() => {
const confirmButton = document.getElementById("confirmRecheckButton");
const cancelButton = document.getElementById("cancelRecheckButton");
const confirmText = document.getElementById("confirmRecheckMessage");
const {
options: { data: { hashes } },
windowEl
} = window.MUI.Windows.instances["confirmRecheckDialog"];
confirmText.textContent = "QBT_TR(Are you sure you want to recheck the selected torrent(s)?)QBT_TR[CONTEXT=confirmRecheckDialog]";
cancelButton.addEventListener("click", (e) => { window.qBittorrent.Client.closeWindow("confirmRecheckDialog"); });
confirmButton.addEventListener("click", (e) => {
new Request({
url: "api/v2/torrents/recheck",
method: "post",
data: {
hashes: hashes.join("|"),
},
onSuccess: function() {
updateMainData();
window.qBittorrent.Client.closeWindow("confirmRecheckDialog");
},
onFailure: function() {
alert("QBT_TR(Unable to recheck torrents.)QBT_TR[CONTEXT=HttpServer]");
}
}).send();
});
// set tabindex so window element receives keydown events
windowEl.setAttribute("tabindex", "-1");
windowEl.focus();
windowEl.addEventListener("keydown", (e) => {
switch (e.key) {
case "Enter":
confirmButton.click();
break;
case "Escape":
window.qBittorrent.Client.closeWindow("confirmRecheckDialog");
break;
}
});
})();
</script>

View file

@ -1,7 +1,7 @@
<div id="confirmDeletionDialog"> <div id="confirmDeletionDialog">
<div class="confirmDeletionGrid"> <div class="confirmDeletionGrid">
<span class="deletionGridItem confirmDialogWarning"></span> <span class="deletionGridItem confirmDialogWarning"></span>
<span class="deletionGridItem" id="deleteTorrentMessage"></span> <span class="deletionGridItem dialogMessage" id="deleteTorrentMessage"></span>
<span class="deletionGridItem"> <span class="deletionGridItem">
<button class="disabled" type="button" id="rememberBtn" title="QBT_TR(Remember choice)QBT_TR[CONTEXT=HttpServer]" aria-label="QBT_TR(Remember choice)QBT_TR[CONTEXT=HttpServer]" disabled></button> <button class="disabled" type="button" id="rememberBtn" title="QBT_TR(Remember choice)QBT_TR[CONTEXT=HttpServer]" aria-label="QBT_TR(Remember choice)QBT_TR[CONTEXT=HttpServer]" disabled></button>
</span> </span>

View file

@ -1168,6 +1168,14 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
<input type="text" id="torrentFileSizeLimit" style="width: 15em;">&nbsp;&nbsp;QBT_TR(MiB)QBT_TR[CONTEXT=OptionsDialog] <input type="text" id="torrentFileSizeLimit" style="width: 15em;">&nbsp;&nbsp;QBT_TR(MiB)QBT_TR[CONTEXT=OptionsDialog]
</td> </td>
</tr> </tr>
<tr>
<td>
<label for="confirmTorrentRecheck">QBT_TR(Confirm torrent recheck:)QBT_TR[CONTEXT=OptionsDialog]</label>
</td>
<td>
<input type="checkbox" id="confirmTorrentRecheck">
</td>
</tr>
<tr> <tr>
<td> <td>
<label for="recheckTorrentsOnCompletion">QBT_TR(Recheck torrents on completion:)QBT_TR[CONTEXT=OptionsDialog]</label> <label for="recheckTorrentsOnCompletion">QBT_TR(Recheck torrents on completion:)QBT_TR[CONTEXT=OptionsDialog]</label>
@ -2464,6 +2472,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
$("saveResumeDataInterval").value = pref.save_resume_data_interval; $("saveResumeDataInterval").value = pref.save_resume_data_interval;
$("saveStatisticsInterval").value = pref.save_statistics_interval; $("saveStatisticsInterval").value = pref.save_statistics_interval;
$("torrentFileSizeLimit").value = (pref.torrent_file_size_limit / 1024 / 1024); $("torrentFileSizeLimit").value = (pref.torrent_file_size_limit / 1024 / 1024);
document.getElementById("confirmTorrentRecheck").checked = pref.confirm_torrent_recheck;
$("recheckTorrentsOnCompletion").checked = pref.recheck_completed_torrents; $("recheckTorrentsOnCompletion").checked = pref.recheck_completed_torrents;
$("appInstanceName").value = pref.app_instance_name; $("appInstanceName").value = pref.app_instance_name;
$("refreshInterval").value = pref.refresh_interval; $("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_resume_data_interval"] = Number($("saveResumeDataInterval").value);
settings["save_statistics_interval"] = Number($("saveStatisticsInterval").value); settings["save_statistics_interval"] = Number($("saveStatisticsInterval").value);
settings["torrent_file_size_limit"] = ($("torrentFileSizeLimit").value * 1024 * 1024); settings["torrent_file_size_limit"] = ($("torrentFileSizeLimit").value * 1024 * 1024);
settings["confirm_torrent_recheck"] = document.getElementById("confirmTorrentRecheck").checked;
settings["recheck_completed_torrents"] = $("recheckTorrentsOnCompletion").checked; settings["recheck_completed_torrents"] = $("recheckTorrentsOnCompletion").checked;
settings["app_instance_name"] = $("appInstanceName").value; settings["app_instance_name"] = $("appInstanceName").value;
settings["refresh_interval"] = Number($("refreshInterval").value); settings["refresh_interval"] = Number($("refreshInterval").value);

View file

@ -421,6 +421,7 @@
<file>private/views/about.html</file> <file>private/views/about.html</file>
<file>private/views/aboutToolbar.html</file> <file>private/views/aboutToolbar.html</file>
<file>private/views/confirmdeletion.html</file> <file>private/views/confirmdeletion.html</file>
<file>private/views/confirmRecheck.html</file>
<file>private/views/filters.html</file> <file>private/views/filters.html</file>
<file>private/views/installsearchplugin.html</file> <file>private/views/installsearchplugin.html</file>
<file>private/views/log.html</file> <file>private/views/log.html</file>