added download progress bars to GUI, and made close automatically act as stop server automatically

This commit is contained in:
Micah Lee 2014-08-27 23:52:56 -07:00
parent 5325b7b173
commit fcdcfd7c39
6 changed files with 107 additions and 32 deletions

View File

@ -14,8 +14,7 @@
"download_finished": "Download finished",
"other_page_loaded": "Other page has been loaded",
"tails_requires_root": "You must run OnionShare as root in Tails",
"close_on_finish": "Close automatically",
"close_countdown": "Closing in {0} seconds...",
"close_on_finish": "Stop server automatically",
"choose_file": "Choose a file to share",
"closing_automatically": "Closing automatically because download finished",
"error_tails_invalid_port": "Invalid value, port must be an integer",
@ -52,7 +51,6 @@
"other_page_loaded": "En annen side har blitt lastet",
"tails_requires_root": "OnionShare kan må kjøres som administrator i Tails",
"close_on_finish": "Lukk automatisk",
"close_countdown": "Lukker om {0} sekunder",
"choose_file": "Velg en fil å dele"
}, "es": {
"calculating_sha1": "Calculando suma de verificación SHA1.",
@ -70,7 +68,6 @@
"other_page_loaded": "Otra página se ha cargado",
"tails_requires_root": "Debe ejecutar OnionShare como root en Tails",
"close_on_finish": "Cerrar automáticamente.",
"close_countdown": "Cierre en {0} segundos...",
"choose_file": "Elija un archivo para compartir"
}, "fr": {
"calculating_sha1": "Calculer un hachage SHA-1.",
@ -97,7 +94,6 @@
"other_page_loaded": "Un altra pagina é stata caricata",
"tails_requires_root": "Con Tails devi avviare OnionShare come utente root",
"close_on_finish": "Chiudi automaticamente",
"close_countdown": "Chiusura in {0} secondi...",
"choose_file": "Scegli un file da condividere"
}, "nl": {
"calculating_sha1": "SHA1 controlecijfer berekenen.",
@ -115,7 +111,6 @@
"other_page_loaded": "Andere pagina is geladen",
"tails_requires_root": "Je moet OnionShare als root draaien in Tails",
"close_on_finish": "Sluit automatisch",
"close_countdown": "Sluit in {0} seconden...",
"choose_file": "Kies betsand om te delen",
"gui_copy_url": "Kopieer URL",
"closing_automatically": "Sluit nu automatisch omdat download gereed is",
@ -142,7 +137,6 @@
"other_page_loaded": "Outra página tem sido carregada",
"tails_requires_root": "Tem que rodar o OnionShare como root no Tails",
"close_on_finish": "Fechar automaticamente",
"close_countdown": "Fechando em {0} segundos...",
"choose_file": "Escolhe um arquivo para compartilhar"
}, "ru": {
"calculating_sha1": "Вычисляется SHA1 хешсумма.",
@ -160,7 +154,6 @@
"other_page_loaded": "Другая страница была загружена",
"tails_requires_root": "Вы должны запустить OnionShare с правами root в Tails",
"close_on_finish": "Закрыть автоматически",
"close_countdown": "Закроется через {0} секунд...",
"choose_file": "Выберите файл",
"gui_copy_url": "Скопировать ссылку"
}, "de": {
@ -179,7 +172,6 @@
"other_page_loaded": "Andere Seite wurde geladen",
"tails_requires_root": "Du musst Onionshare in Tails als root ausführen",
"close_on_finish": "Beende automatisch",
"close_countdown": "Beende in {0} Sekunden...",
"choose_file": "Wähle eine Datei zum teilen aus"
},"tr": {
"punching_a_hole": "Güvenlik duvarında bir yol açılıyor.",
@ -199,7 +191,6 @@
"other_page_loaded": "Diğer sayfa yüklendi",
"tails_requires_root": "Tails'da OnionShare root olarak çalışır",
"close_on_finish": "Kendiliğinden kapan",
"close_countdown": "Kapanıyor {0} saniye...",
"choose_file": "Paylaşım için bir dosya seç",
"gui_copy_url": "URL Kopyala"
}}

View File

@ -62,6 +62,15 @@ def set_stay_open(new_stay_open):
def get_stay_open():
return stay_open
gui_mode = False
def set_gui_mode(new_gui_mode):
global gui_mode
gui_mode = new_gui_mode
def get_gui_mode():
return gui_mode
def debug_mode():
import logging
@ -135,14 +144,16 @@ def download(slug_candidate):
# download is finished, close the server
if not stay_open:
print strings._("closing_automatically")
if shutdown_func is None:
raise RuntimeError('Not running with the Werkzeug Server')
shutdown_func()
if not gui_mode:
print strings._("closing_automatically")
if shutdown_func is None:
raise RuntimeError('Not running with the Werkzeug Server')
shutdown_func()
r = Response(generate())
r.headers.add('Content-Length', zip_filesize)
r.headers.add('Content-Disposition', 'attachment', filename=basename)
# guess content type
(content_type, _) = mimetypes.guess_type(basename, strict=False)
if content_type is not None:
@ -169,7 +180,8 @@ def shutdown(shutdown_slug_candidate):
return ""
def start(port, stay_open=False):
def start(port, stay_open=False, gui_mode=False):
set_stay_open(stay_open)
set_gui_mode(gui_mode)
app.run(port=port)

View File

@ -8,19 +8,43 @@ class Downloads(QtGui.QVBoxLayout):
super(Downloads, self).__init__()
self.addSpacing(10)
self.progress_bars = {}
# downloads label
self.downloads_label = QtGui.QLabel(strings._('gui_downloads'))
"""progress_bar = QtGui.QProgressBar()
progress_bar.setFormat("12.3 KiB, 17%")
progress_bar.setTextVisible(True)
progress_bar.setAlignment(QtCore.Qt.AlignHCenter)
progress_bar.setMinimum(0)
progress_bar.setMaximum(100)
progress_bar.setValue(17)"""
# hide downloads by default
self.downloads_label.hide()
# add the widgets
self.addWidget(self.downloads_label)
#self.addWidget(progress_bar)
def add_download(self, download_id, total_bytes):
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)
# start at 0
self.update_download(download_id, total_bytes, 0)
def update_download(self, download_id, total_bytes, downloaded_bytes):
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}, %p%".format(helpers.human_readable_filesize(downloaded_bytes)))

View File

@ -48,20 +48,25 @@ class OnionShareGui(QtGui.QWidget):
self.file_selection.file_list.files_updated.connect(self.server_status.update)
# downloads
downloads = Downloads()
self.downloads = Downloads()
# options
options = Options(web.stay_open)
self.options = Options(web)
# main layout
self.layout = QtGui.QVBoxLayout()
self.layout.addLayout(self.file_selection)
self.layout.addLayout(self.server_status)
self.layout.addLayout(downloads)
self.layout.addLayout(options)
self.layout.addLayout(self.downloads)
self.layout.addLayout(self.options)
self.setLayout(self.layout)
self.show()
# check for requests frequently
self.timer = QtCore.QTimer()
QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.check_for_requests)
self.timer.start(500)
def start_server(self):
# start the hidden service
try:
@ -76,7 +81,7 @@ class OnionShareGui(QtGui.QWidget):
return
# start onionshare service in new thread
t = threading.Thread(target=web.start, args=(self.app.port, self.app.stay_open))
t = threading.Thread(target=web.start, args=(self.app.port, self.app.stay_open, True))
t.daemon = True
t.start()
@ -93,6 +98,40 @@ class OnionShareGui(QtGui.QWidget):
self.server_status.stop_server_finished()
def check_for_requests(self):
self.update()
# only check for requests if the server is running
if self.server_status.status != self.server_status.STATUS_STARTED:
return
events = []
done = False
while not done:
try:
r = web.q.get(False)
events.append(r)
except web.Queue.Empty:
done = True
for event in events:
#if event["path"] != '/favicon.ico':
# pass
#if event["type"] == web.REQUEST_LOAD:
# pass
if event["type"] == web.REQUEST_DOWNLOAD:
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"])
# is the download complete?
if event["data"]["bytes"] == web.zip_filesize:
# close on finish?
if not web.get_stay_open():
self.server_status.stop_server()
def alert(msg, icon=QtGui.QMessageBox.NoIcon):
dialog = QtGui.QMessageBox()
dialog.setWindowTitle("OnionShare")

View File

@ -4,18 +4,27 @@ import common
from onionshare import strings, helpers
class Options(QtGui.QHBoxLayout):
def __init__(self, stay_open=False):
def __init__(self, web):
super(Options, self).__init__()
self.addSpacing(10)
self.web = web
# close automatically
self.close_automatically = QtGui.QCheckBox()
if stay_open:
if self.web.stay_open:
self.close_automatically.setCheckState(QtCore.Qt.Unchecked)
else:
self.close_automatically.setCheckState(QtCore.Qt.Checked)
self.close_automatically.setText(strings._("close_on_finish"))
self.connect(self.close_automatically, QtCore.SIGNAL('stateChanged(int)'), self.stay_open_changed)
# add the widgets
self.addWidget(self.close_automatically)
def stay_open_changed(self, state):
if state > 0:
self.web.set_stay_open(False)
else:
self.web.set_stay_open(True)

View File

@ -47,7 +47,6 @@ class ServerStatus(QtGui.QVBoxLayout):
self.url_label.setFont(url_font)
self.url_label.setWordWrap(True)
self.url_label.setAlignment(QtCore.Qt.AlignCenter)
self.url_label.setMargin(3)
self.copy_url_button = QtGui.QPushButton(strings._('gui_copy_url'))
self.copy_url_button.clicked.connect(self.copy_url)
url_layout = QtGui.QHBoxLayout()
@ -97,6 +96,7 @@ class ServerStatus(QtGui.QVBoxLayout):
def start_server_finished(self):
self.status = self.STATUS_STARTED
self.copy_url()
self.update()
def stop_server(self):