contacts minor refactoring

This commit is contained in:
ingvar1995 2018-04-18 23:55:51 +03:00
parent 0ba1aadf70
commit dec4990d32
12 changed files with 204 additions and 188 deletions

View file

@ -22,7 +22,7 @@ class App:
def __init__(self, version, path_to_profile=None, uri=None): def __init__(self, version, path_to_profile=None, uri=None):
self._version = version self._version = version
self._app = self._settings = self._profile_manager = self._plugin_loader = None self._app = self._settings = self._profile_manager = self._plugin_loader = None
self._tox = self._ms = self._init = self.tray = self._main_loop = self._av_loop = None self._tox = self._ms = self._init = self._main_loop = self._av_loop = None
self._uri = self._toxes = self._tray = None self._uri = self._toxes = self._tray = None
if uri is not None and uri.startswith('tox:'): if uri is not None and uri.startswith('tox:'):
self._uri = uri[4:] self._uri = uri[4:]
@ -63,15 +63,7 @@ class App:
else: else:
auto_profile = Settings.get_auto_profile() auto_profile = Settings.get_auto_profile()
if auto_profile is None: # no default profile if auto_profile is None: # no default profile
# show login screen if default profile not found result = self.select_profile()
self.load_login_screen_translations()
ls = LoginScreen()
ls.setWindowIconText("Toxygen")
profiles = ProfileManager.find_profiles()
ls.update_select(profiles)
ls.show()
self._app.exec_()
result = ls.result
if result is None: if result is None:
return return
if result.is_new_profile(): # create new profile if result.is_new_profile(): # create new profile
@ -208,6 +200,16 @@ class App:
def create_tox(self, data): def create_tox(self, data):
return tox_factory(data, self._settings) return tox_factory(data, self._settings)
def select_profile(self):
self.load_login_screen_translations()
ls = LoginScreen()
profiles = ProfileManager.find_profiles()
ls.update_select(profiles)
ls.show()
self._app.exec_()
return ls.result
def load_existing_profile(self, profile_path): def load_existing_profile(self, profile_path):
self._settings = Settings(self._toxes, profile_path.replace('.tox', '.json')) self._settings = Settings(self._toxes, profile_path.replace('.tox', '.json'))
self._profile_manager = ProfileManager(self._settings, self._toxes, profile_path) self._profile_manager = ProfileManager(self._settings, self._toxes, profile_path)

View file

@ -1,12 +1,12 @@
import pyaudio import pyaudio
import time import time
import threading import threading
from user_data import settings
from wrapper.toxav_enums import * from wrapper.toxav_enums import *
import cv2 import cv2
import itertools import itertools
import numpy as np import numpy as np
from av import screen_sharing from av import screen_sharing
from av.call import Call
# TODO: play sound until outgoing call will be started or cancelled # TODO: play sound until outgoing call will be started or cancelled
@ -14,8 +14,9 @@ from av import screen_sharing
class AV: class AV:
def __init__(self, toxav): def __init__(self, toxav, settings):
self._toxav = toxav self._toxav = toxav
self._settings = settings
self._running = True self._running = True
self._calls = {} # dict: key - friend number, value - Call instance self._calls = {} # dict: key - friend number, value - Call instance
@ -118,7 +119,7 @@ class AV:
rate=self._audio_rate, rate=self._audio_rate,
channels=self._audio_channels, channels=self._audio_channels,
input=True, input=True,
input_device_index=settings.Settings.get_instance().audio['input'], input_device_index=self._settings.audio['input'],
frames_per_buffer=self._audio_sample_count * 10) frames_per_buffer=self._audio_sample_count * 10)
self._audio_thread = threading.Thread(target=self.send_audio) self._audio_thread = threading.Thread(target=self.send_audio)
@ -147,15 +148,14 @@ class AV:
return return
self._video_running = True self._video_running = True
s = settings.Settings.get_instance()
self._video_width = s.video['width'] self._video_width = s.video['width']
self._video_height = s.video['height'] self._video_height = s.video['height']
if s.video['device'] == -1: if s.video['device'] == -1:
self._video = screen_sharing.DesktopGrabber(s.video['x'], s.video['y'], self._video = screen_sharing.DesktopGrabber(self._settings.video['x'], self._settings.video['y'],
s.video['width'], s.video['height']) self._settings.video['width'], self._settings.video['height'])
else: else:
self._video = cv2.VideoCapture(s.video['device']) self._video = cv2.VideoCapture(self._settings.video['device'])
self._video.set(cv2.CAP_PROP_FPS, 25) self._video.set(cv2.CAP_PROP_FPS, 25)
self._video.set(cv2.CAP_PROP_FRAME_WIDTH, self._video_width) self._video.set(cv2.CAP_PROP_FRAME_WIDTH, self._video_width)
self._video.set(cv2.CAP_PROP_FRAME_HEIGHT, self._video_height) self._video.set(cv2.CAP_PROP_FRAME_HEIGHT, self._video_height)
@ -185,7 +185,7 @@ class AV:
self._out_stream = self._audio.open(format=pyaudio.paInt16, self._out_stream = self._audio.open(format=pyaudio.paInt16,
channels=channels_count, channels=channels_count,
rate=rate, rate=rate,
output_device_index=settings.Settings.get_instance().audio['output'], output_device_index=self._settings.audio['output'],
output=True) output=True)
self._out_stream.write(samples) self._out_stream.write(samples)

View file

@ -4,15 +4,16 @@ import av.calls
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from messenger.messages import * from messenger.messages import *
import time import time
from ui import av_widgets
class CallsManager: class CallsManager:
def __init__(self, tox): def __init__(self, tox, settings):
self._call = av.calls.AV(tox.AV) # object with data about calls self._call = av.calls.AV(tox.AV) # object with data about calls
self._call_widgets = {} # dict of incoming call widgets self._call_widgets = {} # dict of incoming call widgets
self._incoming_calls = set() self._incoming_calls = set()
self._settings = settings
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# AV support # AV support
@ -29,7 +30,7 @@ class CallsManager:
if not self.is_active_a_friend(): if not self.is_active_a_friend():
return return
if num not in self._call and self.is_active_online(): # start call if num not in self._call and self.is_active_online(): # start call
if not Settings.get_instance().audio['enabled']: if not self._settings.audio['enabled']:
return return
self._call(num, audio, video) self._call(num, audio, video)
self._screen.active_call() self._screen.active_call()
@ -47,7 +48,7 @@ class CallsManager:
""" """
Incoming call from friend. Incoming call from friend.
""" """
if not Settings.get_instance().audio['enabled']: if not self._settings.audio['enabled']:
return return
friend = self.get_friend_by_number(friend_number) friend = self.get_friend_by_number(friend_number)
if video: if video:
@ -62,7 +63,7 @@ class CallsManager:
self._messages.scrollToBottom() self._messages.scrollToBottom()
else: else:
friend.actions = True friend.actions = True
self._call_widgets[friend_number] = avwidgets.IncomingCallWidget(friend_number, text, friend.name) self._call_widgets[friend_number] = av_widgets.IncomingCallWidget(friend_number, text, friend.name)
self._call_widgets[friend_number].set_pixmap(friend.get_pixmap()) self._call_widgets[friend_number].set_pixmap(friend.get_pixmap())
self._call_widgets[friend_number].show() self._call_widgets[friend_number].show()

View file

@ -1,6 +1,7 @@
from user_data.settings import * from user_data.settings import *
from PyQt5 import QtCore, QtGui from PyQt5 import QtCore, QtGui
from wrapper.toxcore_enums_and_consts import TOX_PUBLIC_KEY_SIZE from wrapper.toxcore_enums_and_consts import TOX_PUBLIC_KEY_SIZE
import util.util as util
class BaseContact: class BaseContact:
@ -11,13 +12,14 @@ class BaseContact:
Base class for all contacts. Base class for all contacts.
""" """
def __init__(self, name, status_message, widget, tox_id): def __init__(self, profile_manager, name, status_message, widget, tox_id):
""" """
:param name: name, example: 'Toxygen user' :param name: name, example: 'Toxygen user'
:param status_message: status message, example: 'Toxing on Toxygen' :param status_message: status message, example: 'Toxing on Toxygen'
:param widget: ContactItem instance :param widget: ContactItem instance
:param tox_id: tox id of contact :param tox_id: tox id of contact
""" """
self._profile_manager = profile_manager
self._name, self._status_message = name, status_message self._name, self._status_message = name, status_message
self._status, self._widget = None, widget self._status, self._widget = None, widget
self._tox_id = tox_id self._tox_id = tox_id
@ -81,11 +83,7 @@ class BaseContact:
""" """
Tries to load avatar of contact or uses default avatar Tries to load avatar of contact or uses default avatar
""" """
return avatar_path = self.get_avatar_path()
prefix = ProfileManager.get_path() + 'avatars/'
avatar_path = prefix + '{}.png'.format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
if not os.path.isfile(avatar_path) or not os.path.getsize(avatar_path): # load default image
avatar_path = curr_directory() + '/images/avatar.png'
width = self._widget.avatar_label.width() width = self._widget.avatar_label.width()
pixmap = QtGui.QPixmap(avatar_path) pixmap = QtGui.QPixmap(avatar_path)
self._widget.avatar_label.setPixmap(pixmap.scaled(width, width, QtCore.Qt.KeepAspectRatio, self._widget.avatar_label.setPixmap(pixmap.scaled(width, width, QtCore.Qt.KeepAspectRatio,
@ -93,13 +91,13 @@ class BaseContact:
self._widget.avatar_label.repaint() self._widget.avatar_label.repaint()
def reset_avatar(self): def reset_avatar(self):
avatar_path = (ProfileManager.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) avatar_path = self.get_avatar_path()
if os.path.isfile(avatar_path): if os.path.isfile(avatar_path):
os.remove(avatar_path) os.remove(avatar_path)
self.load_avatar() self.load_avatar()
def set_avatar(self, avatar): def set_avatar(self, avatar):
avatar_path = (ProfileManager.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) avatar_path = self.get_avatar_path()
with open(avatar_path, 'wb') as f: with open(avatar_path, 'wb') as f:
f.write(avatar) f.write(avatar)
self.load_avatar() self.load_avatar()
@ -107,6 +105,17 @@ class BaseContact:
def get_pixmap(self): def get_pixmap(self):
return self._widget.avatar_label.pixmap() return self._widget.avatar_label.pixmap()
def get_avatar_path(self):
directory = util.join_path(self._profile_manager.get_path(), 'avatars')
avatar_path = util.join_path(directory, '{}.png'.format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]))
if not os.path.isfile(avatar_path) or not os.path.getsize(avatar_path): # load default image
avatar_path = util.join_path(util.get_images_directory(), self.get_default_avatar_name())
return avatar_path
@staticmethod
def get_default_avatar_name():
return 'avatar.png'
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Widgets # Widgets
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------

View file

@ -1,6 +1,6 @@
from history.database import * from history.database import *
from contacts import basecontact from contacts import basecontact
import util import util.util as util
from messenger.messages import * from messenger.messages import *
from file_transfers import file_transfers as ft from file_transfers import file_transfers as ft
import re import re
@ -12,12 +12,12 @@ class Contact(basecontact.BaseContact):
Properties: number, message getter, history etc. Base class for friend and gc classes Properties: number, message getter, history etc. Base class for friend and gc classes
""" """
def __init__(self, message_getter, number, name, status_message, widget, tox_id): def __init__(self, message_getter, number, profile_manager, name, status_message, widget, tox_id):
""" """
:param message_getter: gets messages from db :param message_getter: gets messages from db
:param number: number of friend. :param number: number of friend.
""" """
super().__init__(name, status_message, widget, tox_id) super().__init__(profile_manager, name, status_message, widget, tox_id)
self._number = number self._number = number
self._new_messages = False self._new_messages = False
self._visible = True self._visible = True

View file

@ -1,36 +1,56 @@
import util.util as util
import util.ui as util_ui
from contacts.friend import Friend
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from messenger.messages import *
from wrapper.toxcore_enums_and_consts import *
from network.tox_dns import tox_dns
class ContactsManager: class ContactsManager:
def __init__(self, tox, settings, screen): def __init__(self, tox, settings, screen, profile_manager):
self._tox = tox self._tox = tox
self._settings = settings self._settings = settings
self._screen = screen
self._profile_manager = profile_manager
self._messages = screen.messages
self._contacts, self._active_friend = [], -1 self._contacts, self._active_friend = [], -1
self._sorting = settings['sorting'] self._sorting = settings['sorting']
data = tox.self_get_friend_list()
self._filter_string = '' self._filter_string = ''
self._friend_item_height = 40 if settings['compact_mode'] else 70 self._friend_item_height = 40 if settings['compact_mode'] else 70
screen.online_contacts.setCurrentIndex(int(self._sorting)) screen.online_contacts.setCurrentIndex(int(self._sorting))
aliases = settings['friends_aliases'] self.load_contacts()
for i in data: # creates list of friends
tox_id = tox.friend_get_public_key(i) def load_contacts(self):
self.load_friends()
self.load_groups()
if len(self._contacts):
self.set_active(0)
self.filtration_and_sorting(self._sorting)
def load_friends(self):
aliases = self._settings['friends_aliases']
friend_numbers = self._tox.self_get_friend_list()
for friend_number in friend_numbers: # creates list of friends
tox_id = self._tox.friend_get_public_key(friend_number)
try: try:
alias = list(filter(lambda x: x[0] == tox_id, aliases))[0][1] alias = list(filter(lambda x: x[0] == tox_id, aliases))[0][1]
except: except:
alias = '' alias = ''
item = self.create_friend_item() item = self.create_friend_item()
name = alias or tox.friend_get_name(i) or tox_id name = alias or self._tox.friend_get_name(friend_number) or tox_id
status_message = tox.friend_get_status_message(i) status_message = self._tox.friend_get_status_message(i)
if not self._history.friend_exists_in_db(tox_id): if not self._history.friend_exists_in_db(tox_id):
self._history.add_friend_to_db(tox_id) self._history.add_friend_to_db(tox_id)
message_getter = self._history.messages_getter(tox_id) message_getter = self._history.messages_getter(tox_id)
friend = Friend(message_getter, i, name, status_message, item, tox_id) friend = Friend(self._profile_manager, message_getter, friend_number, name, status_message, item, tox_id)
friend.set_alias(alias) friend.set_alias(alias)
self._contacts.append(friend) self._contacts.append(friend)
if len(self._contacts):
self.set_active(0)
self.filtration_and_sorting(self._sorting)
def load_groups(self):
pass
def get_friend(self, num): def get_friend(self, num):
if num < 0 or num >= len(self._contacts): if num < 0 or num >= len(self._contacts):
@ -40,6 +60,10 @@ class ContactsManager:
def get_curr_friend(self): def get_curr_friend(self):
return self._contacts[self._active_friend] if self._active_friend + 1 else None return self._contacts[self._active_friend] if self._active_friend + 1 else None
def save_profile(self):
data = self._tox.get_savedata()
self._profile_manager.save_profile(data)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Work with active friend # Work with active friend
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
@ -78,7 +102,7 @@ class ContactsManager:
self._screen.messageEdit.setPlainText(friend.curr_text) self._screen.messageEdit.setPlainText(friend.curr_text)
self._active_friend = value self._active_friend = value
friend.reset_messages() friend.reset_messages()
if not Settings.get_instance()['save_history']: if not self._settings['save_history']:
friend.delete_old_messages() friend.delete_old_messages()
self._messages.clear() self._messages.clear()
friend.load_corr() friend.load_corr()
@ -128,19 +152,14 @@ class ContactsManager:
self._screen.account_name.setText(friend.name) self._screen.account_name.setText(friend.name)
self._screen.account_status.setText(friend.status_message) self._screen.account_status.setText(friend.status_message)
self._screen.account_status.setToolTip(friend.get_full_status()) self._screen.account_status.setToolTip(friend.get_full_status())
if friend.tox_id is None: avatar_path = friend.get_avatar_path()
avatar_path = curr_directory() + '/images/group.png'
else:
avatar_path = (ProfileManager.get_path() + 'avatars/{}.png').format(friend.tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
if not os.path.isfile(avatar_path): # load default image
avatar_path = curr_directory() + '/images/avatar.png'
os.chdir(os.path.dirname(avatar_path)) os.chdir(os.path.dirname(avatar_path))
pixmap = QtGui.QPixmap(avatar_path) pixmap = QtGui.QPixmap(avatar_path)
self._screen.account_avatar.setPixmap(pixmap.scaled(64, 64, QtCore.Qt.KeepAspectRatio, self._screen.account_avatar.setPixmap(pixmap.scaled(64, 64, QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation)) QtCore.Qt.SmoothTransformation))
except Exception as ex: # no friend found. ignore except Exception as ex: # no friend found. ignore
log('Friend value: ' + str(value)) util.log('Friend value: ' + str(value))
log('Error in set active: ' + str(ex)) util.log('Error in set active: ' + str(ex))
raise raise
def set_active_by_number_and_type(self, number, is_friend): def set_active_by_number_and_type(self, number, is_friend):
@ -167,7 +186,6 @@ class ContactsManager:
:param filter_str: show contacts which name contains this substring :param filter_str: show contacts which name contains this substring
""" """
filter_str = filter_str.lower() filter_str = filter_str.lower()
settings = Settings.get_instance()
number = self.get_active_number() number = self.get_active_number()
is_friend = self.is_active_a_friend() is_friend = self.is_active_a_friend()
if sorting > 1: if sorting > 1:
@ -203,8 +221,8 @@ class ContactsManager:
else: else:
self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250, 0)) self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250, 0))
self._sorting, self._filter_string = sorting, filter_str self._sorting, self._filter_string = sorting, filter_str
settings['sorting'] = self._sorting self._settings['sorting'] = self._sorting
settings.save() self._settings.save()
self.set_active_by_number_and_type(number, is_friend) self.set_active_by_number_and_type(number, is_friend)
def update_filtration(self): def update_filtration(self):
@ -213,7 +231,6 @@ class ContactsManager:
""" """
self.filtration_and_sorting(self._sorting, self._filter_string) self.filtration_and_sorting(self._sorting, self._filter_string)
def create_friend_item(self): def create_friend_item(self):
""" """
Method-factory Method-factory
@ -221,7 +238,42 @@ class ContactsManager:
""" """
return self._factory.friend_item() return self._factory.friend_item()
# -----------------------------------------------------------------------------------------------------------------
# Friend getters
# -----------------------------------------------------------------------------------------------------------------
def get_friend_by_number(self, num):
return list(filter(lambda x: x.number == num and type(x) is Friend, self._contacts))[0]
def get_last_message(self):
if self._active_friend + 1:
return self.get_curr_friend().get_last_message_text()
else:
return ''
def get_active_number(self):
return self.get_curr_friend().number if self._active_friend + 1 else -1
def get_active_name(self):
return self.get_curr_friend().name if self._active_friend + 1 else ''
def is_active_online(self):
return self._active_friend + 1 and self.get_curr_friend().status is not None
def new_name(self, number, name):
friend = self.get_friend_by_number(number)
tmp = friend.name
friend.set_name(name)
name = str(name, 'utf-8')
if friend.name == name and tmp != name:
message = QtWidgets.QApplication.translate("MainWindow", 'User {} is now known as {}')
message = message.format(tmp, name)
friend.append_message(InfoMessage(message, time.time()))
friend.actions = True
if number == self.get_active_number():
self.create_message_item(message, time.time(), '', MESSAGE_TYPE['INFO_MESSAGE'])
self._messages.scrollToBottom()
self.set_active(None)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Work with friends (remove, block, set alias, get public key) # Work with friends (remove, block, set alias, get public key)
@ -233,19 +285,11 @@ class ContactsManager:
""" """
friend = self._contacts[num] friend = self._contacts[num]
name = friend.name name = friend.name
dialog = QtWidgets.QApplication.translate('MainWindow', text = util_ui.tr("Enter new alias for friend {} or leave empty to use friend's name:").format(name)
"Enter new alias for friend {} or leave empty to use friend's name:") title = util_ui.tr('Set alias')
dialog = dialog.format(name) text, ok = util_ui.text_dialog(text, title, name)
title = QtWidgets.QApplication.translate('MainWindow',
'Set alias')
text, ok = QtWidgets.QInputDialog.getText(None,
title,
dialog,
QtWidgets.QLineEdit.Normal,
name)
if ok: if ok:
settings = Settings.get_instance() aliases = self._settings['friends_aliases']
aliases = settings['friends_aliases']
if text: if text:
friend.name = bytes(text, 'utf-8') friend.name = bytes(text, 'utf-8')
try: try:
@ -262,7 +306,7 @@ class ContactsManager:
del aliases[index] del aliases[index]
except: except:
pass pass
settings.save() self._settings.save()
if num == self.get_active_number() and self.is_active_a_friend(): if num == self.get_active_number() and self.is_active_a_friend():
self.update() self.update()
@ -275,15 +319,14 @@ class ContactsManager:
:param num: number of friend in list :param num: number of friend in list
""" """
friend = self._contacts[num] friend = self._contacts[num]
settings = Settings.get_instance()
try: try:
index = list(map(lambda x: x[0], settings['friends_aliases'])).index(friend.tox_id) index = list(map(lambda x: x[0], self._settings['friends_aliases'])).index(friend.tox_id)
del settings['friends_aliases'][index] del self._settings['friends_aliases'][index]
except: except:
pass pass
if friend.tox_id in settings['notes']: if friend.tox_id in self._settings['notes']:
del settings['notes'][friend.tox_id] del self._settings['notes'][friend.tox_id]
settings.save() self._settings.save()
self.clear_history(num) self.clear_history(num)
if self._history.friend_exists_in_db(friend.tox_id): if self._history.friend_exists_in_db(friend.tox_id):
self._history.delete_friend_from_db(friend.tox_id) self._history.delete_friend_from_db(friend.tox_id)
@ -296,7 +339,7 @@ class ContactsManager:
else: else:
self.set_active(0) self.set_active(0)
data = self._tox.get_savedata() data = self._tox.get_savedata()
ProfileManager.get_instance().save_profile(data) self._profile_manager.save_profile(data)
def add_friend(self, tox_id): def add_friend(self, tox_id):
""" """
@ -309,7 +352,7 @@ class ContactsManager:
self._history.add_friend_to_db(tox_id) self._history.add_friend_to_db(tox_id)
message_getter = self._history.messages_getter(tox_id) message_getter = self._history.messages_getter(tox_id)
except Exception as ex: # something is wrong except Exception as ex: # something is wrong
log('Accept friend request failed! ' + str(ex)) util.log('Accept friend request failed! ' + str(ex))
message_getter = None message_getter = None
friend = Friend(message_getter, num, tox_id, '', item, tox_id) friend = Friend(message_getter, num, tox_id, '', item, tox_id)
self._contacts.append(friend) self._contacts.append(friend)
@ -319,17 +362,15 @@ class ContactsManager:
Block user with specified tox id (or public key) - delete from friends list and ignore friend requests Block user with specified tox id (or public key) - delete from friends list and ignore friend requests
""" """
tox_id = tox_id[:TOX_PUBLIC_KEY_SIZE * 2] tox_id = tox_id[:TOX_PUBLIC_KEY_SIZE * 2]
if tox_id == self.tox_id[:TOX_PUBLIC_KEY_SIZE * 2]: if tox_id == self._tox.self_get_address[:TOX_PUBLIC_KEY_SIZE * 2]:
return return
settings = Settings.get_instance() if tox_id not in self._settings['blocked']:
if tox_id not in settings['blocked']: self._settings['blocked'].append(tox_id)
settings['blocked'].append(tox_id) self._settings.save()
settings.save()
try: try:
num = self._tox.friend_by_public_key(tox_id) num = self._tox.friend_by_public_key(tox_id)
self.delete_friend(num) self.delete_friend(num)
data = self._tox.get_savedata() self.save_profile()
ProfileManager.get_instance().save_profile(data)
except: # not in friend list except: # not in friend list
pass pass
@ -339,13 +380,11 @@ class ContactsManager:
:param tox_id: tox id of contact :param tox_id: tox id of contact
:param add_to_friend_list: add this contact to friend list or not :param add_to_friend_list: add this contact to friend list or not
""" """
s = Settings.get_instance() self._settings['blocked'].remove(tox_id)
s['blocked'].remove(tox_id) self._settings.save()
s.save()
if add_to_friend_list: if add_to_friend_list:
self.add_friend(tox_id) self.add_friend(tox_id)
data = self._tox.get_savedata() self.save_profile()
ProfileManager.get_instance().save_profile(data)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Friend requests # Friend requests
@ -366,11 +405,9 @@ class ContactsManager:
raise Exception('TOX DNS lookup failed') raise Exception('TOX DNS lookup failed')
if len(tox_id) == TOX_PUBLIC_KEY_SIZE * 2: # public key if len(tox_id) == TOX_PUBLIC_KEY_SIZE * 2: # public key
self.add_friend(tox_id) self.add_friend(tox_id)
msgBox = QtWidgets.QMessageBox() title = util_ui.tr('Friend added')
msgBox.setWindowTitle(QtWidgets.QApplication.translate("MainWindow", "Friend added")) text = util_ui.tr('Friend added without sending friend request')
text = (QtWidgets.QApplication.translate("MainWindow", 'Friend added without sending friend request')) util_ui.message_box(text, title)
msgBox.setText(text)
msgBox.exec_()
else: else:
result = self._tox.friend_add(tox_id, message.encode('utf-8')) result = self._tox.friend_add(tox_id, message.encode('utf-8'))
tox_id = tox_id[:TOX_PUBLIC_KEY_SIZE * 2] tox_id = tox_id[:TOX_PUBLIC_KEY_SIZE * 2]
@ -380,11 +417,10 @@ class ContactsManager:
message_getter = self._history.messages_getter(tox_id) message_getter = self._history.messages_getter(tox_id)
friend = Friend(message_getter, result, tox_id, '', item, tox_id) friend = Friend(message_getter, result, tox_id, '', item, tox_id)
self._contacts.append(friend) self._contacts.append(friend)
data = self._tox.get_savedata() self.save_profile()
ProfileManager.get_instance().save_profile(data)
return True return True
except Exception as ex: # wrong data except Exception as ex: # wrong data
log('Friend request failed with ' + str(ex)) util.log('Friend request failed with ' + str(ex))
return str(ex) return str(ex)
def process_friend_request(self, tox_id, message): def process_friend_request(self, tox_id, message):
@ -396,13 +432,34 @@ class ContactsManager:
if tox_id in self._settings['blocked']: if tox_id in self._settings['blocked']:
return return
try: try:
text = QtWidgets.QApplication.translate('MainWindow', 'User {} wants to add you to contact list. Message:\n{}') text = util_ui.tr('User {} wants to add you to contact list. Message:\n{}')
info = text.format(tox_id, message) reply = util_ui.question(text.format(tox_id, message), util_ui.tr('Friend request'))
fr_req = QtWidgets.QApplication.translate('MainWindow', 'Friend request') if reply: # accepted
reply = QtWidgets.QMessageBox.question(None, fr_req, info, QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes: # accepted
self.add_friend(tox_id) self.add_friend(tox_id)
data = self._tox.get_savedata() data = self._tox.get_savedata()
ProfileManager.get_instance().save_profile(data) self._profile_manager.save_profile(data)
except Exception as ex: # something is wrong except Exception as ex: # something is wrong
log('Accept friend request failed! ' + str(ex)) util.log('Accept friend request failed! ' + str(ex))
# -----------------------------------------------------------------------------------------------------------------
# Typing notifications
# -----------------------------------------------------------------------------------------------------------------
def send_typing(self, typing):
"""
Send typing notification to a friend
"""
if self._settings['typing_notifications'] and self._active_friend + 1:
try:
friend = self.get_curr_friend()
if friend.status is not None:
self._tox.self_set_typing(friend.number, typing)
except:
pass
def friend_typing(self, friend_number, typing):
"""
Display incoming typing notification
"""
if friend_number == self.get_active_number() and self.is_active_a_friend():
self._screen.typing.setVisible(typing)

View file

@ -8,8 +8,8 @@ class Friend(contact.Contact):
Friend in list of friends. Friend in list of friends.
""" """
def __init__(self, message_getter, number, name, status_message, widget, tox_id): def __init__(self, profile_manager, message_getter, number, name, status_message, widget, tox_id):
super().__init__(message_getter, number, name, status_message, widget, tox_id) super().__init__(profile_manager, message_getter, number, name, status_message, widget, tox_id)
self._receipts = 0 self._receipts = 0
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------

View file

@ -1,5 +1,5 @@
from contacts import contact from contacts import contact
import util import util.util as util
from PyQt5 import QtGui, QtCore from PyQt5 import QtGui, QtCore
from wrapper import toxcore_enums_and_consts as constants from wrapper import toxcore_enums_and_consts as constants
@ -8,8 +8,8 @@ from wrapper import toxcore_enums_and_consts as constants
class GroupChat(contact.Contact): class GroupChat(contact.Contact):
def __init__(self, name, status_message, widget, tox, group_number): def __init__(self, profile_manager, name, status_message, widget, tox, group_number):
super().__init__(None, group_number, name, status_message, widget, None) super().__init__(None, group_number, profile_manager, name, status_message, widget, None)
self._tox = tox self._tox = tox
self.set_status(constants.TOX_USER_STATUS['NONE']) self.set_status(constants.TOX_USER_STATUS['NONE'])
@ -23,13 +23,9 @@ class GroupChat(contact.Contact):
def new_title(self, title): def new_title(self, title):
super().set_name(title) super().set_name(title)
def load_avatar(self): @staticmethod
path = util.curr_directory() + '/images/group.png' def get_default_avatar_name():
width = self._widget.avatar_label.width() return 'group.png'
pixmap = QtGui.QPixmap(path)
self._widget.avatar_label.setPixmap(pixmap.scaled(width, width, QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation))
self._widget.avatar_label.repaint()
def remove_invalid_unsent_files(self): def remove_invalid_unsent_files(self):
pass pass

View file

@ -22,12 +22,13 @@ class Profile(basecontact.BaseContact):
""" """
Profile of current toxygen user. Contains friends list, tox instance Profile of current toxygen user. Contains friends list, tox instance
""" """
def __init__(self, tox, screen): def __init__(self, profile_manager, tox, screen):
""" """
:param tox: tox instance :param tox: tox instance
:param screen: ref to main screen :param screen: ref to main screen
""" """
basecontact.BaseContact.__init__(self, basecontact.BaseContact.__init__(self,
profile_manager,
tox.self_get_name(), tox.self_get_name(),
tox.self_get_status_message(), tox.self_get_status_message(),
screen.user_info, screen.user_info,
@ -86,43 +87,6 @@ class Profile(basecontact.BaseContact):
self._tox_id = self._tox.self_get_address() self._tox_id = self._tox.self_get_address()
return self._tox_id return self._tox_id
# -----------------------------------------------------------------------------------------------------------------
# Friend getters
# -----------------------------------------------------------------------------------------------------------------
def get_friend_by_number(self, num):
return list(filter(lambda x: x.number == num and type(x) is Friend, self._contacts))[0]
def get_last_message(self):
if self._active_friend + 1:
return self.get_curr_friend().get_last_message_text()
else:
return ''
def get_active_number(self):
return self.get_curr_friend().number if self._active_friend + 1 else -1
def get_active_name(self):
return self.get_curr_friend().name if self._active_friend + 1 else ''
def is_active_online(self):
return self._active_friend + 1 and self.get_curr_friend().status is not None
def new_name(self, number, name):
friend = self.get_friend_by_number(number)
tmp = friend.name
friend.set_name(name)
name = str(name, 'utf-8')
if friend.name == name and tmp != name:
message = QtWidgets.QApplication.translate("MainWindow", 'User {} is now known as {}')
message = message.format(tmp, name)
friend.append_message(InfoMessage(message, time.time()))
friend.actions = True
if number == self.get_active_number():
self.create_message_item(message, time.time(), '', MESSAGE_TYPE['INFO_MESSAGE'])
self._messages.scrollToBottom()
self.set_active(None)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Friend connection status callbacks # Friend connection status callbacks
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
@ -168,29 +132,6 @@ class Profile(basecontact.BaseContact):
self._paused_file_transfers[ft.get_id()] = [ft.get_path(), friend_num, True, ft.total_size()] self._paused_file_transfers[ft.get_id()] = [ft.get_path(), friend_num, True, ft.total_size()]
self.cancel_transfer(friend_num, file_num, True) self.cancel_transfer(friend_num, file_num, True)
# -----------------------------------------------------------------------------------------------------------------
# Typing notifications
# -----------------------------------------------------------------------------------------------------------------
def send_typing(self, typing):
"""
Send typing notification to a friend
"""
if Settings.get_instance()['typing_notifications'] and self._active_friend + 1:
try:
friend = self.get_curr_friend()
if friend.status is not None:
self._tox.self_set_typing(friend.number, typing)
except:
pass
def friend_typing(self, friend_number, typing):
"""
Display incoming typing notification
"""
if friend_number == self.get_active_number() and self.is_active_a_friend():
self._screen.typing.setVisible(typing)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Private messages # Private messages
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
@ -294,7 +235,6 @@ class Profile(basecontact.BaseContact):
# Friend, message and file transfer items creation # Friend, message and file transfer items creation
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def create_message_item(self, text, time, owner, message_type, append=True): def create_message_item(self, text, time, owner, message_type, append=True):
if message_type == MESSAGE_TYPE['INFO_MESSAGE']: if message_type == MESSAGE_TYPE['INFO_MESSAGE']:
name = '' name = ''

View file

@ -13,7 +13,7 @@ class ProfileManager:
self._path = path self._path = path
self._directory = os.path.basename(path) self._directory = os.path.basename(path)
# create /avatars if not exists: # create /avatars if not exists:
directory = path + 'avatars' directory = util.join_path(self._directory, 'avatars')
if not os.path.exists(directory): if not os.path.exists(directory):
os.makedirs(directory) os.makedirs(directory)

View file

@ -1,21 +1,28 @@
import PyQt5 from PyQt5 import QtWidgets
def tr(s): def tr(s):
return PyQt5.QtWidgets.QApplication.translate('Toxygen', s) return QtWidgets.QApplication.translate('Toxygen', s)
def question(text, title=None): def question(text, title=None):
reply = PyQt5.QtWidgets.QMessageBox.question(None, title or 'Toxygen', text, reply = QtWidgets.QMessageBox.question(None, title or 'Toxygen', text,
PyQt5.QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.Yes,
PyQt5.QtWidgets.QMessageBox.No) QtWidgets.QMessageBox.No)
return reply == PyQt5.QtWidgets.QMessageBox.Yes return reply == QtWidgets.QMessageBox.Yes
def message_box(text, title=None): def message_box(text, title=None):
m_box = PyQt5.QtWidgets.QMessageBox() m_box = QtWidgets.QMessageBox()
m_box.setText(tr(text)) m_box.setText(tr(text))
m_box.setWindowTitle(title or 'Toxygen') m_box.setWindowTitle(title or 'Toxygen')
m_box.exec_() m_box.exec_()
def text_dialog(text, title='', default_value=''):
text, ok = QtWidgets.QInputDialog.getText(None, title, text, QtWidgets.QLineEdit.Normal, default_value)
return text, ok
# TODO: move all dialogs here # TODO: move all dialogs here

View file

@ -79,6 +79,10 @@ def curr_time():
return time.strftime('%H:%M') return time.strftime('%H:%M')
def join_path(a, b):
return os.path.join(a, b)
def copy(src, dest): def copy(src, dest):
if not os.path.exists(dest): if not os.path.exists(dest):
os.makedirs(dest) os.makedirs(dest)