mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-07 08:02:30 -06:00
Compare commits
2 Commits
4be33b2ddc
...
fb4b266828
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb4b266828 | ||
|
|
c953730a42 |
@@ -20,6 +20,8 @@ Required by:
|
||||
|
||||
.mocha {
|
||||
background-color: var(--color-background-default);
|
||||
border-radius: 5px;
|
||||
box-shadow: rgb(51 51 51) 0 1px 5px;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -123,31 +125,15 @@ div.mochaToolbarWrapper.bottom {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.mochaCanvasHeader {
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
visibility: hidden;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.mochaControls {
|
||||
height: 14px;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
right: 6px;
|
||||
top: 6px;
|
||||
width: 52px;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.mochaCanvasControls {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
/*
|
||||
To use images for these buttons:
|
||||
1. Set the useCanvasControls window option to false.
|
||||
@@ -159,17 +145,44 @@ div.mochaToolbarWrapper.bottom {
|
||||
.mochaMinimizeButton,
|
||||
.mochaMaximizeButton,
|
||||
.mochaCloseButton {
|
||||
background-color: var(--color-background-default);
|
||||
color: var(--color-text-default);
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-size: 1px;
|
||||
height: 14px;
|
||||
margin-left: 5px;
|
||||
position: relative;
|
||||
width: 14px;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.mochaMaximizeButton::before,
|
||||
.mochaMaximizeButton::after,
|
||||
.mochaMinimizeButton::before,
|
||||
.mochaCloseButton::before,
|
||||
.mochaCloseButton::after {
|
||||
background-color: var(--color-text-default);
|
||||
border-radius: 1px;
|
||||
content: "";
|
||||
height: 2px;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 9px;
|
||||
}
|
||||
|
||||
.mochaMaximizeButton::after {
|
||||
height: 9px;
|
||||
width: 2px;
|
||||
}
|
||||
|
||||
.mochaCloseButton::before {
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
}
|
||||
|
||||
.mochaCloseButton::after {
|
||||
transform: translate(-50%, -50%) rotate(-45deg);
|
||||
}
|
||||
|
||||
.mochaMinimizeButton {
|
||||
margin-left: 0;
|
||||
}
|
||||
@@ -250,16 +263,6 @@ div.mochaToolbarWrapper.bottom {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* The replaced class is used internally when converting CSS values to Canvas. These classes should not be removed. */
|
||||
|
||||
.mocha.replaced,
|
||||
.mochaTitlebar.replaced,
|
||||
.mochaMinimizeButton.replaced,
|
||||
.mochaMaximizeButton.replaced,
|
||||
.mochaCloseButton.replaced {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.windowClosed {
|
||||
display: none;
|
||||
left: -20000px;
|
||||
@@ -273,8 +276,7 @@ div.mochaToolbarWrapper.bottom {
|
||||
.windowClosed .mochaContentBorder,
|
||||
.windowClosed .mochaToolbarWrapper,
|
||||
.windowClosed .mochaTitlebar,
|
||||
.windowClosed .mochaControls,
|
||||
.windowClosed .mochaCanvasControls {
|
||||
.windowClosed .mochaControls {
|
||||
display: none;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
@@ -345,14 +347,6 @@ div.mochaToolbarWrapper.bottom {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
/* Workaround to make invisible buttons clickable */
|
||||
|
||||
.mochaMinimizeButton.replaced,
|
||||
.mochaMaximizeButton.replaced,
|
||||
.mochaCloseButton.replaced {
|
||||
background-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7") !important;
|
||||
}
|
||||
|
||||
/* iOS iframe scrolling */
|
||||
.windowFrame .mochaContentWrapper {
|
||||
/* scroll the Window content. !important required. */
|
||||
|
||||
@@ -826,10 +826,6 @@ td.statusBarSeparator {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#searchResultsTableDiv {
|
||||
height: calc(100% - 26px) !important;
|
||||
}
|
||||
|
||||
#searchResults .dynamicTable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@
|
||||
const addRowsToTable = (rows, selectedRows) => {
|
||||
let rowId = 0;
|
||||
const rootNode = new window.qBittorrent.FileTree.FolderNode();
|
||||
rootNode.autoCheckFolders = false;
|
||||
rootNode.autoCalculateCheckedState = false;
|
||||
|
||||
rows.forEach((row) => {
|
||||
const pathItems = row.path.split(window.qBittorrent.Filesystem.PathSeparator);
|
||||
@@ -334,7 +334,7 @@
|
||||
|
||||
if (folderNode === null) {
|
||||
folderNode = new window.qBittorrent.FileTree.FolderNode();
|
||||
folderNode.autoCheckFolders = false;
|
||||
folderNode.autoCalculateCheckedState = false;
|
||||
folderNode.rowId = rowId;
|
||||
folderNode.path = (parent.path === "")
|
||||
? folderName
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -114,6 +114,7 @@ window.qBittorrent.FileTree ??= (() => {
|
||||
name = "";
|
||||
path = "";
|
||||
rowId = null;
|
||||
fileId = null;
|
||||
size = 0;
|
||||
checked = TriState.Unchecked;
|
||||
remaining = 0;
|
||||
@@ -122,19 +123,42 @@ window.qBittorrent.FileTree ??= (() => {
|
||||
availability = 0;
|
||||
depth = 0;
|
||||
root = null;
|
||||
data = null;
|
||||
isFolder = false;
|
||||
children = [];
|
||||
|
||||
isIgnored() {
|
||||
return this.priority === FilePriority.Ignored;
|
||||
}
|
||||
|
||||
calculateRemaining() {
|
||||
this.remaining = this.isIgnored() ? 0 : (this.size * (1.0 - (this.progress / 100)));
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return {
|
||||
name: this.name,
|
||||
path: this.path,
|
||||
fileId: this.fileId,
|
||||
size: this.size,
|
||||
checked: this.checked,
|
||||
remaining: this.remaining,
|
||||
progress: this.progress,
|
||||
priority: this.priority,
|
||||
availability: this.availability
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class FolderNode extends FileNode {
|
||||
/**
|
||||
* Will automatically tick the checkbox for a folder if all subfolders and files are also ticked
|
||||
* When true, the folder's `checked` state will be calculately automatically based on its children
|
||||
*/
|
||||
autoCheckFolders = true;
|
||||
autoCalculateCheckedState = true;
|
||||
isFolder = true;
|
||||
fileId = -1;
|
||||
|
||||
addChild(node) {
|
||||
node.calculateRemaining();
|
||||
this.children.push(node);
|
||||
}
|
||||
|
||||
@@ -181,22 +205,32 @@ window.qBittorrent.FileTree ??= (() => {
|
||||
root.checked = TriState.Partial;
|
||||
}
|
||||
|
||||
const isIgnored = (child.priority === FilePriority.Ignored);
|
||||
if (!isIgnored) {
|
||||
if (!child.isIgnored()) {
|
||||
root.remaining += child.remaining;
|
||||
root.progress += (child.progress * child.size);
|
||||
root.availability += (child.availability * child.size);
|
||||
}
|
||||
}
|
||||
|
||||
root.checked = root.autoCheckFolders ? root.checked : TriState.Checked;
|
||||
root.progress /= root.size;
|
||||
root.availability /= root.size;
|
||||
root.checked = root.autoCalculateCheckedState ? root.checked : TriState.Checked;
|
||||
root.progress = (root.size > 0) ? (root.progress / root.size) : 0;
|
||||
root.availability = (root.size > 0) ? (root.availability / root.size) : 0;
|
||||
}
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively recalculate the amount of data remaining to be downloaded.
|
||||
* This is useful for updating a folder's "remaining" size as files are unchecked/ignored.
|
||||
*/
|
||||
calculateRemaining() {
|
||||
this.remaining = this.children.reduce((sum, node) => {
|
||||
node.calculateRemaining();
|
||||
return sum + node.remaining;
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return exports();
|
||||
|
||||
@@ -40,6 +40,7 @@ window.qBittorrent.MonkeyPatch ??= (() => {
|
||||
const patch = () => {
|
||||
patchMootoolsDocumentId();
|
||||
patchMochaGetAsset();
|
||||
patchMochaWindowOptions();
|
||||
};
|
||||
|
||||
const patchMootoolsDocumentId = () => {
|
||||
@@ -123,6 +124,17 @@ window.qBittorrent.MonkeyPatch ??= (() => {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable canvas in MochaUI windows
|
||||
*/
|
||||
const patchMochaWindowOptions = () => {
|
||||
const options = MUI.Window.prototype.options;
|
||||
options.shadowBlur = 0;
|
||||
options.shadowOffset = { x: 0, y: 0 };
|
||||
options.useCanvas = false;
|
||||
options.useCanvasControls = false;
|
||||
};
|
||||
|
||||
return exports();
|
||||
})();
|
||||
Object.freeze(window.qBittorrent.MonkeyPatch);
|
||||
|
||||
@@ -84,12 +84,12 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
|
||||
const getAllChildren = (id, fileId) => {
|
||||
const node = torrentFilesTable.getNode(id);
|
||||
const rowIds = [node.data.rowId];
|
||||
const fileIds = [node.data.fileId];
|
||||
const rowIds = [node.rowId];
|
||||
const fileIds = [node.fileId];
|
||||
|
||||
const getChildFiles = (node) => {
|
||||
rowIds.push(node.data.rowId);
|
||||
fileIds.push(node.data.fileId);
|
||||
rowIds.push(node.rowId);
|
||||
fileIds.push(node.fileId);
|
||||
|
||||
if (node.isFolder) {
|
||||
node.children.forEach((child) => {
|
||||
@@ -214,8 +214,8 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
};
|
||||
|
||||
const getComboboxPriority = (id) => {
|
||||
const row = torrentFilesTable.rows.get(id.toString());
|
||||
return normalizePriority(row.full_data.priority, 10);
|
||||
const node = torrentFilesTable.getNode(id.toString());
|
||||
return normalizePriority(node.priority, 10);
|
||||
};
|
||||
|
||||
const switchGlobalCheckboxState = (e) => {
|
||||
@@ -230,8 +230,9 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
setCheckboxUnchecked(checkbox);
|
||||
torrentFilesTable.rows.forEach((row) => {
|
||||
const rowId = row.rowId;
|
||||
const fileId = row.full_data.fileId;
|
||||
const isChecked = (getCheckboxState(rowId) === TriState.Checked);
|
||||
const node = torrentFilesTable.getNode(rowId);
|
||||
const fileId = node.fileId;
|
||||
const isChecked = (node.checked === TriState.Checked);
|
||||
if (isChecked) {
|
||||
rowIds.push(rowId);
|
||||
fileIds.push(fileId);
|
||||
@@ -242,8 +243,9 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
setCheckboxChecked(checkbox);
|
||||
torrentFilesTable.rows.forEach((row) => {
|
||||
const rowId = row.rowId;
|
||||
const fileId = row.full_data.fileId;
|
||||
const isUnchecked = (getCheckboxState(rowId) === TriState.Unchecked);
|
||||
const node = torrentFilesTable.getNode(rowId);
|
||||
const fileId = node.fileId;
|
||||
const isUnchecked = (node.checked === TriState.Unchecked);
|
||||
if (isUnchecked) {
|
||||
rowIds.push(rowId);
|
||||
fileIds.push(fileId);
|
||||
@@ -285,26 +287,22 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
checkbox.indeterminate = true;
|
||||
};
|
||||
|
||||
const getCheckboxState = (id) => {
|
||||
const row = torrentFilesTable.rows.get(id.toString());
|
||||
return Number(row.full_data.checked);
|
||||
};
|
||||
|
||||
const setFilePriority = (ids, fileIds, priority) => {
|
||||
priority = normalizePriority(priority);
|
||||
|
||||
if (onFilePriorityChanged)
|
||||
onFilePriorityChanged(fileIds, priority);
|
||||
|
||||
const ignore = (priority === FilePriority.Ignored);
|
||||
ids.forEach((id) => {
|
||||
id = id.toString();
|
||||
torrentFilesTable.setIgnored(id, ignore);
|
||||
|
||||
const row = torrentFilesTable.rows.get(id);
|
||||
row.full_data.priority = priority;
|
||||
row.full_data.checked = triStateFromPriority(priority);
|
||||
const nodes = ids.map((id) => {
|
||||
const node = torrentFilesTable.getNode(id.toString());
|
||||
node.priority = priority;
|
||||
node.checked = triStateFromPriority(priority);
|
||||
return node;
|
||||
});
|
||||
|
||||
// must update all nodes above before recalculating
|
||||
for (const node of nodes)
|
||||
node.calculateRemaining();
|
||||
};
|
||||
|
||||
const updateData = (files) => {
|
||||
@@ -318,7 +316,6 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
size: file.size,
|
||||
progress: window.qBittorrent.Misc.toFixedPointString((file.progress * 100), 1),
|
||||
priority: normalizePriority(file.priority),
|
||||
remaining: (ignore ? 0 : (file.size * (1 - file.progress))),
|
||||
availability: file.availability
|
||||
};
|
||||
|
||||
@@ -372,19 +369,17 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
});
|
||||
|
||||
const isChecked = row.checked ? TriState.Checked : TriState.Unchecked;
|
||||
const remaining = (row.priority === FilePriority.Ignored) ? 0 : row.remaining;
|
||||
const childNode = new window.qBittorrent.FileTree.FileNode();
|
||||
childNode.name = row.name;
|
||||
childNode.path = row.fileName;
|
||||
childNode.rowId = rowId;
|
||||
childNode.fileId = row.fileId;
|
||||
childNode.size = row.size;
|
||||
childNode.checked = isChecked;
|
||||
childNode.remaining = remaining;
|
||||
childNode.progress = row.progress;
|
||||
childNode.priority = row.priority;
|
||||
childNode.availability = row.availability;
|
||||
childNode.root = parent;
|
||||
childNode.data = row;
|
||||
parent.addChild(childNode);
|
||||
|
||||
++rowId;
|
||||
@@ -430,6 +425,7 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
const updateComplete = () => {
|
||||
// we've finished recursing
|
||||
updateGlobalCheckbox();
|
||||
torrentFilesTable.calculateRemaining();
|
||||
torrentFilesTable.updateTable(true);
|
||||
};
|
||||
|
||||
@@ -447,7 +443,7 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
let indeterminateCount = 0;
|
||||
let desiredComboboxPriority = null;
|
||||
for (const sibling of siblings) {
|
||||
switch (getCheckboxState(sibling.rowId)) {
|
||||
switch (sibling.checked) {
|
||||
case TriState.Checked:
|
||||
++checkedCount;
|
||||
break;
|
||||
@@ -465,7 +461,7 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
desiredComboboxPriority = FilePriority.Mixed;
|
||||
}
|
||||
|
||||
const currentCheckboxState = getCheckboxState(parent.rowId);
|
||||
const currentCheckboxState = parent.checked;
|
||||
let desiredCheckboxState = TriState.Unchecked;
|
||||
if ((indeterminateCount > 0) || ((checkedCount > 0) && (uncheckedCount > 0)))
|
||||
desiredCheckboxState = TriState.Partial;
|
||||
@@ -474,9 +470,9 @@ window.qBittorrent.TorrentContent ??= (() => {
|
||||
|
||||
const currentComboboxPriority = getComboboxPriority(parent.rowId);
|
||||
if ((currentCheckboxState !== desiredCheckboxState) || (currentComboboxPriority !== desiredComboboxPriority)) {
|
||||
const row = torrentFilesTable.rows.get(parent.rowId.toString());
|
||||
row.full_data.priority = desiredComboboxPriority;
|
||||
row.full_data.checked = desiredCheckboxState;
|
||||
const node = torrentFilesTable.getNode(parent.rowId.toString());
|
||||
node.priority = desiredComboboxPriority;
|
||||
node.checked = desiredCheckboxState;
|
||||
|
||||
updateParentFolder(parent.rowId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user