1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-30 19:46:56 +00:00
transmission/web/javascript/torrent-row.js
Alexander Futekov 660b44da70 DL/UL speed typography changes for web ui
The current icons are very hard to read at the current font size and it's not immediately visible which icon i which.

Additionally, spaces after icons are removed because upload icon is equally positioned between DL/UL speeds (like so `↓ 273 kB/s **↑** 0 kB/s`) which requires reading the whole line to make sense of which number the arrow applies to.

To further separate one type of information from another the hyphen is replaced by the slightly wider en dash.

Old vs New:
Downloading from 7 of 19 peers - ↓ 273 kB/s ↑ 167 kB/s
Downloading from 7 of 19 peers – ▼273 kB/s ▲167 kB/s
2017-08-07 06:34:00 +03:00

416 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright © Mnemosyne LLC
*
* This file is licensed under the GPLv2.
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/
function TorrentRendererHelper() {}
TorrentRendererHelper.getProgressInfo = function (controller, t) {
var pct, extra;
var s = t.getStatus();
var seed_ratio_limit = t.seedRatioLimit(controller);
if (t.needsMetaData()) {
pct = t.getMetadataPercentComplete() * 100;
} else if (!t.isDone()) {
pct = Math.round(t.getPercentDone() * 100);
} else if (seed_ratio_limit > 0 && t.isSeeding()) { // don't split up the bar if paused or queued
pct = Math.round(t.getUploadRatio() * 100 / seed_ratio_limit);
} else {
pct = 100;
};
if (s === Torrent._StatusStopped) {
extra = 'paused';
} else if (s === Torrent._StatusDownloadWait) {
extra = 'leeching queued';
} else if (t.needsMetaData()) {
extra = 'magnet';
} else if (s === Torrent._StatusDownload) {
extra = 'leeching';
} else if (s === Torrent._StatusSeedWait) {
extra = 'seeding queued';
} else if (s === Torrent._StatusSeed) {
extra = 'seeding';
} else {
extra = '';
};
return {
percent: pct,
complete: ['torrent_progress_bar', 'complete', extra].join(' '),
incomplete: ['torrent_progress_bar', 'incomplete', extra].join(' ')
};
};
TorrentRendererHelper.createProgressbar = function (classes) {
var complete, incomplete, progressbar;
complete = document.createElement('div');
complete.className = 'torrent_progress_bar complete';
incomplete = document.createElement('div');
incomplete.className = 'torrent_progress_bar incomplete';
progressbar = document.createElement('div');
progressbar.className = 'torrent_progress_bar_container ' + classes;
progressbar.appendChild(complete);
progressbar.appendChild(incomplete);
return {
'element': progressbar,
'complete': complete,
'incomplete': incomplete
};
};
TorrentRendererHelper.renderProgressbar = function (controller, t, progressbar) {
var e, style, width, display
var info = TorrentRendererHelper.getProgressInfo(controller, t);
// update the complete progressbar
e = progressbar.complete;
style = e.style;
width = '' + info.percent + '%';
display = info.percent > 0 ? 'block' : 'none';
if (style.width !== width || style.display !== display) {
$(e).css({
width: '' + info.percent + '%',
display: display
});
};
if (e.className !== info.complete) {
e.className = info.complete;
};
// update the incomplete progressbar
e = progressbar.incomplete;
display = (info.percent < 100) ? 'block' : 'none';
if (e.style.display !== display) {
e.style.display = display;
};
if (e.className !== info.incomplete) {
e.className = info.incomplete;
};
};
TorrentRendererHelper.formatUL = function (t) {
return '▲' + Transmission.fmt.speedBps(t.getUploadSpeed());
};
TorrentRendererHelper.formatDL = function (t) {
return '▼' + Transmission.fmt.speedBps(t.getDownloadSpeed());
};
TorrentRendererHelper.formatETA = function(t) {
var eta = t.getETA();
if (eta < 0 || eta >= (999 * 60 * 60)) {
return "";
};
return "ETA: " + Transmission.fmt.timeInterval(eta);
};
/****
*****
*****
****/
function TorrentRendererFull() {};
TorrentRendererFull.prototype = {
createRow: function () {
var root, name, peers, progressbar, details, image, button;
root = document.createElement('li');
root.className = 'torrent';
name = document.createElement('div');
name.className = 'torrent_name';
peers = document.createElement('div');
peers.className = 'torrent_peer_details';
progressbar = TorrentRendererHelper.createProgressbar('full');
details = document.createElement('div');
details.className = 'torrent_progress_details';
image = document.createElement('div');
button = document.createElement('a');
button.appendChild(image);
root.appendChild(name);
root.appendChild(peers);
root.appendChild(button);
root.appendChild(progressbar.element);
root.appendChild(details);
root._name_container = name;
root._peer_details_container = peers;
root._progress_details_container = details;
root._progressbar = progressbar;
root._pause_resume_button_image = image;
root._toggle_running_button = button;
return root;
},
getPeerDetails: function (t) {
var err,
peer_count,
webseed_count,
fmt = Transmission.fmt;
if ((err = t.getErrorMessage())) {
return err;
};
if (t.isDownloading()) {
peer_count = t.getPeersConnected();
webseed_count = t.getWebseedsSendingToUs();
if (webseed_count && peer_count) {
// Downloading from 2 of 3 peer(s) and 2 webseed(s)
return ['Downloading from',
t.getPeersSendingToUs(),
'of',
fmt.countString('peer', 'peers', peer_count),
'and',
fmt.countString('web seed', 'web seeds', webseed_count),
'',
TorrentRendererHelper.formatDL(t),
TorrentRendererHelper.formatUL(t)
].join(' ');
} else if (webseed_count) {
// Downloading from 2 webseed(s)
return ['Downloading from',
fmt.countString('web seed', 'web seeds', webseed_count),
'',
TorrentRendererHelper.formatDL(t),
TorrentRendererHelper.formatUL(t)
].join(' ');
} else {
// Downloading from 2 of 3 peer(s)
return ['Downloading from',
t.getPeersSendingToUs(),
'of',
fmt.countString('peer', 'peers', peer_count),
'',
TorrentRendererHelper.formatDL(t),
TorrentRendererHelper.formatUL(t)
].join(' ');
};
};
if (t.isSeeding()) {
return ['Seeding to', t.getPeersGettingFromUs(), 'of', fmt.countString('peer', 'peers', t.getPeersConnected()), '-', TorrentRendererHelper.formatUL(t)].join(' ');
};
if (t.isChecking()) {
return ['Verifying local data (', Transmission.fmt.percentString(100.0 * t.getRecheckProgress()), '% tested)'].join('');
}
return t.getStateString();
},
getProgressDetails: function (controller, t) {
if (t.needsMetaData()) {
var MetaDataStatus = "retrieving";
if (t.isStopped()) {
MetaDataStatus = "needs";
};
var percent = 100 * t.getMetadataPercentComplete();
return ["Magnetized transfer - " + MetaDataStatus + " metadata (",
Transmission.fmt.percentString(percent),
"%)"
].join('');
}
var c;
var sizeWhenDone = t.getSizeWhenDone();
var totalSize = t.getTotalSize();
var is_done = t.isDone() || t.isSeeding();
if (is_done) {
if (totalSize === sizeWhenDone) {
// seed: '698.05 MiB'
c = [Transmission.fmt.size(totalSize)];
} else { // partial seed: '127.21 MiB of 698.05 MiB (18.2%)'
c = [Transmission.fmt.size(sizeWhenDone), ' of ', Transmission.fmt.size(t.getTotalSize()), ' (', t.getPercentDoneStr(), '%)'];
};
// append UL stats: ', uploaded 8.59 GiB (Ratio: 12.3)'
c.push(', uploaded ',
Transmission.fmt.size(t.getUploadedEver()),
' (Ratio ',
Transmission.fmt.ratioString(t.getUploadRatio()),
')');
} else { // not done yet
c = [Transmission.fmt.size(sizeWhenDone - t.getLeftUntilDone()),
' of ', Transmission.fmt.size(sizeWhenDone),
' (', t.getPercentDoneStr(), '%)'
];
};
// maybe append eta
if (!t.isStopped() && (!is_done || t.seedRatioLimit(controller) > 0)) {
c.push(' - ');
var eta = t.getETA();
if (eta < 0 || eta >= (999 * 60 * 60) /* arbitrary */ ) {
c.push('remaining time unknown');
} else {
c.push(Transmission.fmt.timeInterval(t.getETA()), ' remaining');
};
};
return c.join('');
},
render: function (controller, t, root) {
// name
setTextContent(root._name_container, t.getName());
// progressbar
TorrentRendererHelper.renderProgressbar(controller, t, root._progressbar);
// peer details
var has_error = t.getError() !== Torrent._ErrNone;
var e = root._peer_details_container;
$(e).toggleClass('error', has_error);
setTextContent(e, this.getPeerDetails(t));
// progress details
e = root._progress_details_container;
setTextContent(e, this.getProgressDetails(controller, t));
// pause/resume button
var is_stopped = t.isStopped();
e = root._pause_resume_button_image;
e.alt = is_stopped ? 'Resume' : 'Pause';
e.className = is_stopped ? 'torrent_resume' : 'torrent_pause';
}
};
/****
*****
*****
****/
function TorrentRendererCompact() {};
TorrentRendererCompact.prototype = {
createRow: function () {
var progressbar, details, name, root;
progressbar = TorrentRendererHelper.createProgressbar('compact');
details = document.createElement('div');
details.className = 'torrent_peer_details compact';
name = document.createElement('div');
name.className = 'torrent_name compact';
root = document.createElement('li');
root.appendChild(progressbar.element);
root.appendChild(details);
root.appendChild(name);
root.className = 'torrent compact';
root._progressbar = progressbar;
root._details_container = details;
root._name_container = name;
return root;
},
getPeerDetails: function (t) {
var c;
if ((c = t.getErrorMessage())) {
return c;
};
if (t.isDownloading()) {
var have_dn = t.getDownloadSpeed() > 0;
var have_up = t.getUploadSpeed() > 0;
if (!have_up && !have_dn) {
return 'Idle';
};
var s = '';
if (!isMobileDevice) {
s = TorrentRendererHelper.formatETA(t) + ' ';
};
if (have_dn) {
s += TorrentRendererHelper.formatDL(t);
};
if (have_dn && have_up) {
s += ' ';
};
if (have_up) {
s += TorrentRendererHelper.formatUL(t);
};
return s;
};
if (t.isSeeding()) {
return ['Ratio: ', Transmission.fmt.ratioString(t.getUploadRatio()), ', ', TorrentRendererHelper.formatUL(t)].join('');
};
return t.getStateString();
},
render: function (controller, t, root) {
// name
var is_stopped = t.isStopped();
var e = root._name_container;
$(e).toggleClass('paused', is_stopped);
setTextContent(e, t.getName());
// peer details
var has_error = t.getError() !== Torrent._ErrNone;
e = root._details_container;
$(e).toggleClass('error', has_error);
setTextContent(e, this.getPeerDetails(t));
// progressbar
TorrentRendererHelper.renderProgressbar(controller, t, root._progressbar);
}
};
/****
*****
*****
****/
function TorrentRow(view, controller, torrent) {
this.initialize(view, controller, torrent);
};
TorrentRow.prototype = {
initialize: function (view, controller, torrent) {
var row = this;
this._view = view;
this._torrent = torrent;
this._element = view.createRow();
this.render(controller);
$(this._torrent).bind('dataChanged.torrentRowListener', function () {
row.render(controller);
});
},
getElement: function () {
return this._element;
},
render: function (controller) {
var tor = this.getTorrent();
if (tor) {
this._view.render(controller, tor, this.getElement());
};
},
isSelected: function () {
return this.getElement().className.indexOf('selected') !== -1;
},
getTorrent: function () {
return this._torrent;
},
getTorrentId: function () {
return this.getTorrent().getId();
}
};