diff --git a/onionshare/common.py b/onionshare/common.py index ad2f4574..646cbba2 100644 --- a/onionshare/common.py +++ b/onionshare/common.py @@ -322,6 +322,19 @@ class Common(object): font-size: 11px; }""", + # Recieve mode and child widget styles + 'receive_file': """ + QWidget { + background-color: #ffffff; + } + """, + + 'receive_file_size': """ + QLabel { + color: #666666; + font-size: 11px; + }""", + # Settings dialog 'settings_version': """ QLabel { diff --git a/onionshare/web.py b/onionshare/web.py index a3144eb2..4f521bf5 100644 --- a/onionshare/web.py +++ b/onionshare/web.py @@ -707,9 +707,16 @@ class ReceiveModeRequest(Request): self.upload_id = self.web.upload_count self.web.upload_count += 1 + # Figure out the content length + try: + self.content_length = int(self.headers['Content-Length']) + except: + self.content_length = 0 + # Tell the GUI self.web.add_request(Web.REQUEST_STARTED, self.path, { - 'id': self.upload_id + 'id': self.upload_id, + 'content_length': self.content_length }) def _get_file_stream(self, total_content_length, content_type, filename=None, content_length=None): @@ -726,8 +733,8 @@ class ReceiveModeRequest(Request): }) self.progress[filename] = { - 'total_bytes': total_content_length, - 'uploaded_bytes': 0 + 'uploaded_bytes': 0, + 'complete': False } if len(self.progress) > 0: @@ -749,10 +756,14 @@ class ReceiveModeRequest(Request): Keep track of the bytes uploaded so far for all files. """ if self.upload_request: - self.progress[filename]['uploaded_bytes'] += length + # The final write, when upload is complete, length will be 0 + if length == 0: + self.progress[filename]['complete'] = True + else: + self.progress[filename]['uploaded_bytes'] += length + uploaded = self.web.common.human_readable_filesize(self.progress[filename]['uploaded_bytes']) - total = self.web.common.human_readable_filesize(self.progress[filename]['total_bytes']) - print('{}/{} - {} '.format(uploaded, total, filename), end='\r') + print('{} - {} '.format(uploaded, filename), end='\r') # Update the GUI on the upload progress self.web.add_request(Web.REQUEST_PROGRESS, self.path, { diff --git a/onionshare_gui/receive_mode/__init__.py b/onionshare_gui/receive_mode/__init__.py index 000850d2..0d2ef61b 100644 --- a/onionshare_gui/receive_mode/__init__.py +++ b/onionshare_gui/receive_mode/__init__.py @@ -135,7 +135,7 @@ class ReceiveMode(Mode): """ Handle REQUEST_STARTED event. """ - self.uploads.add(event["data"]["id"]) + self.uploads.add(event["data"]["id"], event["data"]["content_length"]) self.uploads_in_progress += 1 self.update_uploads_in_progress() diff --git a/onionshare_gui/receive_mode/uploads.py b/onionshare_gui/receive_mode/uploads.py index 702912c3..2a999f86 100644 --- a/onionshare_gui/receive_mode/uploads.py +++ b/onionshare_gui/receive_mode/uploads.py @@ -32,7 +32,48 @@ class File(QtWidgets.QWidget): self.started = datetime.now() # Filename label - self.label = QtWidgets.QLabel(self.filename) + self.filename_label = QtWidgets.QLabel(self.filename) + + # File size label + self.filesize_label = QtWidgets.QLabel() + self.filesize_label.setStyleSheet(self.common.css['receive_file_size']) + self.filesize_label.hide() + + # Folder button + folder_pixmap = QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/open_folder.png'))) + folder_icon = QtGui.QIcon(folder_pixmap) + self.folder_button = QtWidgets.QPushButton() + self.folder_button.setIcon(folder_icon) + self.folder_button.setIconSize(folder_pixmap.rect().size()) + self.folder_button.setFlat(True) + self.folder_button.hide() + + # Layouts + layout = QtWidgets.QHBoxLayout() + layout.addWidget(self.filename_label) + layout.addWidget(self.filesize_label) + layout.addStretch() + layout.addWidget(self.folder_button) + self.setLayout(layout) + + def update(self, uploaded_bytes, complete): + self.filesize_label.setText(self.common.human_readable_filesize(uploaded_bytes)) + self.filesize_label.show() + + if complete: + self.folder_button.show() + + +class Upload(QtWidgets.QWidget): + def __init__(self, common, upload_id, content_length): + super(Upload, self).__init__() + self.common = common + self.upload_id = upload_id + self.content_length = content_length + self.started = datetime.now() + + # Label + self.label = QtWidgets.QLabel(strings._('gui_upload_in_progress', True).format(self.started.strftime("%b %d, %I:%M%p"))) # Progress bar self.progress_bar = QtWidgets.QProgressBar() @@ -43,79 +84,64 @@ class File(QtWidgets.QWidget): self.progress_bar.setValue(0) self.progress_bar.setStyleSheet(self.common.css['downloads_uploads_progress_bar']) - # Folder button - self.folder_button = QtWidgets.QPushButton("open folder") - self.folder_button.hide() + # This layout contains file widgets + self.files_layout = QtWidgets.QVBoxLayout() + self.files_layout.setContentsMargins(0, 0, 0, 0) + files_widget = QtWidgets.QWidget() + files_widget.setStyleSheet(self.common.css['receive_file']) + files_widget.setLayout(self.files_layout) - # Layouts - info_layout = QtWidgets.QVBoxLayout() - info_layout.addWidget(self.label) - info_layout.addWidget(self.progress_bar) - - # The horizontal layout has info to the left, folder button to the right - layout = QtWidgets.QHBoxLayout() - layout.addLayout(info_layout) - layout.addWidget(self.folder_button) + # Layout + layout = QtWidgets.QVBoxLayout() + layout.addWidget(self.label) + layout.addWidget(self.progress_bar) + layout.addWidget(files_widget) + layout.addStretch() self.setLayout(layout) - def update(self, total_bytes, uploaded_bytes): - print('total_bytes: {}, uploaded_bytes: {}'.format(total_bytes, uploaded_bytes)) - if total_bytes == uploaded_bytes: - # Hide the progress bar, show the folder button - self.progress_bar.hide() - self.folder_button.show() - - else: - # Update the progress bar - self.progress_bar.setMaximum(total_bytes) - self.progress_bar.setValue(uploaded_bytes) - - elapsed = datetime.now() - self.started - if elapsed.seconds < 10: - pb_fmt = strings._('gui_download_upload_progress_starting').format( - self.common.human_readable_filesize(uploaded_bytes)) - else: - estimated_time_remaining = self.common.estimated_time_remaining( - uploaded_bytes, - total_bytes, - started.timestamp()) - pb_fmt = strings._('gui_download_upload_progress_eta').format( - self.common.human_readable_filesize(uploaded_bytes), - estimated_time_remaining) - - -class Upload(QtWidgets.QGroupBox): - def __init__(self, common, upload_id): - super(Upload, self).__init__() - self.common = common - - self.upload_id = upload_id - self.started = datetime.now() - self.uploaded_bytes = 0 - - # Set the title of the title of the group box based on the start time - self.setTitle(strings._('gui_upload_in_progress', True).format(self.started.strftime("%b %m, %I:%M%p"))) - - # The layout contains file widgets - self.layout = QtWidgets.QVBoxLayout() - self.setLayout(self.layout) - # We're also making a dictionary of file widgets, to make them easier to access self.files = {} def update(self, progress): """ - Using the progress from Web, make sure all the file progress bars exist, - and update their progress + Using the progress from Web, update the progress bar and file size labels + for each file """ + total_uploaded_bytes = 0 + for filename in progress: + total_uploaded_bytes += progress[filename]['uploaded_bytes'] + + if total_uploaded_bytes == self.content_length: + # Hide the progress bar, show the folder button + self.progress_bar.hide() + self.folder_button.show() + + else: + # Update the progress bar + self.progress_bar.setMaximum(self.content_length) + self.progress_bar.setValue(total_uploaded_bytes) + + elapsed = datetime.now() - self.started + if elapsed.seconds < 10: + pb_fmt = strings._('gui_download_upload_progress_starting').format( + self.common.human_readable_filesize(total_uploaded_bytes)) + else: + estimated_time_remaining = self.common.estimated_time_remaining( + total_uploaded_bytes, + self.content_length, + started.timestamp()) + pb_fmt = strings._('gui_download_upload_progress_eta').format( + self.common.human_readable_filesize(total_uploaded_bytes), + estimated_time_remaining) + for filename in progress: # Add a new file if needed if filename not in self.files: self.files[filename] = File(self.common, filename) - self.layout.addWidget(self.files[filename]) + self.files_layout.addWidget(self.files[filename]) # Update the file - self.files[filename].update(progress[filename]['total_bytes'], progress[filename]['uploaded_bytes']) + self.files[filename].update(progress[filename]['uploaded_bytes'], progress[filename]['complete']) class Uploads(QtWidgets.QScrollArea): @@ -154,16 +180,16 @@ class Uploads(QtWidgets.QScrollArea): widget.setLayout(layout) self.setWidget(widget) - def add(self, upload_id): + def add(self, upload_id, content_length): """ Add a new upload. """ - self.common.log('Uploads', 'add', 'upload_id: {}'.format(upload_id)) + self.common.log('Uploads', 'add', 'upload_id: {}, content_length: {}'.format(upload_id, content_length)) # Hide the no_uploads_label self.no_uploads_label.hide() # Add it to the list - upload = Upload(self.common, upload_id) + upload = Upload(self.common, upload_id, content_length) self.uploads[upload_id] = upload self.uploads_layout.addWidget(upload) diff --git a/share/images/open_folder.png b/share/images/open_folder.png new file mode 100644 index 00000000..0a734c41 Binary files /dev/null and b/share/images/open_folder.png differ diff --git a/share/locale/en.json b/share/locale/en.json index 4b8c2c04..9874d710 100644 --- a/share/locale/en.json +++ b/share/locale/en.json @@ -191,6 +191,6 @@ "gui_uploads": "Upload History", "gui_uploads_window_tooltip": "Show/hide uploads", "gui_no_uploads": "No uploads yet.", - "gui_upload_in_progress": "Upload in progress, started {}", + "gui_upload_in_progress": "Upload Started {}", "gui_upload_finished": "Uploaded {} to {}" }