From 9d5353640bc875ee029d1166852f4bb252881b9a Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Fri, 18 Mar 2016 16:20:07 +0300 Subject: [PATCH] avatars support --- src/callbacks.py | 2 ++ src/file_transfers.py | 55 +++++++++++++++++++++++++++++++++++++------ src/profile.py | 37 +++++++++++++---------------- 3 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/callbacks.py b/src/callbacks.py index 7c7cacd..496b72d 100644 --- a/src/callbacks.py +++ b/src/callbacks.py @@ -74,6 +74,8 @@ def friend_connection_status(tox, friend_num, new_status, user_data): friend = profile.get_friend_by_number(friend_num) if new_status == TOX_CONNECTION['NONE']: invoke_in_main_thread(friend.set_status, None) + elif friend.status is None: + invoke_in_main_thread(profile.send_avatar, friend_num) invoke_in_main_thread(profile.update_filtration) diff --git a/src/file_transfers.py b/src/file_transfers.py index b983d81..3cb0dce 100644 --- a/src/file_transfers.py +++ b/src/file_transfers.py @@ -1,8 +1,11 @@ # TODO: add support of file transfers # TODO: add support of avatars -from toxcore_enums_and_consts import TOX_FILE_KIND -from os.path import basename, getsize +from toxcore_enums_and_consts import TOX_FILE_KIND, TOX_FILE_CONTROL +from os.path import basename, getsize, exists +from os import remove from time import time +from tox import Tox +import profile TOX_FILE_TRANSFER_STATE = { @@ -44,10 +47,15 @@ class FileTransfer(object): class SendTransfer(FileTransfer): - def __init__(self, path, tox, friend_number): - super(self.__class__, self).__init__(path, tox, friend_number) - self._file_number = tox.file_send(friend_number, TOX_FILE_KIND['DATA'], getsize(path), None, basename(path)) - self._file = open(path, 'rb') + def __init__(self, path, tox, friend_number, kind=TOX_FILE_KIND['DATA'], file_id=None): + super(SendTransfer, self).__init__(path, tox, friend_number) + self._file_number = tox.file_send(friend_number, + kind, + getsize(path) if path else 0, + file_id, + basename(path) if path else '') + if path is not None: + self._file = open(path, 'rb') def send_chunk(self, position, size): self._file.seek(position) @@ -55,9 +63,19 @@ class SendTransfer(FileTransfer): return self._tox.file_send_chunk(self._friend_number, self._file_number, position, data) +class SendAvatar(SendTransfer): + def __init__(self, path, tox, friend_number): + if path is None: + super(SendAvatar, self).__init__(path, tox, friend_number, TOX_FILE_KIND['AVATAR']) + else: + with open(path, 'rb') as fl: + hash = Tox.hash(fl.read()) + super(self.__class__, self).__init__(path, tox, friend_number, TOX_FILE_KIND['AVATAR'], hash) + + class ReceiveTransfer(FileTransfer): def __init__(self, path, tox, friend_number, file_number): - super(self.__class__, self).__init__(path, tox, friend_number, file_number) + super(ReceiveTransfer, self).__init__(path, tox, friend_number, file_number) self._file = open(self._path, 'wb') self._file.truncate(0) self._size = 0 @@ -75,3 +93,26 @@ class ReceiveTransfer(FileTransfer): self._size = position + len(data) else: self._file.close() + self.state = TOX_FILE_TRANSFER_STATE['FINISHED'] + + +class ReceiveAvatar(ReceiveTransfer): + def __init__(self, tox, friend_number, file_number, has_size=True): + path = profile.ProfileHelper.get_path() + '/avatars/{}.png'.format(tox.friend_get_public_key(friend_number)) + super(ReceiveAvatar, self).__init__(path, tox, friend_number, file_number) + if exists(path): + if not has_size: + remove(path) + self.send_control(TOX_FILE_CONTROL['CANCEL']) + self.state = TOX_FILE_TRANSFER_STATE['CANCELED'] + else: + hash = self.get_file_id() + with open(path, 'rb') as fl: + existing_hash = Tox.hash(fl.read()) + if hash == existing_hash: + self.send_control(TOX_FILE_CONTROL['CANCEL']) + self.state = TOX_FILE_TRANSFER_STATE['CANCELED'] + else: + self.send_control(TOX_FILE_CONTROL['RESUME']) + else: + self.send_control(TOX_FILE_CONTROL['RESUME']) diff --git a/src/profile.py b/src/profile.py index cc6966b..98d6a15 100644 --- a/src/profile.py +++ b/src/profile.py @@ -148,7 +148,7 @@ class Contact(object): """ Tries to load avatar of contact or uses default avatar """ - avatar_path = (Settings.get_default_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) + avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) if not os.path.isfile(avatar_path): # load default image avatar_path = curr_directory() + '/images/avatar.png' pixmap = QtGui.QPixmap(QtCore.QSize(64, 64)) @@ -157,19 +157,19 @@ class Contact(object): self._widget.avatar_label.repaint() def reset_avatar(self): - avatar_path = (Settings.get_default_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) + avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) if os.path.isfile(avatar_path): os.remove(avatar_path) self.load_avatar() def set_avatar(self, avatar): - avatar_path = (Settings.get_default_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) + avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) with open(avatar_path, 'wb') as f: f.write(avatar) self.load_avatar() def get_avatar_hash(self): - avatar_path = (Settings.get_default_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) + avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) if not os.path.isfile(avatar_path): # load default image return 0 with open(avatar_path, 'rb') as fl: @@ -715,31 +715,26 @@ class Profile(Contact, Singleton): :param file_number: file number :param size: size of avatar or 0 (default avatar) """ - friend = self.get_friend_by_number(friend_number) - if not size: - friend.reset_avatar() - self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL']) + ra = ReceiveAvatar(self._tox, friend_number, file_number, size) + if ra.state != TOX_FILE_TRANSFER_STATE['CANCELED']: + self._file_transfers[(friend_number, file_number)] = ra else: - hash = friend.get_avatar_hash() - new_avatar_hash = self._tox.file_get_file_id(friend_number, file_number) - if hash == new_avatar_hash: # avatar is the same - self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL']) # ignore file - else: # get new avatar - path = ProfileHelper.get_path() + '/avatars/{}.png'.format(friend.tox_id) - rt = ReceiveTransfer(path, self._tox, friend_number, file_number) - self._file_transfers[(friend_number, file_number)] = rt - self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['RESUME']) + self.get_friend_by_number(friend_number).load_avatar() def incoming_chunk(self, friend_number, file_number, position, data): transfer = self._file_transfers[(friend_number, file_number)] transfer.write_chunk(position, data) - if data is None: + if transfer.state: + if type(transfer) is ReceiveAvatar: + self.get_friend_by_number(friend_number).load_avatar() del self._file_transfers[(friend_number, file_number)] - friend = self.get_friend_by_number(friend_number) - friend.load_avatar() def send_avatar(self, friend_number): - pass + avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) + if not os.path.isfile(avatar_path): # reset image + avatar_path = None + sa = SendAvatar(avatar_path, self._tox, friend_number) + self._file_transfers[(friend_number, sa.get_file_number())] = sa def send_file(self, path): friend_number = self.get_active_number()