Merge branch 'garrettr-eta'

This commit is contained in:
Micah Lee 2016-02-12 08:58:39 -08:00
commit 191218d943
4 changed files with 108 additions and 30 deletions

View File

@ -41,5 +41,8 @@
"gui_please_wait": "Please wait...",
"error_hs_dir_cannot_create": "Cannot create hidden service dir {0:s}",
"error_hs_dir_not_writable": "Hidden service dir {0:s} is not writable",
"using_ephemeral": "Staring ephemeral Tor hidden service and awaiting publication"
"using_ephemeral": "Staring ephemeral Tor hidden service and awaiting publication",
"gui_download_progress_complete": "%p%, Time Elapsed: {0:s}",
"gui_download_progress_starting": "{0:s}, %p% (Computing ETA)",
"gui_download_progress_eta": "{0:s}, ETA: {1:s}, %p%"
}

View File

@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import os, inspect, hashlib, base64, hmac, platform, zipfile, tempfile
from itertools import izip
import math
import time
# hack to make unicode filenames work (#141)
import sys
@ -112,6 +114,44 @@ def human_readable_filesize(b):
return '{0:.1f} {1:s}'.format(round(b, 1), units[u])
def format_seconds(seconds):
"""Return a human-readable string of the format 1d2h3m4s"""
seconds_in_a_minute = 60
seconds_in_an_hour = seconds_in_a_minute * 60
seconds_in_a_day = seconds_in_an_hour * 24
days = math.floor(seconds / seconds_in_a_day)
hour_seconds = seconds % seconds_in_a_day
hours = math.floor(hour_seconds / seconds_in_an_hour)
minute_seconds = hour_seconds % seconds_in_an_hour
minutes = math.floor(minute_seconds / seconds_in_a_minute)
remaining_seconds = minute_seconds % seconds_in_a_minute
seconds = math.ceil(remaining_seconds)
human_readable = []
if days > 0:
human_readable.append("{}d".format(int(days)))
if hours > 0:
human_readable.append("{}h".format(int(hours)))
if minutes > 0:
human_readable.append("{}m".format(int(minutes)))
if seconds > 0:
human_readable.append("{}s".format(int(seconds)))
return ''.join(human_readable)
def estimated_time_remaining(bytes_downloaded, total_bytes, started):
now = time.time()
time_elapsed = now - started # in seconds
download_rate = bytes_downloaded / time_elapsed
remaining_bytes = total_bytes - bytes_downloaded
eta = remaining_bytes / download_rate
return format_seconds(eta)
def is_root():
"""
Returns if user is root.

View File

@ -17,12 +17,68 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import time
from PyQt4 import QtCore, QtGui
import common
from onionshare import strings, helpers
class Download(object):
def __init__(self, download_id, total_bytes):
self.download_id = download_id
self.started = time.time()
self.total_bytes = total_bytes
self.downloaded_bytes = 0
# make a new progress bar
self.progress_bar = QtGui.QProgressBar()
self.progress_bar.setTextVisible(True)
self.progress_bar.setAlignment(QtCore.Qt.AlignHCenter)
self.progress_bar.setMinimum(0)
self.progress_bar.setMaximum(total_bytes)
self.progress_bar.setValue(0)
self.progress_bar.setStyleSheet(
"QProgressBar::chunk { background-color: #05B8CC; }")
self.progress_bar.total_bytes = total_bytes
# start at 0
self.update(0)
def update(self, downloaded_bytes):
self.downloaded_bytes = downloaded_bytes
self.progress_bar.setValue(downloaded_bytes)
if downloaded_bytes == self.progress_bar.total_bytes:
pb_fmt = strings._('gui_download_progress_complete').format(
helpers.format_seconds(time.time() - self.started))
else:
elapsed = time.time() - self.started
if elapsed < 10:
# Wait a couple of seconds for the download rate to stabilize.
# This prevents an "Windows copy dialog"-esque experience at
# the beginning of the download.
pb_fmt = strings._('gui_download_progress_starting').format(
helpers.human_readable_filesize(downloaded_bytes))
else:
pb_fmt = strings._('gui_download_progress_eta').format(
helpers.human_readable_filesize(downloaded_bytes),
self.estimated_time_remaining)
self.progress_bar.setFormat(pb_fmt)
def cancel(self):
self.progress_bar.setFormat(strings._('gui_canceled'))
@property
def estimated_time_remaining(self):
return helpers.estimated_time_remaining(self.downloaded_bytes,
self.total_bytes,
self.started)
class Downloads(QtGui.QVBoxLayout):
"""
The downloads chunk of the GUI. This lists all of the active download
@ -31,7 +87,7 @@ class Downloads(QtGui.QVBoxLayout):
def __init__(self):
super(Downloads, self).__init__()
self.progress_bars = {}
self.downloads = {}
# downloads label
self.downloads_label = QtGui.QLabel(strings._('gui_downloads', True))
@ -46,40 +102,19 @@ class Downloads(QtGui.QVBoxLayout):
"""
self.downloads_label.show()
# make a new progress bar
pb = QtGui.QProgressBar()
pb.setTextVisible(True)
pb.setAlignment(QtCore.Qt.AlignHCenter)
pb.setMinimum(0)
pb.setMaximum(total_bytes)
pb.setValue(0)
pb.setStyleSheet("QProgressBar::chunk { background-color: #05B8CC; }")
pb.total_bytes = total_bytes
# add it to the list
self.progress_bars[download_id] = pb
self.addWidget(pb)
download = Download(download_id, total_bytes)
self.downloads[download_id] = download
self.addWidget(download.progress_bar)
# start at 0
self.update_download(download_id, total_bytes, 0)
def update_download(self, download_id, total_bytes, downloaded_bytes):
def update_download(self, download_id, downloaded_bytes):
"""
Update the progress of a download progress bar.
"""
if download_id not in self.progress_bars:
self.add_download(download_id, total_bytes)
pb = self.progress_bars[download_id]
pb.setValue(downloaded_bytes)
if downloaded_bytes == pb.total_bytes:
pb.setFormat("%p%")
else:
pb.setFormat("{0:s}, %p%".format(helpers.human_readable_filesize(downloaded_bytes)))
self.downloads[download_id].update(downloaded_bytes)
def cancel_download(self, download_id):
"""
Update a download progress bar to show that it has been canceled.
"""
pb = self.progress_bars[download_id]
pb.setFormat(strings._('gui_canceled'))
self.downloads[download_id].cancel()

View File

@ -216,7 +216,7 @@ class OnionShareGui(QtGui.QWidget):
self.downloads.add_download(event["data"]["id"], web.zip_filesize)
elif event["type"] == web.REQUEST_PROGRESS:
self.downloads.update_download(event["data"]["id"], web.zip_filesize, event["data"]["bytes"])
self.downloads.update_download(event["data"]["id"], event["data"]["bytes"])
# is the download complete?
if event["data"]["bytes"] == web.zip_filesize: