deps creation - improvements. db and history fixes. widgets creation - factory

This commit is contained in:
ingvar1995 2018-04-29 00:52:42 +03:00
parent a9d2d3d809
commit e9272eee2a
18 changed files with 419 additions and 319 deletions

View file

@ -20,6 +20,9 @@ from contacts.profile import Profile
from file_transfers.file_transfers_handler import FileTransfersHandler from file_transfers.file_transfers_handler import FileTransfersHandler
from contacts.contact_provider import ContactProvider from contacts.contact_provider import ContactProvider
from contacts.friend_factory import FriendFactory from contacts.friend_factory import FriendFactory
from contacts.contacts_manager import ContactsManager
from av.calls_manager import CallsManager
from history.database import Database
class App: class App:
@ -29,6 +32,7 @@ class App:
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._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 = self._file_transfer_handler = self._contacts_provider = None self._uri = self._toxes = self._tray = self._file_transfer_handler = self._contacts_provider = None
self._friend_factory = self._calls_manager = self._contacts_manager = 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:]
self._path = path_to_profile self._path = path_to_profile
@ -97,24 +101,9 @@ class App:
if self.try_to_update(): if self.try_to_update():
return return
self._ms = MainWindow(self._settings, self._tox, self.reset, self._tray) self.create_dependencies()
self._friend_factory = FriendFactory(None, self._profile_manager, self._settings, self._tox)
self._contacts_provider = ContactProvider(self._tox, self._friend_factory)
self._file_transfer_handler = FileTransfersHandler(self._tox, self._settings, self._contacts_provider)
profile = Profile(self._profile_manager, self._tox, self._ms, self._file_transfer_handler)
self._ms.profile = profile
self._ms.show()
self._tray = tray.init_tray(profile, self._settings, self._ms)
self._tray.show()
self._plugin_loader = PluginLoader(self._tox, self._toxes, profile, self._settings) # plugins support
self.start_threads() self.start_threads()
# callbacks initialization
callbacks.init_callbacks(self._tox, profile, self._settings, self._plugin_loader, None, None, None,
self._ms, self._tray)
if self._uri is not None: if self._uri is not None:
self._ms.add_contact(self._uri) self._ms.add_contact(self._uri)
@ -131,6 +120,9 @@ class App:
else: else:
break break
self.stop_app()
def stop_app(self):
self._plugin_loader.stop() self._plugin_loader.stop()
self.stop_threads() self.stop_threads()
self._tray.hide() self._tray.hide()
@ -155,6 +147,28 @@ class App:
return self._tox return self._tox
def create_dependencies(self):
self._ms = MainWindow(self._settings, self._tox, self.reset, self._tray)
db = Database(self._path.replace('.tox', '.db'), self._toxes)
self._friend_factory = FriendFactory(self._profile_manager, self._settings, self._tox, db)
self._contacts_provider = ContactProvider(self._tox, self._friend_factory)
self._contacts_manager = ContactsManager(self._tox, self._settings, self._ms, self._profile_manager,
self._contacts_provider, db)
self._calls_manager = CallsManager(self._tox.AV, self._settings)
self._file_transfer_handler = FileTransfersHandler(self._tox, self._settings, self._contacts_provider)
profile = Profile(self._profile_manager, self._tox, self._ms, self._file_transfer_handler)
self._ms.profile = profile
self._ms.show()
self._tray = tray.init_tray(profile, self._settings, self._ms)
self._tray.show()
self._plugin_loader = PluginLoader(self._tox, self._toxes, profile, self._settings) # plugins support
# callbacks initialization
callbacks.init_callbacks(self._tox, profile, self._settings, self._plugin_loader, self._contacts_manager,
self._calls_manager, self._file_transfer_handler, self._ms, self._tray)
def load_app_styles(self): def load_app_styles(self):
# application color scheme # application color scheme
for theme in self._settings.built_in_themes().keys(): for theme in self._settings.built_in_themes().keys():

View file

@ -9,8 +9,8 @@ from ui import av_widgets
class CallsManager: class CallsManager:
def __init__(self, tox, settings): def __init__(self, toxAV, settings):
self._call = av.calls.AV(tox.AV) # object with data about calls self._call = av.calls.AV(toxAV, settings) # 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 self._settings = settings

View file

@ -8,6 +8,20 @@ class ContactProvider(util.ToxSave):
self._friend_factory = friend_factory self._friend_factory = friend_factory
self._cache = {} # key - contact's public key, value - contact instance self._cache = {} # key - contact's public key, value - contact instance
# -----------------------------------------------------------------------------------------------------------------
# Private methods
# -----------------------------------------------------------------------------------------------------------------
def _get_contact_from_cache(self, public_key):
return self._cache[public_key] if public_key in self._cache else None
def _add_to_cache(self, public_key, contact):
self._cache[public_key] = contact
# -----------------------------------------------------------------------------------------------------------------
# Friends
# -----------------------------------------------------------------------------------------------------------------
def get_friend_by_number(self, friend_number): def get_friend_by_number(self, friend_number):
public_key = self._tox.friend_get_public_key(friend_number) public_key = self._tox.friend_get_public_key(friend_number)
@ -22,17 +36,39 @@ class ContactProvider(util.ToxSave):
return friend return friend
def get_all_friends(self):
friend_numbers = self._tox.self_get_friend_list()
friends = map(lambda n: self.get_friend_by_number(n), friend_numbers)
return list(friends)
# -----------------------------------------------------------------------------------------------------------------
# GC
# -----------------------------------------------------------------------------------------------------------------
def get_all_gc(self):
return []
def get_gc_by_number(self): def get_gc_by_number(self):
pass pass
def get_gc_by_public_key(self): def get_gc_by_public_key(self):
pass pass
# -----------------------------------------------------------------------------------------------------------------
# All contacts
# -----------------------------------------------------------------------------------------------------------------
def get_all(self):
return self.get_all_friends() + self.get_all_gc()
# -----------------------------------------------------------------------------------------------------------------
# Caching
# -----------------------------------------------------------------------------------------------------------------
def clear_cache(self): def clear_cache(self):
self._cache.clear() self._cache.clear()
def _get_contact_from_cache(self, public_key): def remove_friend_from_cache(self, friend_public_key):
return self._cache[public_key] if public_key in self._cache else None if friend_public_key in self._cache:
del self._cache[friend_public_key]
def _add_to_cache(self, public_key, contact):
self._cache[public_key] = contact

View file

@ -6,31 +6,40 @@ from PyQt5 import QtCore, QtGui, QtWidgets
from messenger.messages import * from messenger.messages import *
from wrapper.toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
from network.tox_dns import tox_dns from network.tox_dns import tox_dns
from history.history_loader import HistoryLoader
class ContactsManager: class ContactsManager:
def __init__(self, tox, settings, screen, profile_manager): def __init__(self, tox, settings, screen, profile_manager, contact_provider, db):
self._tox = tox self._tox = tox
self._settings = settings self._settings = settings
self._screen = screen self._screen = screen
self._profile_manager = profile_manager self._profile_manager = profile_manager
self._contact_provider = contact_provider
self._messages = screen.messages self._messages = screen.messages
self._contacts, self._active_friend = [], -1 self._contacts, self._active_contact = [], -1
self._sorting = settings['sorting'] self._sorting = settings['sorting']
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))
self.load_contacts() self._history = HistoryLoader(contact_provider, db, settings)
self._load_contacts()
def load_contacts(self): def __del__(self):
self.load_friends() del self._history
self.load_groups()
if len(self._contacts): def _is_active_a_friend(self):
self.set_active(0) return type(self.get_curr_contact()) is Friend
def _load_contacts(self):
self._load_friends()
self._load_groups()
# if len(self._contacts):
# self.set_active(0)
self.filtration_and_sorting(self._sorting) self.filtration_and_sorting(self._sorting)
def load_friends(self): def _load_friends(self):
aliases = self._settings['friends_aliases'] aliases = self._settings['friends_aliases']
friend_numbers = self._tox.self_get_friend_list() friend_numbers = self._tox.self_get_friend_list()
for friend_number in friend_numbers: # creates list of friends for friend_number in friend_numbers: # creates list of friends
@ -41,15 +50,14 @@ class ContactsManager:
alias = '' alias = ''
item = self.create_friend_item() item = self.create_friend_item()
name = alias or self._tox.friend_get_name(friend_number) or tox_id name = alias or self._tox.friend_get_name(friend_number) or tox_id
status_message = self._tox.friend_get_status_message(i) status_message = self._tox.friend_get_status_message(friend_number)
if not self._history.friend_exists_in_db(tox_id): self._history.get_message_getter(tox_id)
self._history.add_friend_to_db(tox_id) message_getter = self._history.get_message_getter(tox_id)
message_getter = self._history.messages_getter(tox_id)
friend = Friend(self._profile_manager, message_getter, friend_number, 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)
def load_groups(self): def _load_groups(self):
pass pass
def get_friend(self, num): def get_friend(self, num):
@ -57,8 +65,8 @@ class ContactsManager:
return None return None
return self._contacts[num] return self._contacts[num]
def get_curr_friend(self): def get_curr_contact(self):
return self._contacts[self._active_friend] if self._active_friend + 1 else None return self._contacts[self._active_contact] if self._active_contact + 1 else None
def save_profile(self): def save_profile(self):
data = self._tox.get_savedata() data = self._tox.get_savedata()
@ -69,20 +77,20 @@ class ContactsManager:
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def get_active(self): def get_active(self):
return self._active_friend return self._active_contact
def set_active(self, value=None): def set_active(self, value=None):
""" """
Change current active friend or update info Change current active friend or update info
:param value: number of new active friend in friend's list or None to update active user's data :param value: number of new active friend in friend's list or None to update active user's data
""" """
if value is None and self._active_friend == -1: # nothing to update if value is None and self._active_contact == -1: # nothing to update
return return
if value == -1: # all friends were deleted if value == -1: # all friends were deleted
self._screen.account_name.setText('') self._screen.account_name.setText('')
self._screen.account_status.setText('') self._screen.account_status.setText('')
self._screen.account_status.setToolTip('') self._screen.account_status.setToolTip('')
self._active_friend = -1 self._active_contact = -1
self._screen.account_avatar.setHidden(True) self._screen.account_avatar.setHidden(True)
self._messages.clear() self._messages.clear()
self._screen.messageEdit.clear() self._screen.messageEdit.clear()
@ -91,16 +99,16 @@ class ContactsManager:
self.send_typing(False) self.send_typing(False)
self._screen.typing.setVisible(False) self._screen.typing.setVisible(False)
if value is not None: if value is not None:
if self._active_friend + 1 and self._active_friend != value: if self._active_contact + 1 and self._active_contact != value:
try: try:
self.get_curr_friend().curr_text = self._screen.messageEdit.toPlainText() self.get_curr_friend().curr_text = self._screen.messageEdit.toPlainText()
except: except:
pass pass
friend = self._contacts[value] friend = self._contacts[value]
friend.remove_invalid_unsent_files() friend.remove_invalid_unsent_files()
if self._active_friend != value: if self._active_contact != value:
self._screen.messageEdit.setPlainText(friend.curr_text) self._screen.messageEdit.setPlainText(friend.curr_text)
self._active_friend = value self._active_contact = value
friend.reset_messages() friend.reset_messages()
if not self._settings['save_history']: if not self._settings['save_history']:
friend.delete_old_messages() friend.delete_old_messages()
@ -166,14 +174,14 @@ class ContactsManager:
for i in range(len(self._contacts)): for i in range(len(self._contacts)):
c = self._contacts[i] c = self._contacts[i]
if c.number == number and (type(c) is Friend == is_friend): if c.number == number and (type(c) is Friend == is_friend):
self._active_friend = i self._active_contact = i
break break
active_friend = property(get_active, set_active) active_friend = property(get_active, set_active)
def update(self): def update(self):
if self._active_friend + 1: if self._active_contact + 1:
self.set_active(self._active_friend) self.set_active(self._active_contact)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Filtration # Filtration
@ -187,7 +195,7 @@ class ContactsManager:
""" """
filter_str = filter_str.lower() filter_str = filter_str.lower()
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:
if sorting & 2: if sorting & 2:
self._contacts = sorted(self._contacts, key=lambda x: int(x.status is not None), reverse=True) self._contacts = sorted(self._contacts, key=lambda x: int(x.status is not None), reverse=True)
@ -216,10 +224,10 @@ class ContactsManager:
for index, friend in enumerate(self._contacts): for index, friend in enumerate(self._contacts):
friend.visibility = (friend.status is not None or not (sorting & 1)) and (filter_str in friend.name.lower()) friend.visibility = (friend.status is not None or not (sorting & 1)) and (filter_str in friend.name.lower())
friend.visibility = friend.visibility or friend.messages or friend.actions friend.visibility = friend.visibility or friend.messages or friend.actions
if friend.visibility: # if friend.visibility:
self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250, self._friend_item_height)) # self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250, self._friend_item_height))
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
self._settings['sorting'] = self._sorting self._settings['sorting'] = self._sorting
self._settings.save() self._settings.save()
@ -236,7 +244,7 @@ class ContactsManager:
Method-factory Method-factory
:return: new widget for friend instance :return: new widget for friend instance
""" """
return self._factory.friend_item() return None #self._factory.friend_item()
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Friend getters # Friend getters
@ -246,19 +254,19 @@ class ContactsManager:
return list(filter(lambda x: x.number == num and type(x) is Friend, self._contacts))[0] return list(filter(lambda x: x.number == num and type(x) is Friend, self._contacts))[0]
def get_last_message(self): def get_last_message(self):
if self._active_friend + 1: if self._active_contact + 1:
return self.get_curr_friend().get_last_message_text() return self.get_curr_friend().get_last_message_text()
else: else:
return '' return ''
def get_active_number(self): def get_active_number(self):
return self.get_curr_friend().number if self._active_friend + 1 else -1 return self.get_curr_friend().number if self._active_contact + 1 else -1
def get_active_name(self): def get_active_name(self):
return self.get_curr_friend().name if self._active_friend + 1 else '' return self.get_curr_friend().name if self._active_contact + 1 else ''
def is_active_online(self): def is_active_online(self):
return self._active_friend + 1 and self.get_curr_friend().status is not None return self._active_contact + 1 and self.get_curr_friend().status is not None
def new_name(self, number, name): def new_name(self, number, name):
friend = self.get_friend_by_number(number) friend = self.get_friend_by_number(number)
@ -333,7 +341,7 @@ class ContactsManager:
self._tox.friend_delete(friend.number) self._tox.friend_delete(friend.number)
del self._contacts[num] del self._contacts[num]
self._screen.friends_list.takeItem(num) self._screen.friends_list.takeItem(num)
if num == self._active_friend: # active friend was deleted if num == self._active_contact: # active friend was deleted
if not len(self._contacts): # last friend was deleted if not len(self._contacts): # last friend was deleted
self.set_active(-1) self.set_active(-1)
else: else:
@ -449,7 +457,7 @@ class ContactsManager:
""" """
Send typing notification to a friend Send typing notification to a friend
""" """
if self._settings['typing_notifications'] and self._active_friend + 1: if self._settings['typing_notifications'] and self._active_contact + 1:
try: try:
friend = self.get_curr_friend() friend = self.get_curr_friend()
if friend.status is not None: if friend.status is not None:

View file

@ -3,9 +3,10 @@ from contacts.friend import Friend
class FriendFactory: class FriendFactory:
def __init__(self, history, profile_manager, settings, tox): def __init__(self, profile_manager, settings, tox, db):
self._history, self._profile_manager = history, profile_manager self._profile_manager = profile_manager
self._settings, self._tox = settings, tox self._settings, self._tox = settings, tox
self._db = db
def create_friend_by_number(self, friend_number): def create_friend_by_number(self, friend_number):
aliases = self._settings['friends_aliases'] aliases = self._settings['friends_aliases']
@ -17,9 +18,7 @@ class FriendFactory:
item = self.create_friend_item() item = self.create_friend_item()
name = alias or self._tox.friend_get_name(friend_number) or tox_id name = alias or self._tox.friend_get_name(friend_number) or tox_id
status_message = self._tox.friend_get_status_message(friend_number) status_message = self._tox.friend_get_status_message(friend_number)
if not self._history.friend_exists_in_db(tox_id): message_getter = self._db.messages_getter(tox_id)
self._history.add_friend_to_db(tox_id)
message_getter = self._history.messages_getter(tox_id)
friend = Friend(self._profile_manager, message_getter, friend_number, 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)

View file

@ -16,6 +16,7 @@ import cv2
import threading import threading
from contacts.group_chat import * from contacts.group_chat import *
import re import re
import util.ui as util_ui
class Profile(basecontact.BaseContact): class Profile(basecontact.BaseContact):
@ -69,7 +70,7 @@ class Profile(basecontact.BaseContact):
tmp = self.name tmp = self.name
super(Profile, self).set_name(value.encode('utf-8')) super(Profile, self).set_name(value.encode('utf-8'))
self._tox.self_set_name(self._name.encode('utf-8')) self._tox.self_set_name(self._name.encode('utf-8'))
message = QtWidgets.QApplication.translate("MainWindow", 'User {} is now known as {}') message = util_ui.tr('User {} is now known as {}')
message = message.format(tmp, value) message = message.format(tmp, value)
for friend in self._contacts: for friend in self._contacts:
friend.append_message(InfoMessage(message, time.time())) friend.append_message(InfoMessage(message, time.time()))
@ -290,14 +291,9 @@ class Profile(basecontact.BaseContact):
""" """
for friend in self._contacts: for friend in self._contacts:
self.friend_exit(friend.number) self.friend_exit(friend.number)
self._call.stop()
del self._call
del self._tox del self._tox
self._tox = restart() self._tox = restart()
self._call = calls.AV(self._tox.AV)
self.status = None self.status = None
for friend in self._contacts:
friend.number = self._tox.friend_by_public_key(friend.tox_id) # numbers update
self._contacts_manager.update_filtration() self._contacts_manager.update_filtration()
def reconnect(self): def reconnect(self):
@ -315,9 +311,6 @@ class Profile(basecontact.BaseContact):
if hasattr(self, '_call'): if hasattr(self, '_call'):
self._call.stop() self._call.stop()
del self._call del self._call
s = Settings.get_instance()
s['paused_file_transfers'] = dict(self._paused_file_transfers) if s['resend_files'] else {}
s.save()
def reset_avatar(self): def reset_avatar(self):
super().reset_avatar() super().reset_avatar()

View file

@ -1,6 +1,6 @@
from file_transfers.file_transfers import * from file_transfers.file_transfers import *
from messenger.messages import * from messenger.messages import *
from history.database import MESSAGE_OWNER from history.database import MESSAGE_AUTHOR
import os import os
import util.util as util import util.util as util
@ -15,6 +15,13 @@ class FileTransfersHandler:
# key = (friend number, file number), value - transfer instance # key = (friend number, file number), value - transfer instance
self._paused_file_transfers = dict(settings['paused_file_transfers']) self._paused_file_transfers = dict(settings['paused_file_transfers'])
# key - file id, value: [path, friend number, is incoming, start position] # key - file id, value: [path, friend number, is incoming, start position]
def __del__(self):
self._settings['paused_file_transfers'] = self._paused_file_transfers if self._settings['resend_files'] else {}
self._settings.save()
def _get_friend_by_number(self, friend_number):
return self._contact_provider.get_friend_by_number(friend_number)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# File transfers support # File transfers support
@ -41,7 +48,7 @@ class FileTransfersHandler:
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(None, data[0], friend_number, file_number, size, False, pos)
tm = TransferMessage(MESSAGE_OWNER['FRIEND'], tm = TransferMessage(MESSAGE_AUTHOR['FRIEND'],
time.time(), time.time(),
TOX_FILE_TRANSFER_STATE['RUNNING'], TOX_FILE_TRANSFER_STATE['RUNNING'],
size, size,
@ -50,7 +57,7 @@ class FileTransfersHandler:
file_number) file_number)
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(None, '', friend_number, file_number, size, True)
tm = TransferMessage(MESSAGE_OWNER['FRIEND'], tm = TransferMessage(MESSAGE_AUTHOR['FRIEND'],
time.time(), time.time(),
TOX_FILE_TRANSFER_STATE['RUNNING'], TOX_FILE_TRANSFER_STATE['RUNNING'],
size, size,
@ -61,7 +68,7 @@ class FileTransfersHandler:
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(None, path + '/' + file_name, friend_number, file_number, size)
tm = TransferMessage(MESSAGE_OWNER['FRIEND'], tm = TransferMessage(MESSAGE_AUTHOR['FRIEND'],
time.time(), time.time(),
TOX_FILE_TRANSFER_STATE['RUNNING'], TOX_FILE_TRANSFER_STATE['RUNNING'],
size, size,
@ -69,7 +76,7 @@ class FileTransfersHandler:
friend_number, friend_number,
file_number) file_number)
else: else:
tm = TransferMessage(MESSAGE_OWNER['FRIEND'], tm = TransferMessage(MESSAGE_AUTHOR['FRIEND'],
time.time(), time.time(),
TOX_FILE_TRANSFER_STATE['INCOMING_NOT_STARTED'], TOX_FILE_TRANSFER_STATE['INCOMING_NOT_STARTED'],
size, size,
@ -180,7 +187,6 @@ class FileTransfersHandler:
:param data: raw data - png :param data: raw data - png
""" """
self.send_inline(data, 'toxygen_inline.png') self.send_inline(data, 'toxygen_inline.png')
self._messages.repaint()
def send_sticker(self, path): def send_sticker(self, path):
with open(path, 'rb') as fl: with open(path, 'rb') as fl:
@ -200,7 +206,7 @@ class FileTransfersHandler:
st = SendFromBuffer(self._tox, friend.number, data, file_name) st = SendFromBuffer(self._tox, friend.number, data, file_name)
st.set_transfer_finished_handler(self.transfer_finished) st.set_transfer_finished_handler(self.transfer_finished)
self._file_transfers[(friend.number, st.get_file_number())] = st self._file_transfers[(friend.number, st.get_file_number())] = st
tm = TransferMessage(MESSAGE_OWNER['ME'], tm = TransferMessage(MESSAGE_AUTHOR['ME'],
time.time(), time.time(),
TOX_FILE_TRANSFER_STATE['OUTGOING_NOT_STARTED'], TOX_FILE_TRANSFER_STATE['OUTGOING_NOT_STARTED'],
len(data), len(data),
@ -233,7 +239,7 @@ class FileTransfersHandler:
st = SendTransfer(path, self._tox, friend_number, TOX_FILE_KIND['DATA'], file_id) st = SendTransfer(path, self._tox, friend_number, TOX_FILE_KIND['DATA'], file_id)
st.set_transfer_finished_handler(self.transfer_finished) st.set_transfer_finished_handler(self.transfer_finished)
self._file_transfers[(friend_number, st.get_file_number())] = st self._file_transfers[(friend_number, st.get_file_number())] = st
tm = TransferMessage(MESSAGE_OWNER['ME'], tm = TransferMessage(MESSAGE_AUTHOR['ME'],
time.time(), time.time(),
TOX_FILE_TRANSFER_STATE['OUTGOING_NOT_STARTED'], TOX_FILE_TRANSFER_STATE['OUTGOING_NOT_STARTED'],
os.path.getsize(path), os.path.getsize(path),
@ -293,6 +299,7 @@ class FileTransfersHandler:
def send_avatar(self, friend_number, avatar_path=None): def send_avatar(self, friend_number, avatar_path=None):
""" """
:param friend_number: number of friend who should get new avatar :param friend_number: number of friend who should get new avatar
:param avatar_path: path to avatar or None if reset
""" """
sa = SendAvatar(avatar_path, self._tox, friend_number) sa = SendAvatar(avatar_path, self._tox, friend_number)
self._file_transfers[(friend_number, sa.get_file_number())] = sa self._file_transfers[(friend_number, sa.get_file_number())] = sa
@ -312,6 +319,3 @@ class FileTransfersHandler:
self.get_friend_by_number(friend_number).load_avatar() self.get_friend_by_number(friend_number).load_avatar()
if self.get_active_number() == friend_number and self.is_active_a_friend(): if self.get_active_number() == friend_number and self.is_active_a_friend():
self.set_active(None) self.set_active(None)
def _get_friend_by_number(self, friend_number):
return self._contact_provider.get_friend_by_number(friend_number)

View file

@ -1,32 +1,31 @@
from sqlite3 import connect from sqlite3 import connect
from user_data import settings
from os import chdir
import os.path import os.path
import util.util as util
PAGE_SIZE = 42
TIMEOUT = 11 TIMEOUT = 11
SAVE_MESSAGES = 500 SAVE_MESSAGES = 500
MESSAGE_OWNER = { MESSAGE_AUTHOR = {
'ME': 0, 'ME': 0,
'FRIEND': 1, 'FRIEND': 1,
'NOT_SENT': 2, 'NOT_SENT': 2,
'GC_PEER': 3 'GC_PEER': 3
} }
# TODO: unique message id and ngc support, profile name as db name CONTACT_TYPE = {
'FRIEND': 0,
'GC_PEER': 1,
'GC_PEER_PRIVATE': 2
}
class Database: class Database:
def __init__(self, name, toxes): def __init__(self, path, toxes):
self._name = name self._path, self._toxes = path, toxes
self._toxes = toxes self._name = os.path.basename(path)
chdir(settings.ProfileManager.get_path())
path = settings.ProfileManager.get_path() + self._name + '.hstr'
if os.path.exists(path): if os.path.exists(path):
try: try:
with open(path, 'rb') as fin: with open(path, 'rb') as fin:
@ -35,28 +34,35 @@ class Database:
data = toxes.pass_decrypt(data) data = toxes.pass_decrypt(data)
with open(path, 'wb') as fout: with open(path, 'wb') as fout:
fout.write(data) fout.write(data)
except: except Exception as ex:
util.log('Db reading error: ' + str(ex))
os.remove(path) os.remove(path)
db = connect(name + '.hstr', timeout=TIMEOUT) db = self._connect()
cursor = db.cursor() cursor = db.cursor()
cursor.execute('CREATE TABLE IF NOT EXISTS friends(' cursor.execute('CREATE TABLE IF NOT EXISTS contacts ('
' tox_id TEXT PRIMARY KEY' ' tox_id TEXT PRIMARY KEY,'
' contact_type INTEGER'
')') ')')
db.close() db.close()
def _connect(self):
return connect(self._path, timeout=TIMEOUT)
# -----------------------------------------------------------------------------------------------------------------
# Public methods
# -----------------------------------------------------------------------------------------------------------------
def save(self): def save(self):
if self._toxes.has_password(): if self._toxes.has_password():
path = settings.ProfileManager.get_path() + self._name + '.hstr' with open(self._path, 'rb') as fin:
with open(path, 'rb') as fin:
data = fin.read() data = fin.read()
data = self._toxes.pass_encrypt(bytes(data)) data = self._toxes.pass_encrypt(bytes(data))
with open(path, 'wb') as fout: with open(self._path, 'wb') as fout:
fout.write(data) fout.write(data)
def export(self, directory): def export(self, directory):
path = settings.ProfileManager.get_path() + self._name + '.hstr' new_path = util.join_path(directory, self._name)
new_path = directory + self._name + '.hstr' with open(self._path, 'rb') as fin:
with open(path, 'rb') as fin:
data = fin.read() data = fin.read()
if self._toxes.has_password(): if self._toxes.has_password():
data = self._toxes.pass_encrypt(data) data = self._toxes.pass_encrypt(data)
@ -64,15 +70,16 @@ class Database:
fout.write(data) fout.write(data)
def add_friend_to_db(self, tox_id): def add_friend_to_db(self, tox_id):
chdir(settings.ProfileManager.get_path()) db = self._connect()
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
cursor.execute('INSERT INTO friends VALUES (?);', (tox_id, )) cursor.execute('INSERT INTO contacts VALUES (?);', (tox_id, ))
cursor.execute('CREATE TABLE id' + tox_id + '(' cursor.execute('CREATE TABLE id' + tox_id + '('
' id INTEGER PRIMARY KEY,' ' id INTEGER PRIMARY KEY,'
' message_id INTEGER,'
' author_name TEXT,'
' message TEXT,' ' message TEXT,'
' owner INTEGER,' ' author INTEGER,'
' unix_time REAL,' ' unix_time REAL,'
' message_type INTEGER' ' message_type INTEGER'
')') ')')
@ -84,11 +91,10 @@ class Database:
db.close() db.close()
def delete_friend_from_db(self, tox_id): def delete_friend_from_db(self, tox_id):
chdir(settings.ProfileManager.get_path()) db = self._connect()
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
cursor.execute('DELETE FROM friends WHERE tox_id=?;', (tox_id, )) cursor.execute('DELETE FROM contacts WHERE tox_id=?;', (tox_id, ))
cursor.execute('DROP TABLE id' + tox_id + ';') cursor.execute('DROP TABLE id' + tox_id + ';')
db.commit() db.commit()
except: except:
@ -98,21 +104,20 @@ class Database:
db.close() db.close()
def friend_exists_in_db(self, tox_id): def friend_exists_in_db(self, tox_id):
chdir(settings.ProfileManager.get_path()) db = self._connect()
db = connect(self._name + '.hstr', timeout=TIMEOUT)
cursor = db.cursor() cursor = db.cursor()
cursor.execute('SELECT 0 FROM friends WHERE tox_id=?', (tox_id, )) cursor.execute('SELECT 1 FROM contacts WHERE tox_id=?', (tox_id, ))
result = cursor.fetchone() result = cursor.fetchone()
db.close() db.close()
return result is not None return result is not None
def save_messages_to_db(self, tox_id, messages_iter): def save_messages_to_db(self, tox_id, messages_iter):
chdir(settings.ProfileManager.get_path()) db = self._connect()
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
cursor.executemany('INSERT INTO id' + tox_id + '(message, owner, unix_time, message_type) ' cursor.executemany('INSERT INTO id' + tox_id +
'VALUES (?, ?, ?, ?);', messages_iter) '(message, message_id, author_name, author, unix_time, message_type) ' +
'VALUES (?, ?, ?, ?, ?, ?);', messages_iter)
db.commit() db.commit()
except: except:
print('Database is locked!') print('Database is locked!')
@ -120,13 +125,12 @@ class Database:
finally: finally:
db.close() db.close()
def update_messages(self, tox_id, unsent_time): def update_messages(self, tox_id, message_id):
chdir(settings.ProfileManager.get_path()) db = self._connect()
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
cursor.execute('UPDATE id' + tox_id + ' SET owner = 0 ' cursor.execute('UPDATE id' + tox_id + ' SET author = 0 '
'WHERE unix_time < ' + str(unsent_time) + ' AND owner = 2;') 'WHERE message_id = ' + str(message_id) + ' AND author = 2;')
db.commit() db.commit()
except: except:
print('Database is locked!') print('Database is locked!')
@ -134,13 +138,11 @@ class Database:
finally: finally:
db.close() db.close()
def delete_message(self, tox_id, message_id): def delete_message(self, tox_id, unique_id):
chdir(settings.ProfileManager.get_path()) db = self._connect()
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
cursor.execute('DELETE FROM id' + tox_id + ' WHERE unix_time < ' + end + ' AND unix_time > ' + cursor.execute('DELETE FROM id' + tox_id + ' WHERE id = ' + str(unique_id) + ';')
start + ';')
db.commit() db.commit()
except: except:
print('Database is locked!') print('Database is locked!')
@ -149,8 +151,7 @@ class Database:
db.close() db.close()
def delete_messages(self, tox_id): def delete_messages(self, tox_id):
chdir(settings.ProfileManager.get_path()) db = self._connect()
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
cursor.execute('DELETE FROM id' + tox_id + ';') cursor.execute('DELETE FROM id' + tox_id + ';')
@ -162,46 +163,44 @@ class Database:
db.close() db.close()
def messages_getter(self, tox_id): def messages_getter(self, tox_id):
return Database.MessageGetter(self._name, tox_id) return Database.MessageGetter(self._path, tox_id)
# -----------------------------------------------------------------------------------------------------------------
# Messages loading
# -----------------------------------------------------------------------------------------------------------------
class MessageGetter: class MessageGetter:
def __init__(self, name, tox_id): def __init__(self, path, tox_id):
self._count = 0 self._count = 0
self._name = name self._path = path
self._tox_id = tox_id self._tox_id = tox_id
self._db = self._cursor = None self._db = self._cursor = None
def connect(self): def _connect(self):
chdir(settings.ProfileManager.get_path()) self._db = connect(self._path, timeout=TIMEOUT)
self._db = connect(self._name + '.hstr', timeout=TIMEOUT)
self._cursor = self._db.cursor() self._cursor = self._db.cursor()
self._cursor.execute('SELECT message, owner, unix_time, message_type FROM id' + self._tox_id + self._cursor.execute('SELECT id, message_id, message, author, unix_time, message_type FROM id' +
' ORDER BY unix_time DESC;') self._tox_id + ' ORDER BY unix_time DESC;')
def disconnect(self): def _disconnect(self):
self._db.close() self._db.close()
def get_one(self): def get_one(self):
self.connect() return self.get(1)
self.skip()
data = self._cursor.fetchone()
self._count += 1
self.disconnect()
return data
def get_all(self): def get_all(self):
self.connect() self._connect()
data = self._cursor.fetchall() data = self._cursor.fetchall()
self.disconnect() self._disconnect()
self._count = len(data) self._count = len(data)
return data return data
def get(self, count): def get(self, count):
self.connect() self._connect()
self.skip() self.skip()
data = self._cursor.fetchmany(count) data = self._cursor.fetchmany(count)
self.disconnect() self._disconnect()
self._count += len(data) self._count += len(data)
return data return data

View file

@ -1,11 +1,17 @@
from messenger.messages import * from messenger.messages import *
# TODO: fix history loading and saving
class HistoryLoader: class HistoryLoader:
def __init__(self, db, settings): def __init__(self, contact_provider, db, settings):
self._contact_provider = contact_provider
self._db = db self._db = db
self._settings = settings self._settings = settings
def __del__(self):
del self._db
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# History support # History support
@ -15,22 +21,20 @@ class HistoryLoader:
""" """
Save history to db Save history to db
""" """
if hasattr(self, '_history'): if self._settings['save_db']:
if self._settings['save_history']: for friend in self._contact_provider.get_all_friends():
for friend in filter(lambda x: type(x) is Friend, self._contacts): if not self._db.friend_exists_in_db(friend.tox_id):
if not self._history.friend_exists_in_db(friend.tox_id): self._db.add_friend_to_db(friend.tox_id)
self._history.add_friend_to_db(friend.tox_id) if not self._settings['save_unsent_only']:
if not self._settings['save_unsent_only']: messages = friend.get_corr_for_saving()
messages = friend.get_corr_for_saving() else:
else: messages = friend.get_unsent_messages_for_saving()
messages = friend.get_unsent_messages_for_saving() self._db.delete_messages(friend.tox_id)
self._history.delete_messages(friend.tox_id) self._db.save_messages_to_db(friend.tox_id, messages)
self._history.save_messages_to_db(friend.tox_id, messages) unsent_messages = friend.get_unsent_messages()
unsent_messages = friend.get_unsent_messages() # unsent_time = unsent_messages[0].get_data()[2] if len(unsent_messages) else time.time() + 1
unsent_time = unsent_messages[0].get_data()[2] if len(unsent_messages) else time.time() + 1 # self._db.update_messages(friend.tox_id, unsent_time)
self._history.update_messages(friend.tox_id, unsent_time) self._db.save()
self._history.save()
del self._history
def clear_history(self, friend, save_unsent=False): def clear_history(self, friend, save_unsent=False):
""" """
@ -45,9 +49,9 @@ class HistoryLoader:
""" """
Tries to load next part of messages Tries to load next part of messages
""" """
if not self._load_history: if not self._load_db:
return return
self._load_history = False self._load_db = False
friend = self.get_curr_friend() friend = self.get_curr_friend()
friend.load_corr(False) friend.load_corr(False)
data = friend.get_corr() data = friend.get_corr()
@ -84,9 +88,16 @@ class HistoryLoader:
'', '',
data[3], data[3],
False) False)
self._load_history = True self._load_db = True
def export_history(self, friend, as_text=True, _range=None): def get_message_getter(self, friend_public_key):
if not self._db.friend_exists_in_db(friend_public_key):
self._db.add_friend_to_db(friend_public_key)
return self._db.messages_getter(friend_public_key)
@staticmethod
def export_history(friend, as_text=True, _range=None):
if _range is None: if _range is None:
friend.load_all_corr() friend.load_all_corr()
corr = friend.get_corr() corr = friend.get_corr()
@ -95,16 +106,28 @@ class HistoryLoader:
else: else:
corr = friend.get_corr()[_range[0]:] corr = friend.get_corr()[_range[0]:]
generator = TextHistoryGenerator() if as_text else HtmlHistoryGenerator generator = TextHistoryGenerator(corr) if as_text else HtmlHistoryGenerator(corr)
return generator.generate(corr) return generator.generate()
class HtmlHistoryGenerator: class HistoryLogsGenerator:
def generate(self, corr): def __init__(self, history):
self._history = history
def generate(self):
return str()
class HtmlHistoryGenerator(HistoryLogsGenerator):
def __init__(self, history):
super().__init__(history)
def generate(self):
arr = [] arr = []
for message in corr: for message in self._history:
if type(message) is TextMessage: if type(message) is TextMessage:
data = message.get_data() data = message.get_data()
x = '[{}] <b>{}:</b> {}<br>' x = '[{}] <b>{}:</b> {}<br>'
@ -117,11 +140,14 @@ class HtmlHistoryGenerator:
return s return s
class TextHistoryGenerator: class TextHistoryGenerator(HistoryLogsGenerator):
def generate(self, corr): def __init__(self, history):
super().__init__(history)
def generate(self):
arr = [] arr = []
for message in corr: for message in self._history:
if type(message) is TextMessage: if type(message) is TextMessage:
data = message.get_data() data = message.get_data()
x = '[{}] {}: {}\n' x = '[{}] {}: {}\n'

View file

@ -1,4 +1,4 @@
from history.database import MESSAGE_OWNER from history.database import MESSAGE_AUTHOR
MESSAGE_TYPE = { MESSAGE_TYPE = {
@ -9,6 +9,8 @@ MESSAGE_TYPE = {
'INFO_MESSAGE': 4 'INFO_MESSAGE': 4
} }
PAGE_SIZE = 42
class MessageAuthor: class MessageAuthor:
@ -53,7 +55,7 @@ class Message:
self._widget = None self._widget = None
def mark_as_sent(self): def mark_as_sent(self):
self._author.author_type = MESSAGE_OWNER['ME'] self._author.author_type = MESSAGE_AUTHOR['ME']
def _create_widget(self): def _create_widget(self):
pass pass

View file

@ -377,6 +377,10 @@ def init_callbacks(tox, profile, settings, plugin_loader, contacts_manager,
:param tox: Tox instance :param tox: Tox instance
:param profile: Profile instance :param profile: Profile instance
:param settings: Settings instance :param settings: Settings instance
:param contacts_manager: ContactsManager instance
:param contacts_manager: ContactsManager instance
:param calls_manager: CallsManager instance
:param file_transfer_handler: FileTransferHandler instance
:param plugin_loader: PluginLoader instance :param plugin_loader: PluginLoader instance
:param main_window: main window screen :param main_window: main window screen
:param tray: tray (for notifications) :param tray: tray (for notifications)

View file

@ -11,7 +11,7 @@ from util.util import curr_directory
class IncomingCallWidget(widgets.CenteredWidget): class IncomingCallWidget(widgets.CenteredWidget):
def __init__(self, friend_number, text, name): def __init__(self, friend_number, text, name):
super(IncomingCallWidget, self).__init__() super().__init__()
self.setWindowFlags(QtCore.Qt.CustomizeWindowHint | QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowStaysOnTopHint) self.setWindowFlags(QtCore.Qt.CustomizeWindowHint | QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowStaysOnTopHint)
self.resize(QtCore.QSize(500, 270)) self.resize(QtCore.QSize(500, 270))
self.avatar_label = QtWidgets.QLabel(self) self.avatar_label = QtWidgets.QLabel(self)

View file

@ -360,7 +360,6 @@ class MainWindow(QtWidgets.QMainWindow):
if self._saved: if self._saved:
return return
self._saved = True self._saved = True
self.profile.save_history()
self.profile.close() self.profile.close()
self._settings['x'] = self.geometry().x() self._settings['x'] = self.geometry().x()
self._settings['y'] = self.geometry().y() self._settings['y'] = self.geometry().y()
@ -500,7 +499,7 @@ class MainWindow(QtWidgets.QMainWindow):
def show_menu(self): def show_menu(self):
if not hasattr(self, 'menu'): if not hasattr(self, 'menu'):
self.menu = DropdownMenu(self) self.menu = DropdownMenu(self)
self.menu.setGeometry(QtCore.QRect(0 if Settings.get_instance()['mirror_mode'] else 270, self.menu.setGeometry(QtCore.QRect(0 if self._settings['mirror_mode'] else 270,
self.height() - 120, self.height() - 120,
180, 180,
120)) 120))

View file

@ -2,14 +2,16 @@ from PyQt5 import QtCore, QtGui, QtWidgets
from ui.widgets import RubberBandWindow, create_menu, QRightClickButton, CenteredWidget, LineEdit from ui.widgets import RubberBandWindow, create_menu, QRightClickButton, CenteredWidget, LineEdit
from contacts.profile import Profile from contacts.profile import Profile
import smileys import smileys
import urllib
import util.util as util import util.util as util
import util.ui as util_ui
class MessageArea(QtWidgets.QPlainTextEdit): class MessageArea(QtWidgets.QPlainTextEdit):
"""User types messages here""" """User types messages here"""
def __init__(self, parent, form): def __init__(self, parent, form):
super(MessageArea, self).__init__(parent) super().__init__(parent)
self.parent = form self.parent = form
self.setAcceptDrops(True) self.setAcceptDrops(True)
self.timer = QtCore.QTimer(self) self.timer = QtCore.QTimer(self)
@ -76,15 +78,18 @@ class MessageArea(QtWidgets.QPlainTextEdit):
self.insertPlainText(text) self.insertPlainText(text)
def parse_file_name(self, file_name): def parse_file_name(self, file_name):
import urllib
if file_name.endswith('\r\n'): if file_name.endswith('\r\n'):
file_name = file_name[:-2] file_name = file_name[:-2]
file_name = urllib.parse.unquote(file_name) file_name = urllib.parse.unquote(file_name)
return file_name[8 if platform.system() == 'Windows' else 7:] return file_name[8 if util.get_platform() == 'Windows' else 7:]
class ScreenShotWindow(RubberBandWindow): class ScreenShotWindow(RubberBandWindow):
def __init__(self, file_transfer_handler, *args):
super().__init__(*args)
self._file_transfer_handler = file_transfer_handler
def closeEvent(self, *args): def closeEvent(self, *args):
if self.parent.isHidden(): if self.parent.isHidden():
self.parent.show() self.parent.show()
@ -104,7 +109,7 @@ class ScreenShotWindow(RubberBandWindow):
buffer = QtCore.QBuffer(byte_array) buffer = QtCore.QBuffer(byte_array)
buffer.open(QtCore.QIODevice.WriteOnly) buffer.open(QtCore.QIODevice.WriteOnly)
p.save(buffer, 'PNG') p.save(buffer, 'PNG')
Profile.get_instance().send_screenshot(bytes(byte_array.data())) self._file_transfer_handler.send_screenshot(bytes(byte_array.data()))
self.close() self.close()
@ -113,11 +118,10 @@ class SmileyWindow(QtWidgets.QWidget):
Smiley selection window Smiley selection window
""" """
def __init__(self, parent): def __init__(self, parent, smiley_loader):
super(SmileyWindow, self).__init__() super().__init__(parent)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint) self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
inst = smileys.SmileyLoader.get_instance() self.data = smiley_loader.get_smileys()
self.data = inst.get_smileys()
count = len(self.data) count = len(self.data)
if not count: if not count:
self.close() self.close()
@ -172,18 +176,18 @@ class SmileyWindow(QtWidgets.QWidget):
class MenuButton(QtWidgets.QPushButton): class MenuButton(QtWidgets.QPushButton):
def __init__(self, parent, enter): def __init__(self, parent, enter):
super(MenuButton, self).__init__(parent) super().__init__(parent)
self.enter = enter self.enter = enter
def enterEvent(self, event): def enterEvent(self, event):
self.enter() self.enter()
super(MenuButton, self).enterEvent(event) super().enterEvent(event)
class DropdownMenu(QtWidgets.QWidget): class DropdownMenu(QtWidgets.QWidget):
def __init__(self, parent): def __init__(self, parent):
super(DropdownMenu, self).__init__(parent) super().__init__(parent)
self.installEventFilter(self) self.installEventFilter(self)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint) self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setMaximumSize(120, 120) self.setMaximumSize(120, 120)
@ -245,7 +249,7 @@ class DropdownMenu(QtWidgets.QWidget):
class StickerItem(QtWidgets.QWidget): class StickerItem(QtWidgets.QWidget):
def __init__(self, fl): def __init__(self, fl):
super(StickerItem, self).__init__() super().__init__()
self._image_label = QtWidgets.QLabel(self) self._image_label = QtWidgets.QLabel(self)
self.path = fl self.path = fl
self.pixmap = QtGui.QPixmap() self.pixmap = QtGui.QPixmap()
@ -260,7 +264,7 @@ class StickerWindow(QtWidgets.QWidget):
"""Sticker selection window""" """Sticker selection window"""
def __init__(self, parent): def __init__(self, parent):
super(StickerWindow, self).__init__() super().__init__()
self.setWindowFlags(QtCore.Qt.FramelessWindowHint) self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setMaximumSize(250, 200) self.setMaximumSize(250, 200)
self.setMinimumSize(250, 200) self.setMinimumSize(250, 200)
@ -289,8 +293,9 @@ class StickerWindow(QtWidgets.QWidget):
class WelcomeScreen(CenteredWidget): class WelcomeScreen(CenteredWidget):
def __init__(self): def __init__(self, settings):
super().__init__() super().__init__()
self._settings = settings
self.setMaximumSize(250, 200) self.setMaximumSize(250, 200)
self.setMinimumSize(250, 200) self.setMinimumSize(250, 200)
self.center() self.center()
@ -300,51 +305,39 @@ class WelcomeScreen(CenteredWidget):
self.text.setOpenExternalLinks(True) self.text.setOpenExternalLinks(True)
self.checkbox = QtWidgets.QCheckBox(self) self.checkbox = QtWidgets.QCheckBox(self)
self.checkbox.setGeometry(QtCore.QRect(5, 170, 240, 30)) self.checkbox.setGeometry(QtCore.QRect(5, 170, 240, 30))
self.checkbox.setText(QtWidgets.QApplication.translate('WelcomeScreen', "Don't show again")) self.checkbox.setText(util_ui.tr( "Don't show again"))
self.setWindowTitle(QtWidgets.QApplication.translate('WelcomeScreen', 'Tip of the day')) self.setWindowTitle(util_ui.tr( 'Tip of the day'))
import random import random
num = random.randint(0, 10) num = random.randint(0, 10)
if num == 0: if num == 0:
text = QtWidgets.QApplication.translate('WelcomeScreen', 'Press Esc if you want hide app to tray.') text = util_ui.tr('Press Esc if you want hide app to tray.')
elif num == 1: elif num == 1:
text = QtWidgets.QApplication.translate('WelcomeScreen', text = util_ui.tr('Right click on screenshot button hides app to tray during screenshot.')
'Right click on screenshot button hides app to tray during screenshot.')
elif num == 2: elif num == 2:
text = QtWidgets.QApplication.translate('WelcomeScreen', text = util_ui.tr('You can use Tox over Tor. For more info read <a href="https://wiki.tox.chat/users/tox_over_tor_tot">this post</a>')
'You can use Tox over Tor. For more info read <a href="https://wiki.tox.chat/users/tox_over_tor_tot">this post</a>')
elif num == 3: elif num == 3:
text = QtWidgets.QApplication.translate('WelcomeScreen', text = util_ui.tr('Use Settings -> Interface to customize interface.')
'Use Settings -> Interface to customize interface.')
elif num == 4: elif num == 4:
text = QtWidgets.QApplication.translate('WelcomeScreen', text = util_ui.tr('Set profile password via Profile -> Settings. Password allows Toxygen encrypt your history and settings.')
'Set profile password via Profile -> Settings. Password allows Toxygen encrypt your history and settings.')
elif num == 5: elif num == 5:
text = QtWidgets.QApplication.translate('WelcomeScreen', text = util_ui.tr('Since v0.1.3 Toxygen supports plugins. <a href="https://github.com/toxygen-project/toxygen/blob/master/docs/plugins.md">Read more</a>')
'Since v0.1.3 Toxygen supports plugins. <a href="https://github.com/toxygen-project/toxygen/blob/master/docs/plugins.md">Read more</a>')
elif num == 6: elif num == 6:
text = QtWidgets.QApplication.translate('WelcomeScreen', text = util_ui.tr('Toxygen supports faux offline messages and file transfers. Send message or file to offline friend and he will get it later.')
'Toxygen supports faux offline messages and file transfers. Send message or file to offline friend and he will get it later.')
elif num == 7: elif num == 7:
text = QtWidgets.QApplication.translate('WelcomeScreen', text = util_ui.tr('New in Toxygen 0.4.1:<br>Downloading nodes from tox.chat<br>Bug fixes')
'New in Toxygen 0.4.1:<br>Downloading nodes from tox.chat<br>Bug fixes')
elif num == 8: elif num == 8:
text = QtWidgets.QApplication.translate('WelcomeScreen', text = util_ui.tr('Delete single message in chat: make right click on spinner or message time and choose "Delete" in menu')
'Delete single message in chat: make right click on spinner or message time and choose "Delete" in menu')
elif num == 9: elif num == 9:
text = QtWidgets.QApplication.translate('WelcomeScreen', text = util_ui.tr( 'Use right click on inline image to save it')
'Use right click on inline image to save it')
else: else:
text = QtWidgets.QApplication.translate('WelcomeScreen', text = util_ui.tr('Set new NoSpam to avoid spam friend requests: Profile -> Settings -> Set new NoSpam.')
'Set new NoSpam to avoid spam friend requests: Profile -> Settings -> Set new NoSpam.')
self.text.setHtml(text) self.text.setHtml(text)
self.checkbox.stateChanged.connect(self.not_show) self.checkbox.stateChanged.connect(self.not_show)
QtCore.QTimer.singleShot(1000, self.show) QtCore.QTimer.singleShot(1000, self.show)
def not_show(self): def not_show(self):
from user_data import settings self._settings['show_welcome_screen'] = False
s = settings.Settings.get_instance() self._settings.save()
s['show_welcome_screen'] = False
s.save()
class MainMenuButton(QtWidgets.QPushButton): class MainMenuButton(QtWidgets.QPushButton):
@ -417,7 +410,7 @@ class SearchScreen(QtWidgets.QWidget):
self.retranslateUi() self.retranslateUi()
def retranslateUi(self): def retranslateUi(self):
self.search_text.setPlaceholderText(QtWidgets.QApplication.translate("MainWindow", "Search")) self.search_text.setPlaceholderText(util_ui.tr('Search'))
def show(self): def show(self):
super().show() super().show()
@ -473,11 +466,4 @@ class SearchScreen(QtWidgets.QWidget):
@staticmethod @staticmethod
def not_found(text): def not_found(text):
mbox = QtWidgets.QMessageBox() util_ui.message_box(util_ui.tr('Text "{}" was not found').format(text), util_ui.tr('Not found'))
mbox_text = QtWidgets.QApplication.translate("MainWindow",
'Text "{}" was not found')
mbox.setText(mbox_text.format(text))
mbox.setWindowTitle(QtWidgets.QApplication.translate("MainWindow",
'Not found'))
mbox.exec_()

View file

@ -7,13 +7,15 @@ import pyaudio
from user_data import toxes from user_data import toxes
import plugin_support import plugin_support
import updater import updater
import util.ui as util_ui
class AddContact(CenteredWidget): class AddContact(CenteredWidget):
"""Add contact form""" """Add contact form"""
def __init__(self, tox_id=''): def __init__(self, contacts_manager, tox_id=''):
super(AddContact, self).__init__() super().__init__()
self._contacts_manager = contacts_manager
self.initUI(tox_id) self.initUI(tox_id)
self._adding = False self._adding = False
self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
@ -61,8 +63,10 @@ class AddContact(CenteredWidget):
if self._adding: if self._adding:
return return
self._adding = True self._adding = True
profile = Profile.get_instance() tox_id = self.tox_id.text().strip()
send = profile.send_friend_request(self.tox_id.text().strip(), self.message_edit.toPlainText()) if tox_id.startswith('tox:'):
tox_id = tox_id[4:]
send = self._contacts_manager.send_friend_request(tox_id, self.message_edit.toPlainText())
self._adding = False self._adding = False
if send is True: if send is True:
# request was successful # request was successful
@ -71,17 +75,18 @@ class AddContact(CenteredWidget):
self.error_label.setText(send) self.error_label.setText(send)
def retranslateUi(self): def retranslateUi(self):
self.setWindowTitle(QtWidgets.QApplication.translate('AddContact', "Add contact")) self.setWindowTitle(util_ui.tr('Add contact'))
self.sendRequestButton.setText(QtWidgets.QApplication.translate("Form", "Send request")) self.sendRequestButton.setText(util_ui.tr('Send request'))
self.label.setText(QtWidgets.QApplication.translate('AddContact', "TOX ID:")) self.label.setText(util_ui.tr('TOX ID:'))
self.message.setText(QtWidgets.QApplication.translate('AddContact', "Message:")) self.message.setText(util_ui.tr('Message:'))
self.tox_id.setPlaceholderText(QtWidgets.QApplication.translate('AddContact', "TOX ID or public key of contact")) self.tox_id.setPlaceholderText(util_ui.tr('TOX ID or public key of contact'))
class ProfileSettings(CenteredWidget): class ProfileSettings(CenteredWidget):
"""Form with profile settings such as name, status, TOX ID""" """Form with profile settings such as name, status, TOX ID"""
def __init__(self): def __init__(self, profile):
super(ProfileSettings, self).__init__() super().__init__()
self._profile = profile
self.initUI() self.initUI()
self.center() self.center()
@ -91,13 +96,12 @@ class ProfileSettings(CenteredWidget):
self.setMaximumSize(QtCore.QSize(700, 600)) self.setMaximumSize(QtCore.QSize(700, 600))
self.nick = LineEdit(self) self.nick = LineEdit(self)
self.nick.setGeometry(QtCore.QRect(30, 60, 350, 27)) self.nick.setGeometry(QtCore.QRect(30, 60, 350, 27))
profile = Profile.get_instance() self.nick.setText(self._profile.name)
self.nick.setText(profile.name)
self.status = QtWidgets.QComboBox(self) self.status = QtWidgets.QComboBox(self)
self.status.setGeometry(QtCore.QRect(400, 60, 200, 27)) self.status.setGeometry(QtCore.QRect(400, 60, 200, 27))
self.status_message = LineEdit(self) self.status_message = LineEdit(self)
self.status_message.setGeometry(QtCore.QRect(30, 130, 350, 27)) self.status_message.setGeometry(QtCore.QRect(30, 130, 350, 27))
self.status_message.setText(profile.status_message) self.status_message.setText(self._profile.status_message)
self.label = QtWidgets.QLabel(self) self.label = QtWidgets.QLabel(self)
self.label.setGeometry(QtCore.QRect(40, 30, 91, 25)) self.label.setGeometry(QtCore.QRect(40, 30, 91, 25))
font = QtGui.QFont() font = QtGui.QFont()
@ -164,37 +168,37 @@ class ProfileSettings(CenteredWidget):
self.auto = path + name == ProfileManager.get_path() + Settings.get_instance().name self.auto = path + name == ProfileManager.get_path() + Settings.get_instance().name
self.default.clicked.connect(self.auto_profile) self.default.clicked.connect(self.auto_profile)
self.retranslateUi() self.retranslateUi()
if profile.status is not None: if self._profile.status is not None:
self.status.setCurrentIndex(profile.status) self.status.setCurrentIndex(self._profile.status)
else: else:
self.status.setVisible(False) self.status.setVisible(False)
QtCore.QMetaObject.connectSlotsByName(self) QtCore.QMetaObject.connectSlotsByName(self)
def retranslateUi(self): def retranslateUi(self):
self.export.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Export profile")) self.export.setText(util_ui.tr("Export profile"))
self.setWindowTitle(QtWidgets.QApplication.translate("ProfileSettingsForm", "Profile settings")) self.setWindowTitle(util_ui.tr("Profile settings"))
self.label.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Name:")) self.label.setText(util_ui.tr("Name:"))
self.label_2.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Status:")) self.label_2.setText(util_ui.tr("Status:"))
self.label_3.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "TOX ID:")) self.label_3.setText(util_ui.tr("TOX ID:"))
self.copyId.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Copy TOX ID")) self.copyId.setText(util_ui.tr("Copy TOX ID"))
self.new_avatar.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "New avatar")) self.new_avatar.setText(util_ui.tr("New avatar"))
self.delete_avatar.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Reset avatar")) self.delete_avatar.setText(util_ui.tr("Reset avatar"))
self.new_nospam.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "New NoSpam")) self.new_nospam.setText(util_ui.tr("New NoSpam"))
self.profilepass.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Profile password")) self.profilepass.setText(util_ui.tr("Profile password"))
self.password.setPlaceholderText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Password (at least 8 symbols)")) self.password.setPlaceholderText(util_ui.tr("Password (at least 8 symbols)"))
self.confirm_password.setPlaceholderText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Confirm password")) self.confirm_password.setPlaceholderText(util_ui.tr("Confirm password"))
self.set_password.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Set password")) self.set_password.setText(util_ui.tr("Set password"))
self.not_match.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Passwords do not match")) self.not_match.setText(util_ui.tr("Passwords do not match"))
self.leave_blank.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Leaving blank will reset current password")) self.leave_blank.setText(util_ui.tr("Leaving blank will reset current password"))
self.warning.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "There is no way to recover lost passwords")) self.warning.setText(util_ui.tr("There is no way to recover lost passwords"))
self.status.addItem(QtWidgets.QApplication.translate("ProfileSettingsForm", "Online")) self.status.addItem(util_ui.tr("Online"))
self.status.addItem(QtWidgets.QApplication.translate("ProfileSettingsForm", "Away")) self.status.addItem(util_ui.tr("Away"))
self.status.addItem(QtWidgets.QApplication.translate("ProfileSettingsForm", "Busy")) self.status.addItem(util_ui.tr("Busy"))
self.copy_pk.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Copy public key")) self.copy_pk.setText(util_ui.tr("Copy public key"))
if self.auto: if self.auto:
self.default.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Mark as not default profile")) self.default.setText(util_ui.tr("Mark as not default profile"))
else: else:
self.default.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Mark as default profile")) self.default.setText(util_ui.tr("Mark as default profile"))
def auto_profile(self): def auto_profile(self):
if self.auto: if self.auto:
@ -203,10 +207,10 @@ class ProfileSettings(CenteredWidget):
Settings.set_auto_profile(ProfileManager.get_path(), Settings.get_instance().name) Settings.set_auto_profile(ProfileManager.get_path(), Settings.get_instance().name)
self.auto = not self.auto self.auto = not self.auto
if self.auto: if self.auto:
self.default.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Mark as not default profile")) self.default.setText(util_ui.tr("Mark as not default profile"))
else: else:
self.default.setText( self.default.setText(
QtWidgets.QApplication.translate("ProfileSettingsForm", "Mark as default profile")) util_ui.tr("Mark as default profile"))
def new_password(self): def new_password(self):
if self.password.text() == self.confirm_password.text(): if self.password.text() == self.confirm_password.text():
@ -216,10 +220,10 @@ class ProfileSettings(CenteredWidget):
self.close() self.close()
else: else:
self.not_match.setText( self.not_match.setText(
QtWidgets.QApplication.translate("ProfileSettingsForm", "Password must be at least 8 symbols")) util_ui.tr("Password must be at least 8 symbols"))
self.not_match.setVisible(True) self.not_match.setVisible(True)
else: else:
self.not_match.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Passwords do not match")) self.not_match.setText(util_ui.tr("Passwords do not match"))
self.not_match.setVisible(True) self.not_match.setVisible(True)
def copy(self): def copy(self):
@ -244,10 +248,10 @@ class ProfileSettings(CenteredWidget):
self.tox_id.setText(Profile.get_instance().new_nospam()) self.tox_id.setText(Profile.get_instance().new_nospam())
def reset_avatar(self): def reset_avatar(self):
Profile.get_instance().reset_avatar() self._profile.reset_avatar()
def set_avatar(self): def set_avatar(self):
choose = QtWidgets.QApplication.translate("ProfileSettingsForm", "Choose avatar") choose = util_ui.tr("Choose avatar")
name = QtWidgets.QFileDialog.getOpenFileName(self, choose, None, 'Images (*.png)', name = QtWidgets.QFileDialog.getOpenFileName(self, choose, None, 'Images (*.png)',
options=QtWidgets.QFileDialog.DontUseNativeDialog) options=QtWidgets.QFileDialog.DontUseNativeDialog)
if name[0]: if name[0]:
@ -262,21 +266,15 @@ class ProfileSettings(CenteredWidget):
Profile.get_instance().set_avatar(bytes(byte_array.data())) Profile.get_instance().set_avatar(bytes(byte_array.data()))
def export_profile(self): def export_profile(self):
directory = QtWidgets.QFileDialog.getExistingDirectory(self, '', curr_directory(), directory = util_ui.directory_dialog() + '/'
QtWidgets.QFileDialog.DontUseNativeDialog) + '/'
if directory != '/': if directory != '/':
reply = QtWidgets.QMessageBox.question(None, reply = util_ui.question(util_ui.tr('Do you want to move your profile to this location?'),
QtWidgets.QApplication.translate("ProfileSettingsForm", util_ui.tr('Use new path'))
'Use new path'),
QtWidgets.QApplication.translate("ProfileSettingsForm",
'Do you want to move your profile to this location?'),
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
settings = Settings.get_instance() settings = Settings.get_instance()
settings.export(directory) settings.export(directory)
profile = Profile.get_instance() profile = Profile.get_instance()
profile.export_db(directory) profile.export_db(directory)
ProfileManager.get_instance().export_profile(directory, reply == QtWidgets.QMessageBox.Yes) ProfileManager.get_instance().export_profile(directory, reply)
def closeEvent(self, event): def closeEvent(self, event):
profile = Profile.get_instance() profile = Profile.get_instance()
@ -287,8 +285,9 @@ class ProfileSettings(CenteredWidget):
class NetworkSettings(CenteredWidget): class NetworkSettings(CenteredWidget):
"""Network settings form: UDP, Ipv6 and proxy""" """Network settings form: UDP, Ipv6 and proxy"""
def __init__(self, reset): def __init__(self, settings, reset):
super(NetworkSettings, self).__init__() super().__init__()
self._settings = settings
self.reset = reset self.reset = reset
self.initUI() self.initUI()
self.center() self.center()
@ -323,35 +322,34 @@ class NetworkSettings(CenteredWidget):
self.reconnect = QtWidgets.QPushButton(self) self.reconnect = QtWidgets.QPushButton(self)
self.reconnect.setGeometry(QtCore.QRect(40, 230, 231, 30)) self.reconnect.setGeometry(QtCore.QRect(40, 230, 231, 30))
self.reconnect.clicked.connect(self.restart_core) self.reconnect.clicked.connect(self.restart_core)
settings = Settings.get_instance() self.ipv.setChecked(self._settings['ipv6_enabled'])
self.ipv.setChecked(settings['ipv6_enabled']) self.udp.setChecked(self._settings['udp_enabled'])
self.udp.setChecked(settings['udp_enabled']) self.proxy.setChecked(self._settings['proxy_type'])
self.proxy.setChecked(settings['proxy_type']) self.proxyip.setText(self._settings['proxy_host'])
self.proxyip.setText(settings['proxy_host']) self.proxyport.setText(str(self._settings['proxy_port']))
self.proxyport.setText(str(settings['proxy_port'])) self.http.setChecked(self._settings['proxy_type'] == 1)
self.http.setChecked(settings['proxy_type'] == 1)
self.warning = QtWidgets.QLabel(self) self.warning = QtWidgets.QLabel(self)
self.warning.setGeometry(QtCore.QRect(5, 270, 290, 60)) self.warning.setGeometry(QtCore.QRect(5, 270, 290, 60))
self.warning.setStyleSheet('QLabel { color: #BC1C1C; }') self.warning.setStyleSheet('QLabel { color: #BC1C1C; }')
self.nodes = QtWidgets.QCheckBox(self) self.nodes = QtWidgets.QCheckBox(self)
self.nodes.setGeometry(QtCore.QRect(20, 350, 270, 22)) self.nodes.setGeometry(QtCore.QRect(20, 350, 270, 22))
self.nodes.setChecked(settings['download_nodes_list']) self.nodes.setChecked(self._settings['download_nodes_list'])
self.retranslateUi() self.retranslateUi()
self.proxy.stateChanged.connect(lambda x: self.activate()) self.proxy.stateChanged.connect(lambda x: self.activate())
self.activate() self.activate()
QtCore.QMetaObject.connectSlotsByName(self) QtCore.QMetaObject.connectSlotsByName(self)
def retranslateUi(self): def retranslateUi(self):
self.setWindowTitle(QtWidgets.QApplication.translate("NetworkSettings", "Network settings")) self.setWindowTitle(util_ui.tr("Network settings"))
self.ipv.setText(QtWidgets.QApplication.translate("Form", "IPv6")) self.ipv.setText(util_ui.tr("IPv6"))
self.udp.setText(QtWidgets.QApplication.translate("Form", "UDP")) self.udp.setText(util_ui.tr("UDP"))
self.proxy.setText(QtWidgets.QApplication.translate("Form", "Proxy")) self.proxy.setText(util_ui.tr("Proxy"))
self.label.setText(QtWidgets.QApplication.translate("Form", "IP:")) self.label.setText(util_ui.tr("IP:"))
self.label_2.setText(QtWidgets.QApplication.translate("Form", "Port:")) self.label_2.setText(util_ui.tr("Port:"))
self.reconnect.setText(QtWidgets.QApplication.translate("NetworkSettings", "Restart TOX core")) self.reconnect.setText(util_ui.tr("Restart TOX core"))
self.http.setText(QtWidgets.QApplication.translate("Form", "HTTP")) self.http.setText(util_ui.tr("HTTP"))
self.nodes.setText(QtWidgets.QApplication.translate("Form", "Download nodes list from tox.chat")) self.nodes.setText(util_ui.tr("Download nodes list from tox.chat"))
self.warning.setText(QtWidgets.QApplication.translate("Form", "WARNING:\nusing proxy with enabled UDP\ncan produce IP leak")) self.warning.setText(util_ui.tr("WARNING:\nusing proxy with enabled UDP\ncan produce IP leak"))
def activate(self): def activate(self):
bl = self.proxy.isChecked() bl = self.proxy.isChecked()
@ -361,14 +359,13 @@ class NetworkSettings(CenteredWidget):
def restart_core(self): def restart_core(self):
try: try:
settings = Settings.get_instance() self._settings['ipv6_enabled'] = self.ipv.isChecked()
settings['ipv6_enabled'] = self.ipv.isChecked() self._settings['udp_enabled'] = self.udp.isChecked()
settings['udp_enabled'] = self.udp.isChecked() self._settings['proxy_type'] = 2 - int(self.http.isChecked()) if self.proxy.isChecked() else 0
settings['proxy_type'] = 2 - int(self.http.isChecked()) if self.proxy.isChecked() else 0 self._settings['proxy_host'] = str(self.proxyip.text())
settings['proxy_host'] = str(self.proxyip.text()) self._settings['proxy_port'] = int(self.proxyport.text())
settings['proxy_port'] = int(self.proxyport.text()) self._settings['download_nodes_list'] = self.nodes.isChecked()
settings['download_nodes_list'] = self.nodes.isChecked() self._settings.save()
settings.save()
# recreate tox instance # recreate tox instance
Profile.get_instance().reset(self.reset) Profile.get_instance().reset(self.reset)
self.close() self.close()
@ -380,7 +377,7 @@ class PrivacySettings(CenteredWidget):
"""Privacy settings form: history, typing notifications""" """Privacy settings form: history, typing notifications"""
def __init__(self): def __init__(self):
super(PrivacySettings, self).__init__() super().__init__()
self.initUI() self.initUI()
self.center() self.center()

View file

@ -79,7 +79,7 @@ class QRightClickButton(QtWidgets.QPushButton):
class RubberBand(QtWidgets.QRubberBand): class RubberBand(QtWidgets.QRubberBand):
def __init__(self): def __init__(self):
super(RubberBand, self).__init__(QtWidgets.QRubberBand.Rectangle, None) super().__init__(QtWidgets.QRubberBand.Rectangle, None)
self.setPalette(QtGui.QPalette(QtCore.Qt.transparent)) self.setPalette(QtGui.QPalette(QtCore.Qt.transparent))
self.pen = QtGui.QPen(QtCore.Qt.blue, 4) self.pen = QtGui.QPen(QtCore.Qt.blue, 4)
self.pen.setStyle(QtCore.Qt.SolidLine) self.pen.setStyle(QtCore.Qt.SolidLine)

View file

@ -0,0 +1,27 @@
from ui.main_screen_widgets import *
from ui.menu import *
class WidgetsFactory:
def __init__(self, settings, profile, contacts_manager, file_transfer_handler, smiley_loader):
self._settings = settings
self._profile = profile
self._contacts_manager = contacts_manager
self._file_transfer_handler = file_transfer_handler
self._smiley_loader = smiley_loader
def create_screenshot_window(self, *args):
return ScreenShotWindow(self._file_transfer_handler, *args)
def create_smiley_window(self, parent):
return SmileyWindow(parent, self._smiley_loader)
def create_welcome_window(self):
return WelcomeScreen(self._settings)
def create_profile_settings_window(self):
return ProfileSettings(self._profile)
def create_network_settings_window(self):
return NetworkSettings(self._settings, self._profile.reset)

View file

@ -1,4 +1,5 @@
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
import util.util as util
def tr(s): def tr(s):
@ -25,4 +26,9 @@ def text_dialog(text, title='', default_value=''):
return text, ok return text, ok
def directory_dialog(caption=''):
return QtWidgets.QFileDialog.getExistingDirectory(None, caption, util.curr_directory(),
QtWidgets.QFileDialog.DontUseNativeDialog)
# TODO: move all dialogs here # TODO: move all dialogs here