file transfers fixes - part 3

This commit is contained in:
ingvar1995 2018-05-17 00:02:22 +03:00
parent c0a143c817
commit a96f6d2928
12 changed files with 79 additions and 74 deletions

View file

@ -323,7 +323,7 @@ class App:
self._toxes, self._version) self._toxes, self._version)
self._tray = tray.init_tray(profile, self._settings, self._ms) self._tray = tray.init_tray(profile, self._settings, self._ms)
self._ms.set_dependencies(widgets_factory, self._tray, self._contacts_manager, self._messenger, profile, self._ms.set_dependencies(widgets_factory, self._tray, self._contacts_manager, self._messenger, profile,
self._plugin_loader) self._plugin_loader, self._file_transfer_handler)
self._tray.show() self._tray.show()
self._ms.show() self._ms.show()

View file

@ -8,9 +8,13 @@ class Event:
def __iadd__(self, callback): def __iadd__(self, callback):
self.add_callback(callback) self.add_callback(callback)
return self
def __isub__(self, callback): def __isub__(self, callback):
self.remove_callback(callback) self.remove_callback(callback)
return self
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
for callback in self._callbacks: for callback in self._callbacks:
callback(*args, **kwargs) callback(*args, **kwargs)

View file

@ -101,6 +101,9 @@ class Contact(basecontact.BaseContact):
for message in self._corr: for message in self._corr:
message.remove_widget() message.remove_widget()
def get_message(self, _filter):
return list(filter(lambda m: _filter(m), self._corr))[0]
@staticmethod @staticmethod
def _get_text_message(params): def _get_text_message(params):
(message, author_type, author_name, unix_time, message_type, unique_id) = params (message, author_type, author_name, unix_time, message_type, unique_id) = params

View file

@ -1,8 +1,4 @@
import utils.util as util
import utils.ui as util_ui
from contacts.friend import Friend from contacts.friend import Friend
from PyQt5 import QtCore, QtGui
from wrapper.toxcore_enums_and_consts import *
from messenger.messages import * from messenger.messages import *
@ -71,10 +67,10 @@ class ContactsManager:
self._screen.messageEdit.clear() self._screen.messageEdit.clear()
return return
try: try:
# self.send_typing(False) # TODO: fix
self._screen.typing.setVisible(False) self._screen.typing.setVisible(False)
current_contact = self.get_curr_contact() current_contact = self.get_curr_contact()
if current_contact is not None: if current_contact is not None:
current_contact.typing_notification_handler.send(self._tox, False)
current_contact.remove_messages_widgets() # TODO: if required current_contact.remove_messages_widgets() # TODO: if required
self._unsubscribe_from_events(current_contact) self._unsubscribe_from_events(current_contact)
@ -96,6 +92,11 @@ class ContactsManager:
contact.load_corr() contact.load_corr()
corr = contact.get_corr()[-PAGE_SIZE:] corr = contact.get_corr()[-PAGE_SIZE:]
for message in corr: for message in corr:
if message.type == MESSAGE_TYPE['FILE_TRANSFER']:
self._messages_items_factory.create_file_transfer_item(message)
elif message.type == MESSAGE_TYPE['INLINE']:
self._messages_items_factory.create_inline_item(message.data)
else:
self._messages_items_factory.create_message_item(message) self._messages_items_factory.create_message_item(message)
# if value in self._call: # if value in self._call:
# self._screen.active_call() # self._screen.active_call()

View file

@ -18,14 +18,13 @@ class Friend(contact.Contact):
# File transfers support # File transfers support
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def update_transfer_data(self, file_number, status, inline=None): def update_transfer_data(self, file_number, inline): # TODO: rewrite
""" """
Update status of active transfer and load inline if needed Update status of active transfer and load inline if needed
""" """
try: try:
tr = list(filter(lambda x: x.get_type() == MESSAGE_TYPE['FILE_TRANSFER'] and x.is_active(file_number), tr = list(filter(lambda x: x.get_type() == MESSAGE_TYPE['FILE_TRANSFER'] and x.is_active(file_number),
self._corr))[0] self._corr))[0]
tr.set_status(status)
i = self._corr.index(tr) i = self._corr.index(tr)
if inline: # inline was loaded if inline: # inline was loaded
self._corr.insert(i, inline) self._corr.insert(i, inline)

View file

@ -1,7 +1,7 @@
from wrapper.toxcore_enums_and_consts import TOX_FILE_KIND, TOX_FILE_CONTROL from wrapper.toxcore_enums_and_consts import TOX_FILE_KIND, TOX_FILE_CONTROL
from os.path import basename, getsize, exists, dirname from os.path import basename, getsize, exists, dirname
from os import remove, rename, chdir from os import remove, rename, chdir
from time import time, sleep from time import time
from wrapper.tox import Tox from wrapper.tox import Tox
from common.event import Event from common.event import Event
@ -47,7 +47,7 @@ class FileTransfer:
self._done = 0 self._done = 0
self._state_changed_event = Event() self._state_changed_event = Event()
self._finished_event = Event() self._finished_event = Event()
self._file_id = None self._file_id = self._file = None
def set_tox(self, tox): def set_tox(self, tox):
self._tox = tox self._tox = tox
@ -85,13 +85,12 @@ class FileTransfer:
def cancel(self): def cancel(self):
self.send_control(TOX_FILE_CONTROL['CANCEL']) self.send_control(TOX_FILE_CONTROL['CANCEL'])
if hasattr(self, '_file'): if self._file is not None:
self._file.close() self._file.close()
self.signal() self.signal()
def cancelled(self): def cancelled(self):
if hasattr(self, '_file'): if self._file is not None:
sleep(0.1)
self._file.close() self._file.close()
self.state = FILE_TRANSFER_STATE['CANCELLED'] self.state = FILE_TRANSFER_STATE['CANCELLED']
self.signal() self.signal()

View file

@ -1,8 +1,5 @@
from file_transfers.file_transfers import *
from messenger.messages import * from messenger.messages import *
from history.database import MESSAGE_AUTHOR
from ui.contact_items import * from ui.contact_items import *
from PyQt5 import QtWidgets
import utils.util as util import utils.util as util
@ -46,13 +43,13 @@ class FileTransfersHandler:
self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL']) self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL'])
return return
self._tox.file_seek(friend_number, file_number, pos) self._tox.file_seek(friend_number, file_number, pos)
self.accept_transfer(None, data[0], friend_number, file_number, size, False, pos) self.accept_transfer(data[0], friend_number, file_number, size, False, pos)
elif inline and size < 1024 * 1024: elif inline and size < 1024 * 1024:
self.accept_transfer(None, '', friend_number, file_number, size, True) self.accept_transfer('', friend_number, file_number, size, True)
elif auto: elif auto:
path = self._settings['auto_accept_path'] or util.curr_directory() path = self._settings['auto_accept_path'] or util.curr_directory()
self.accept_transfer(None, path + '/' + file_name, friend_number, file_number, size) self.accept_transfer(path + '/' + file_name, friend_number, file_number, size)
else: else:
accepted = False accepted = False
@ -66,8 +63,6 @@ class FileTransfersHandler:
:param file_number: file number :param file_number: file number
:param already_cancelled: was cancelled by friend :param already_cancelled: was cancelled by friend
""" """
i = self._get_friend_by_number(friend_number).update_transfer_data(file_number,
FILE_TRANSFER_STATE['CANCELLED'])
if (friend_number, file_number) in self._file_transfers: if (friend_number, file_number) in self._file_transfers:
tr = self._file_transfers[(friend_number, file_number)] tr = self._file_transfers[(friend_number, file_number)]
if not already_cancelled: if not already_cancelled:
@ -77,15 +72,8 @@ class FileTransfersHandler:
if (friend_number, file_number) in self._file_transfers: if (friend_number, file_number) in self._file_transfers:
del tr del tr
del self._file_transfers[(friend_number, file_number)] del self._file_transfers[(friend_number, file_number)]
else: elif not already_cancelled:
if not already_cancelled:
self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL']) self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL'])
if friend_number == self.get_active_number() and self.is_active_a_friend():
tmp = self._messages.count() + i
if tmp >= 0:
self._messages.itemWidget(
self._messages.item(tmp)).update_transfer_state(FILE_TRANSFER_STATE['CANCELLED'],
0, -1)
def cancel_not_started_transfer(self, cancel_time): def cancel_not_started_transfer(self, cancel_time):
self.get_curr_friend().delete_one_unsent_file(cancel_time) self.get_curr_friend().delete_one_unsent_file(cancel_time)
@ -96,15 +84,11 @@ class FileTransfersHandler:
""" """
tr = self._file_transfers[(friend_number, file_number)] tr = self._file_transfers[(friend_number, file_number)]
tr.pause(by_friend) tr.pause(by_friend)
t = FILE_TRANSFER_STATE['PAUSED_BY_FRIEND'] if by_friend else FILE_TRANSFER_STATE['PAUSED_BY_USER']
self._get_friend_by_number(friend_number).update_transfer_data(file_number, t)
def resume_transfer(self, friend_number, file_number, by_friend=False): def resume_transfer(self, friend_number, file_number, by_friend=False):
""" """
Resume transfer with specified data Resume transfer with specified data
""" """
# self.get_friend_by_number(friend_number).update_transfer_data(file_number,
# TOX_FILE_TRANSFER_STATE['RUNNING'])
tr = self._file_transfers[(friend_number, file_number)] tr = self._file_transfers[(friend_number, file_number)]
if by_friend: if by_friend:
tr.state = FILE_TRANSFER_STATE['RUNNING'] tr.state = FILE_TRANSFER_STATE['RUNNING']
@ -112,9 +96,8 @@ class FileTransfersHandler:
else: else:
tr.send_control(TOX_FILE_CONTROL['RESUME']) tr.send_control(TOX_FILE_CONTROL['RESUME'])
def accept_transfer(self, item, path, friend_number, file_number, size, inline=False, from_position=0): def accept_transfer(self, path, friend_number, file_number, size, inline=False, from_position=0):
""" """
:param item: transfer item.
:param path: path for saving :param path: path for saving
:param friend_number: friend number :param friend_number: friend number
:param file_number: file number :param file_number: file number
@ -122,32 +105,23 @@ class FileTransfersHandler:
:param inline: is inline image :param inline: is inline image
:param from_position: position for start :param from_position: position for start
""" """
path, file_name = os.path.split(path) path = self._generate_valid_path(path, from_position)
new_file_name, i = file_name, 1 friend = self._get_friend_by_number(friend_number)
if not from_position:
while os.path.isfile(path + '/' + new_file_name): # file with same name already exists
if '.' in file_name: # has extension
d = file_name.rindex('.')
else: # no extension
d = len(file_name)
new_file_name = file_name[:d] + ' ({})'.format(i) + file_name[d:]
i += 1
path = os.path.join(path, new_file_name)
if not inline: if not inline:
rt = ReceiveTransfer(path, self._tox, friend_number, size, file_number, from_position) rt = ReceiveTransfer(path, self._tox, friend_number, size, file_number, from_position)
else: else:
rt = ReceiveToBuffer(self._tox, friend_number, size, file_number) rt = ReceiveToBuffer(self._tox, friend_number, size, file_number)
rt.set_transfer_finished_handler(self.transfer_finished) rt.set_transfer_finished_handler(self.transfer_finished)
message = friend.get_message(lambda m: m.type == MESSAGE_TYPE['FILE_TRANSFER']
and m.state == FILE_TRANSFER_STATE['INCOMING_NOT_STARTED']
and m.file_number == file_number)
rt.set_state_changed_handler(message.transfer_updated)
self._file_transfers[(friend_number, file_number)] = rt self._file_transfers[(friend_number, file_number)] = rt
self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['RESUME']) self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['RESUME'])
if item is not None:
rt.set_state_changed_handler(item.update_transfer_state)
self._get_friend_by_number(friend_number).update_transfer_data(file_number,
FILE_TRANSFER_STATE['RUNNING'])
def send_screenshot(self, data, friend_number): def send_screenshot(self, data, friend_number):
""" """
Send screenshot to current active friend Send screenshot
:param data: raw data - png :param data: raw data - png
""" """
self.send_inline(data, 'toxygen_inline.png', friend_number) self.send_inline(data, 'toxygen_inline.png', friend_number)
@ -169,7 +143,8 @@ class FileTransfersHandler:
st.set_transfer_finished_handler(self.transfer_finished) st.set_transfer_finished_handler(self.transfer_finished)
file_number = st.get_file_number() file_number = st.get_file_number()
self._file_transfers[(friend.number, file_number)] = st self._file_transfers[(friend.number, file_number)] = st
self._file_transfers_message_service.add_outgoing_transfer_message(friend, st.size, file_name, file_number) tm = self._file_transfers_message_service.add_outgoing_transfer_message(friend, st.size, file_name, file_number)
st.set_state_changed_handler(tm.transfer_updated)
def send_file(self, path, friend_number, is_resend=False, file_id=None): def send_file(self, path, friend_number, is_resend=False, file_id=None):
""" """
@ -192,7 +167,8 @@ class FileTransfersHandler:
file_number = st.get_file_number() file_number = st.get_file_number()
self._file_transfers[(friend_number, file_number)] = st self._file_transfers[(friend_number, file_number)] = st
file_name = os.path.basename(path) file_name = os.path.basename(path)
self._file_transfers_message_service.add_outgoing_transfer_message(friend, st.size, file_name, file_number) tm = self._file_transfers_message_service.add_outgoing_transfer_message(friend, st.size, file_name, file_number)
st.set_state_changed_handler(tm.transfer_updated)
def incoming_chunk(self, friend_number, file_number, position, data): def incoming_chunk(self, friend_number, file_number, position, data):
""" """
@ -214,13 +190,8 @@ class FileTransfersHandler:
elif t is ReceiveToBuffer or (t is SendFromBuffer and self._settings['allow_inline']): # inline image elif t is ReceiveToBuffer or (t is SendFromBuffer and self._settings['allow_inline']): # inline image
print('inline') print('inline')
inline = InlineImage(transfer.get_data()) inline = InlineImage(transfer.get_data())
index = self._get_friend_by_number(friend_number).update_transfer_data(file_number, index = self._get_friend_by_number(friend_number).update_transfer_data(file_number, inline)
FILE_TRANSFER_STATE['FINISHED'],
inline)
self._file_transfers_message_service.add_inline_message(transfer, index) self._file_transfers_message_service.add_inline_message(transfer, index)
elif t is not SendAvatar:
self._get_friend_by_number(friend_number).update_transfer_data(file_number,
FILE_TRANSFER_STATE['FINISHED'])
del self._file_transfers[(friend_number, file_number)] del self._file_transfers[(friend_number, file_number)]
del transfer del transfer
@ -279,3 +250,19 @@ class FileTransfersHandler:
def _get_friend_by_number(self, friend_number): def _get_friend_by_number(self, friend_number):
return self._contact_provider.get_friend_by_number(friend_number) return self._contact_provider.get_friend_by_number(friend_number)
@staticmethod
def _generate_valid_path(path, from_position):
path, file_name = os.path.split(path)
new_file_name, i = file_name, 1
if not from_position:
while os.path.isfile(path + '/' + new_file_name): # file with same name already exists
if '.' in file_name: # has extension
d = file_name.rindex('.')
else: # no extension
d = len(file_name)
new_file_name = file_name[:d] + ' ({})'.format(i) + file_name[d:]
i += 1
path = os.path.join(path, new_file_name)
return path

View file

@ -24,6 +24,8 @@ class FileTransfersMessagesService:
friend.append_message(tm) friend.append_message(tm)
return tm
def add_outgoing_transfer_message(self, friend, size, file_name, file_number): def add_outgoing_transfer_message(self, friend, size, file_name, file_number):
author = MessageAuthor(self._profile.name, MESSAGE_AUTHOR['ME']) author = MessageAuthor(self._profile.name, MESSAGE_AUTHOR['ME'])
status = FILE_TRANSFER_STATE['OUTGOING_NOT_STARTED'] status = FILE_TRANSFER_STATE['OUTGOING_NOT_STARTED']
@ -35,6 +37,8 @@ class FileTransfersMessagesService:
friend.append_message(tm) friend.append_message(tm)
return tm
def add_inline_message(self, transfer, index): def add_inline_message(self, transfer, index):
if self._is_active(transfer.friend_number): if self._is_active(transfer.friend_number):
count = self._messages.count() count = self._messages.count()

View file

@ -164,6 +164,11 @@ class TransferMessage(Message):
file_name = property(get_file_name) file_name = property(get_file_name)
def transfer_updated(self, state, percentage, time):
self._state = state
if self._widget is not None:
self._widget.update_transfer_state(state, percentage, time)
def _create_widget(self, *args): def _create_widget(self, *args):
return FileTransferItem(self, *args) return FileTransferItem(self, *args)

View file

@ -45,7 +45,7 @@ class MessagesItemsFactory:
return item return item
def create_inline_item(self, data, append, position=0): def create_inline_item(self, data, append=True, position=0):
elem = QtWidgets.QListWidgetItem() elem = QtWidgets.QListWidgetItem()
item = InlineImageItem(data, self._messages.width(), elem) item = InlineImageItem(data, self._messages.width(), elem)
elem.setSizeHint(QtCore.QSize(self._messages.width(), item.height())) elem.setSizeHint(QtCore.QSize(self._messages.width(), item.height()))
@ -57,7 +57,7 @@ class MessagesItemsFactory:
return item return item
def create_unsent_file_item(self, tm, append): def create_unsent_file_item(self, tm, append=True):
item = UnsentFileItem(self._file_transfers_handler, self._settings, tm, self._messages.width()) item = UnsentFileItem(self._file_transfers_handler, self._settings, tm, self._messages.width())
elem = QtWidgets.QListWidgetItem() elem = QtWidgets.QListWidgetItem()
elem.setSizeHint(QtCore.QSize(self._messages.width() - 30, 34)) elem.setSizeHint(QtCore.QSize(self._messages.width() - 30, 34))
@ -70,7 +70,7 @@ class MessagesItemsFactory:
return item return item
def create_file_transfer_item(self, tm, append=True): def create_file_transfer_item(self, tm, append=True):
item = tm.get_widget(self._file_transfers_handler, self._settings, tm, self._messages.width()) item = tm.get_widget(self._file_transfers_handler, self._settings, self._messages.width())
elem = QtWidgets.QListWidgetItem() elem = QtWidgets.QListWidgetItem()
elem.setSizeHint(QtCore.QSize(self._messages.width() - 30, 34)) elem.setSizeHint(QtCore.QSize(self._messages.width() - 30, 34))
if append: if append:

View file

@ -19,14 +19,17 @@ class MainWindow(QtWidgets.QMainWindow):
self.setAcceptDrops(True) self.setAcceptDrops(True)
self._saved = False self._saved = False
self._profile = None self._profile = None
self._file_transfer_handler = None
self.initUI() self.initUI()
def set_dependencies(self, widget_factory, tray, contacts_manager, messenger, profile, plugins_loader): def set_dependencies(self, widget_factory, tray, contacts_manager, messenger, profile, plugins_loader,
file_transfer_handler):
self._widget_factory = widget_factory self._widget_factory = widget_factory
self._tray = tray self._tray = tray
self._contacts_manager = contacts_manager self._contacts_manager = contacts_manager
self._profile = profile self._profile = profile
self._plugins_loader = plugins_loader self._plugins_loader = plugins_loader
self._file_transfer_handler = file_transfer_handler
self.messageEdit.set_messenger(messenger) self.messageEdit.set_messenger(messenger)
def show(self): def show(self):
@ -519,7 +522,7 @@ class MainWindow(QtWidgets.QMainWindow):
caption = util_ui.tr('Choose file') caption = util_ui.tr('Choose file')
name = util_ui.file_dialog(caption) name = util_ui.file_dialog(caption)
if name[0]: if name[0]:
self._contacts_manager.send_file(name[0], self._contacts_manager.get_contact().number) self._file_transfer_handler.send_file(name[0], self._contacts_manager.get_active_number())
def send_screenshot(self, hide=False): def send_screenshot(self, hide=False):
self.menu.hide() self.menu.hide()

View file

@ -218,10 +218,10 @@ class MessageItem(QtWidgets.QWidget):
class FileTransferItem(QtWidgets.QListWidget): class FileTransferItem(QtWidgets.QListWidget):
def __init__(self, file_transfers_handler, settings, transfer_message, width, parent=None): def __init__(self, transfer_message, file_transfer_handler, settings, width, parent=None):
QtWidgets.QListWidget.__init__(self, parent) QtWidgets.QListWidget.__init__(self, parent)
self._file_transfers_handler = file_transfers_handler self._file_transfer_handler = file_transfer_handler
self.resize(QtCore.QSize(width, 34)) self.resize(QtCore.QSize(width, 34))
if transfer_message.state == FILE_TRANSFER_STATE['CANCELLED']: if transfer_message.state == FILE_TRANSFER_STATE['CANCELLED']:
self.setStyleSheet('QListWidget { border: 1px solid #B40404; }') self.setStyleSheet('QListWidget { border: 1px solid #B40404; }')
@ -308,7 +308,7 @@ class FileTransferItem(QtWidgets.QListWidget):
self.paused = False self.paused = False
def cancel_transfer(self, friend_number, file_number): def cancel_transfer(self, friend_number, file_number):
self._file_transfers_handler.cancel_transfer(friend_number, file_number) self._file_transfer_handler.cancel_transfer(friend_number, file_number)
self.setStyleSheet('QListWidget { border: 1px solid #B40404; }') self.setStyleSheet('QListWidget { border: 1px solid #B40404; }')
self.cancel.setVisible(False) self.cancel.setVisible(False)
self.accept_or_pause.setVisible(False) self.accept_or_pause.setVisible(False)
@ -319,7 +319,7 @@ class FileTransferItem(QtWidgets.QListWidget):
directory = util_ui.directory_dialog(util_ui.tr('Choose folder')) directory = util_ui.directory_dialog(util_ui.tr('Choose folder'))
self.pb.setVisible(True) self.pb.setVisible(True)
if directory: if directory:
self._file_transfer_handler.accept_transfer(self, directory + '/' + self.saved_name, self._file_transfer_handler.accept_transfer(directory + '/' + self.saved_name,
friend_number, file_number, size) friend_number, file_number, size)
self.button_update('pause') self.button_update('pause')
elif self.state == FILE_TRANSFER_STATE['PAUSED_BY_USER']: # resume elif self.state == FILE_TRANSFER_STATE['PAUSED_BY_USER']: # resume
@ -390,8 +390,8 @@ class FileTransferItem(QtWidgets.QListWidget):
class UnsentFileItem(FileTransferItem): class UnsentFileItem(FileTransferItem):
def __init__(self, file_transfers_handler, settings, transfer_message, width, parent=None): def __init__(self, file_transfer_handler, settings, transfer_message, width, parent=None):
super().__init__(file_transfers_handler, settings, transfer_message, width, parent) super().__init__(file_transfer_handler, settings, transfer_message, width, parent)
self._time = time self._time = time
self.pb.setVisible(False) self.pb.setVisible(False)
movie = QtGui.QMovie(util.join_path(util.get_images_directory(), 'spinner.gif')) movie = QtGui.QMovie(util.join_path(util.get_images_directory(), 'spinner.gif'))
@ -399,7 +399,7 @@ class UnsentFileItem(FileTransferItem):
movie.start() movie.start()
def cancel_transfer(self, *args): def cancel_transfer(self, *args):
self._file_transfers_handler.cancel_not_started_transfer(self._time) self._file_transfer_handler.cancel_not_started_transfer(self._time)
class InlineImageItem(QtWidgets.QScrollArea): class InlineImageItem(QtWidgets.QScrollArea):