refactoring - login screen, incorrect refs

This commit is contained in:
ingvar1995 2018-04-16 00:11:51 +03:00
parent 1bead7d55d
commit 85467e1885
21 changed files with 302 additions and 254 deletions

View File

@ -1,50 +1,60 @@
import communication.callbacks
import threads import threads
from PyQt5 import QtWidgets, QtGui, QtCore
import ui.password_screen as passwordscreen
from util.util import curr_directory, get_platform, get_images_directory, get_styles_directory, log
import updater.updater as updater
import os
from communication.tox_factory import tox_factory
import wrapper.libtox as libtox
import user_data.toxes
from user_data.settings import Settings
from ui.login_screen import LoginScreen
from user_data.profile_manager import ProfileManager
class App: class App:
def __init__(self, path_or_uri=None): def __init__(self, path_to_profile=None, uri=None):
self.tox = self.ms = self.init = self.app = self.tray = self.mainloop = self.avloop = None self.tox = self.ms = self.init = self.app = self.tray = self.mainloop = self.avloop = None
if path_or_uri is None: self.uri = self.path = self.toxes = None
self.uri = self.path = None if uri is not None and uri.startswith('tox:'):
elif path_or_uri.startswith('tox:'): self.uri = uri[4:]
self.path = None if path_to_profile is not None:
self.uri = path_or_uri[4:] self.path = path_to_profile
else:
self.path = path_or_uri
self.uri = None
def enter_pass(self, data): def enter_pass(self, data):
""" """
Show password screen Show password screen
""" """
tmp = [data] p = passwordscreen.PasswordScreen(self.toxes, data)
p = PasswordScreen(toxes.ToxES.get_instance(), tmp)
p.show() p.show()
self.app.lastWindowClosed.connect(self.app.quit) self.app.lastWindowClosed.connect(self.app.quit)
self.app.exec_() self.app.exec_()
if tmp[0] == data: result = p.result
if result is None:
raise SystemExit() raise SystemExit()
else: else:
return tmp[0] return result
def main(self): def main(self):
""" """
Main function of app. loads login screen if needed and starts main screen Main function of app. loads login screen if needed and starts main screen
""" """
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication([])
app.setWindowIcon(QtGui.QIcon(curr_directory() + '/images/icon.png')) icon_file = os.path.join(get_images_directory(), 'icon.png')
app.setWindowIcon(QtGui.QIcon(icon_file))
self.app = app self.app = app
if platform.system() == 'Linux': if get_platform() == 'Linux':
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads) QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads)
with open(curr_directory() + '/styles/dark_style.qss') as fl: with open(os.path.join(get_styles_directory(), 'dark_style.qss')) as fl:
style = fl.read() style = fl.read()
app.setStyleSheet(style) app.setStyleSheet(style)
encrypt_save = toxes.ToxES() encrypt_save = libtox.LibToxEncryptSave()
toxes = user_data.toxes.ToxES(encrypt_save)
if self.path is not None: if self.path is not None:
path = os.path.dirname(self.path) + '/' path = os.path.dirname(self.path) + '/'
@ -70,15 +80,13 @@ class App:
ls = LoginScreen() ls = LoginScreen()
ls.setWindowIconText("Toxygen") ls.setWindowIconText("Toxygen")
profiles = ProfileManager.find_profiles() profiles = ProfileManager.find_profiles()
ls.update_select(map(lambda x: x[1], profiles)) ls.update_select(profiles)
_login = self.Login(profiles)
ls.update_on_close(_login.login_screen_close)
ls.show() ls.show()
app.exec_() app.exec_()
if not _login.t: result = ls.result
if result is None:
return return
elif _login.t == 1: # create new profile elif result.is_new_profile(): # create new profile
_login.name = _login.name.strip()
name = _login.name if _login.name else 'toxygen_user' name = _login.name if _login.name else 'toxygen_user'
pr = map(lambda x: x[1], ProfileManager.find_profiles()) pr = map(lambda x: x[1], ProfileManager.find_profiles())
if name in list(pr): if name in list(pr):
@ -130,14 +138,14 @@ class App:
settings['language'] = curr_lang settings['language'] = curr_lang
settings.save() settings.save()
else: # load existing profile else: # load existing profile
path, name = _login.get_data() path = result.profile_path
if _login.default: if result.load_as_default:
Settings.set_auto_profile(path, name) Settings.set_auto_profile(path)
data = ProfileManager(path, name).open_profile() settings = Settings(toxes, path)
if encrypt_save.is_data_encrypted(data): data = ProfileManager(settings, toxes, path).open_profile()
if toxes.is_data_encrypted(data):
data = self.enter_pass(data) data = self.enter_pass(data)
settings = Settings(name) self.tox = communication.tox_factory.tox_factory(data, settings)
self.tox = profile.tox_factory(data, settings)
else: else:
path, name = auto_profile path, name = auto_profile
data = ProfileManager(path, name).open_profile() data = ProfileManager(path, name).open_profile()

View File

@ -5,10 +5,7 @@ from contacts.profile import Profile
from wrapper.toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
from wrapper.toxav_enums import * from wrapper.toxav_enums import *
from wrapper.tox import bin_to_string from wrapper.tox import bin_to_string
from plugin_support import PluginLoader from plugin_support.plugin_support import PluginLoader
import queue
import threading
import util
import cv2 import cv2
import numpy as np import numpy as np
from threads import invoke_in_main_thread, execute from threads import invoke_in_main_thread, execute
@ -31,6 +28,7 @@ def self_connection_status(tox, profile):
invoke_in_main_thread(profile.set_status, status) invoke_in_main_thread(profile.set_status, status)
elif connection == TOX_CONNECTION['NONE']: elif connection == TOX_CONNECTION['NONE']:
invoke_in_main_thread(profile.set_status, None) invoke_in_main_thread(profile.set_status, None)
return wrapped return wrapped
@ -132,41 +130,45 @@ def friend_request(contacts_manager):
return wrapped return wrapped
def friend_typing(tox, friend_number, typing, user_data): def friend_typing(contacts_manager):
invoke_in_main_thread(Profile.get_instance().friend_typing, friend_number, typing) def wrapped(tox, friend_number, typing, user_data):
invoke_in_main_thread(contacts_manager.friend_typing, friend_number, typing)
return wrapped
def friend_read_receipt(tox, friend_number, message_id, user_data): def friend_read_receipt(contacts_manager):
profile = Profile.get_instance() def wrapped(tox, friend_number, message_id, user_data):
profile.get_friend_by_number(friend_number).dec_receipt() contacts_manager.get_friend_by_number(friend_number).dec_receipt()
if friend_number == profile.get_active_number(): if friend_number == contacts_manager.get_active_number():
invoke_in_main_thread(profile.receipt) invoke_in_main_thread(contacts_manager.receipt)
return wrapped
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Callbacks - file transfers # Callbacks - file transfers
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def tox_file_recv(window, tray): def tox_file_recv(window, tray, profile, file_transfer_handler, contacts_manager, settings):
""" """
New incoming file New incoming file
""" """
def wrapped(tox, friend_number, file_number, file_type, size, file_name, file_name_size, user_data): def wrapped(tox, friend_number, file_number, file_type, size, file_name, file_name_size, user_data):
profile = Profile.get_instance()
settings = Settings.get_instance()
if file_type == TOX_FILE_KIND['DATA']: if file_type == TOX_FILE_KIND['DATA']:
print('File') print('File')
try: try:
file_name = str(file_name[:file_name_size], 'utf-8') file_name = str(file_name[:file_name_size], 'utf-8')
except: except:
file_name = 'toxygen_file' file_name = 'toxygen_file'
invoke_in_main_thread(profile.incoming_file_transfer, invoke_in_main_thread(file_transfer_handler.incoming_file_transfer,
friend_number, friend_number,
file_number, file_number,
size, size,
file_name) file_name)
if not window.isActiveWindow(): if not window.isActiveWindow():
friend = profile.get_friend_by_number(friend_number) friend = contacts_manager.get_friend_by_number(friend_number)
if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY'] and not settings.locked: if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY'] and not settings.locked:
file_from = QtWidgets.QApplication.translate("Callback", "File from") file_from = QtWidgets.QApplication.translate("Callback", "File from")
invoke_in_main_thread(tray_notification, file_from + ' ' + friend.name, file_name, tray, window) invoke_in_main_thread(tray_notification, file_from + ' ' + friend.name, file_name, tray, window)
@ -175,7 +177,7 @@ def tox_file_recv(window, tray):
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(curr_directory() + '/images/icon_new_messages.png')) invoke_in_main_thread(tray.setIcon, QtGui.QIcon(curr_directory() + '/images/icon_new_messages.png'))
else: # AVATAR else: # AVATAR
print('Avatar') print('Avatar')
invoke_in_main_thread(profile.incoming_avatar, invoke_in_main_thread(file_transfer_handler.incoming_avatar,
friend_number, friend_number,
file_number, file_number,
size) size)
@ -222,16 +224,19 @@ def file_recv_control(file_transfer_handler):
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def lossless_packet(tox, friend_number, data, length, user_data): def lossless_packet(plugin_loader):
def wrapped(tox, friend_number, data, length, user_data):
""" """
Incoming lossless packet Incoming lossless packet
""" """
data = data[:length] data = data[:length]
plugin = PluginLoader.get_instance() invoke_in_main_thread(plugin_loader.callback_lossless, friend_number, data)
invoke_in_main_thread(plugin.callback_lossless, friend_number, data)
return wrapped
def lossy_packet(tox, friend_number, data, length, user_data): def lossy_packet(plugin_loader):
def wrapped(tox, friend_number, data, length, user_data):
""" """
Incoming lossy packet Incoming lossy packet
""" """
@ -239,39 +244,50 @@ def lossy_packet(tox, friend_number, data, length, user_data):
plugin = PluginLoader.get_instance() plugin = PluginLoader.get_instance()
invoke_in_main_thread(plugin.callback_lossy, friend_number, data) invoke_in_main_thread(plugin.callback_lossy, friend_number, data)
return wrapped
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Callbacks - audio # Callbacks - audio
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def call_state(toxav, friend_number, mask, user_data): def call_state(calls_manager):
def wrapped(toxav, friend_number, mask, user_data):
""" """
New call state New call state
""" """
print(friend_number, mask) print(friend_number, mask)
if mask == TOXAV_FRIEND_CALL_STATE['FINISHED'] or mask == TOXAV_FRIEND_CALL_STATE['ERROR']: if mask == TOXAV_FRIEND_CALL_STATE['FINISHED'] or mask == TOXAV_FRIEND_CALL_STATE['ERROR']:
invoke_in_main_thread(Profile.get_instance().stop_call, friend_number, True) invoke_in_main_thread(calls_manager.stop_call, friend_number, True)
else: else:
Profile.get_instance().call.toxav_call_state_cb(friend_number, mask) calls_manager.toxav_call_state_cb(friend_number, mask)
return wrapped
def call(toxav, friend_number, audio, video, user_data): def call(calls_manager):
def wrapped(toxav, friend_number, audio, video, user_data):
""" """
Incoming call from friend Incoming call from friend
""" """
print(friend_number, audio, video) print(friend_number, audio, video)
invoke_in_main_thread(Profile.get_instance().incoming_call, audio, video, friend_number) invoke_in_main_thread(calls_manager.incoming_call, audio, video, friend_number)
return wrapped
def callback_audio(toxav, friend_number, samples, audio_samples_per_channel, audio_channels_count, rate, user_data): def callback_audio(calls_manager):
def wrapped(toxav, friend_number, samples, audio_samples_per_channel, audio_channels_count, rate, user_data):
""" """
New audio chunk New audio chunk
""" """
Profile.get_instance().call.audio_chunk( calls_manager.call.audio_chunk(
bytes(samples[:audio_samples_per_channel * 2 * audio_channels_count]), bytes(samples[:audio_samples_per_channel * 2 * audio_channels_count]),
audio_channels_count, audio_channels_count,
rate) rate)
return wrapped
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Callbacks - video # Callbacks - video
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
@ -333,11 +349,6 @@ def video_receive_frame(toxav, friend_number, width, height, y, u, v, ystride, u
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def group_invite(tox, friend_number, gc_type, data, length, user_data):
invoke_in_main_thread(Profile.get_instance().group_invite, friend_number, gc_type,
bytes(data[:length]))
def show_gc_notification(window, tray, message, group_number, peer_number): def show_gc_notification(window, tray, message, group_number, peer_number):
profile = Profile.get_instance() profile = Profile.get_instance()
settings = Settings.get_instance() settings = Settings.get_instance()
@ -350,72 +361,40 @@ def show_gc_notification(window, tray, message, group_number, peer_number):
sound_notification(SOUND_NOTIFICATION['MESSAGE']) sound_notification(SOUND_NOTIFICATION['MESSAGE'])
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(curr_directory() + '/images/icon_new_messages.png')) invoke_in_main_thread(tray.setIcon, QtGui.QIcon(curr_directory() + '/images/icon_new_messages.png'))
def group_message(window, tray):
def wrapped(tox, group_number, peer_number, message, length, user_data):
message = str(message[:length], 'utf-8')
invoke_in_main_thread(Profile.get_instance().new_gc_message, group_number,
peer_number, TOX_MESSAGE_TYPE['NORMAL'], message)
show_gc_notification(window, tray, message, group_number, peer_number)
return wrapped
def group_action(window, tray):
def wrapped(tox, group_number, peer_number, message, length, user_data):
message = str(message[:length], 'utf-8')
invoke_in_main_thread(Profile.get_instance().new_gc_message, group_number,
peer_number, TOX_MESSAGE_TYPE['ACTION'], message)
show_gc_notification(window, tray, message, group_number, peer_number)
return wrapped
def group_title(tox, group_number, peer_number, title, length, user_data):
invoke_in_main_thread(Profile.get_instance().new_gc_title, group_number,
title[:length])
def group_namelist_change(tox, group_number, peer_number, change, user_data):
invoke_in_main_thread(Profile.get_instance().update_gc, group_number)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Callbacks - initialization # Callbacks - initialization
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def init_callbacks(tox, window, tray): def init_callbacks(tox, profile, settings, plugin_loader, contacts_manager,
calls_manager, file_transfer_handler, window, tray):
""" """
Initialization of all callbacks. Initialization of all callbacks.
:param tox: tox instance :param tox: tox instance
:param window: main window :param window: main window
:param tray: tray (for notifications) :param tray: tray (for notifications)
""" """
tox.callback_self_connection_status(self_connection_status(tox), 0) tox.callback_self_connection_status(self_connection_status(tox, profile), 0)
tox.callback_friend_status(friend_status, 0) tox.callback_friend_status(friend_status(profile, settings), 0)
tox.callback_friend_message(friend_message(window, tray), 0) tox.callback_friend_message(friend_message(profile, settings, window, tray), 0)
tox.callback_friend_connection_status(friend_connection_status, 0) tox.callback_friend_connection_status(friend_connection_status(profile, settings, plugin_loader), 0)
tox.callback_friend_name(friend_name, 0) tox.callback_friend_name(friend_name(profile), 0)
tox.callback_friend_status_message(friend_status_message, 0) tox.callback_friend_status_message(friend_status_message(profile), 0)
tox.callback_friend_request(friend_request, 0) tox.callback_friend_request(friend_request(contacts_manager), 0)
tox.callback_friend_typing(friend_typing, 0) tox.callback_friend_typing(friend_typing(contacts_manager), 0)
tox.callback_friend_read_receipt(friend_read_receipt, 0) tox.callback_friend_read_receipt(friend_read_receipt(contacts_manager), 0)
tox.callback_file_recv(tox_file_recv(window, tray), 0) tox.callback_file_recv(tox_file_recv(window, tray, profile, file_transfer_handler, contacts_manager, settings), 0)
tox.callback_file_recv_chunk(file_recv_chunk, 0) tox.callback_file_recv_chunk(file_recv_chunk(file_transfer_handler), 0)
tox.callback_file_chunk_request(file_chunk_request, 0) tox.callback_file_chunk_request(file_chunk_request(file_transfer_handler), 0)
tox.callback_file_recv_control(file_recv_control, 0) tox.callback_file_recv_control(file_recv_control(file_transfer_handler), 0)
toxav = tox.AV toxav.callback_call_state(call_state(calls_manager), 0)
toxav.callback_call_state(call_state, 0) toxav.callback_call(call(calls_manager), 0)
toxav.callback_call(call, 0) toxav.callback_audio_receive_frame(callback_audio(calls_manager), 0)
toxav.callback_audio_receive_frame(callback_audio, 0)
toxav.callback_video_receive_frame(video_receive_frame, 0) toxav.callback_video_receive_frame(video_receive_frame, 0)
tox.callback_friend_lossless_packet(lossless_packet, 0) tox.callback_friend_lossless_packet(lossless_packet(plugin_loader), 0)
tox.callback_friend_lossy_packet(lossy_packet, 0) tox.callback_friend_lossy_packet(lossy_packet(plugin_loader), 0)
tox.callback_group_invite(group_invite)
tox.callback_group_message(group_message(window, tray))
tox.callback_group_action(group_action(window, tray))
tox.callback_group_title(group_title)
tox.callback_group_namelist_change(group_namelist_change)

View File

@ -3,10 +3,9 @@ from PyQt5 import QtWidgets
from contacts.friend import * from contacts.friend import *
from user_data.settings import * from user_data.settings import *
from wrapper.toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
from ctypes import * from util.util import log, curr_directory
from util import log, Singleton, curr_directory
from network.tox_dns import tox_dns from network.tox_dns import tox_dns
from db.database import * from history.database import *
from file_transfers.file_transfers import * from file_transfers.file_transfers import *
import time import time
from av import calls from av import calls
@ -19,7 +18,7 @@ from contacts.group_chat import *
import re import re
class Profile(basecontact.BaseContact, Singleton): class Profile(basecontact.BaseContact):
""" """
Profile of current toxygen user. Contains friends list, tox instance Profile of current toxygen user. Contains friends list, tox instance
""" """
@ -33,7 +32,6 @@ class Profile(basecontact.BaseContact, Singleton):
tox.self_get_status_message(), tox.self_get_status_message(),
screen.user_info, screen.user_info,
tox.self_get_address()) tox.self_get_address())
Singleton.__init__(self)
self._screen = screen self._screen = screen
self._messages = screen.messages self._messages = screen.messages
self._tox = tox self._tox = tox
@ -43,8 +41,6 @@ class Profile(basecontact.BaseContact, Singleton):
self._factory = items_factory.ItemsFactory(self._screen.friends_list, self._messages) self._factory = items_factory.ItemsFactory(self._screen.friends_list, self._messages)
settings = Settings.get_instance() settings = Settings.get_instance()
self._show_avatars = settings['show_avatars'] self._show_avatars = settings['show_avatars']
self._paused_file_transfers = dict(settings['paused_file_transfers'])
# key - file id, value: [path, friend number, is incoming, start position]
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
@ -97,6 +93,7 @@ class Profile(basecontact.BaseContact, Singleton):
def get_friend_by_number(self, num): def get_friend_by_number(self, num):
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_friend + 1:
return self.get_curr_friend().get_last_message_text() return self.get_curr_friend().get_last_message_text()

View File

@ -9,6 +9,8 @@ class FileTransfersHandler:
self._tox = tox self._tox = tox
self._settings = settings self._settings = settings
self._file_transfers = {} self._file_transfers = {}
self._paused_file_transfers = dict(settings['paused_file_transfers'])
# key - file id, value: [path, friend number, is incoming, start position]
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# File transfers support # File transfers support

View File

@ -1,9 +1,12 @@
import sys import sys
import app import app
from user_data.settings import * from user_data.settings import *
from util.util import curr_directory, program_version, remove from util.util import curr_directory, remove
import argparse import argparse
__maintainer__ = 'Ingvar'
__version__ = '0.5.0'
def clean(): def clean():
"""Removes all windows libs from libs folder""" """Removes all windows libs from libs folder"""
@ -15,30 +18,31 @@ def reset():
Settings.reset_auto_profile() Settings.reset_auto_profile()
def print_toxygen_version():
print('Toxygen v' + __version__)
def main(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--version') parser.add_argument('--version', help='Prints Toxygen version')
parser.add_argument('--clean') parser.add_argument('--clean', help='Deletes toxcore libs from libs folder')
parser.add_argument('--reset') parser.add_argument('--reset', help='Resets default profile')
parser.add_argument('profile_path', nargs='?', default=None, help='Resets default profile')
args = parser.parse_args() args = parser.parse_args()
if not len(args):
toxygen = app.App() if args.version:
else: # started with argument(s) print_toxygen_version()
arg = sys.argv[1]
if arg == '--version':
print('Toxygen v' + program_version)
return return
elif arg == '--help':
print('Usage:\ntoxygen path_to_profile\ntoxygen tox_id\ntoxygen --version\ntoxygen --reset') if args.clean:
return
elif arg == '--clean':
clean() clean()
return return
elif arg == '--reset':
if args.reset:
reset() reset()
return return
else:
toxygen = app.App(arg) toxygen = app.App(path_to_profile=args.profile_path)
toxygen.main() toxygen.main()

View File

@ -1,6 +1,6 @@
import json import json
import urllib.request import urllib.request
from util import log from util.util import log
from user_data import settings from user_data import settings
from PyQt5 import QtNetwork, QtCore from PyQt5 import QtNetwork, QtCore

View File

@ -1,4 +1,4 @@
import util import util.util as util
from contacts import profile from contacts import profile
import os import os
import importlib import importlib
@ -8,15 +8,15 @@ from user_data import toxes
import sys import sys
class PluginLoader(util.Singleton): class PluginLoader():
def __init__(self, tox, settings): def __init__(self, tox, toxes, profile, settings):
super().__init__() super().__init__()
self._profile = profile.Profile.get_instance() self._profile = profile
self._settings = settings self._settings = settings
self._plugins = {} # dict. key - plugin unique short name, value - tuple (plugin instance, is active) self._plugins = {} # dict. key - plugin unique short name, value - tuple (plugin instance, is active)
self._tox = tox self._tox = tox
self._encr = toxes.ToxES.get_instance() self._toxes = toxes
def set_tox(self, tox): def set_tox(self, tox):
""" """
@ -55,7 +55,7 @@ class PluginLoader(util.Singleton):
if inspect.isclass(obj) and hasattr(obj, 'is_plugin') and obj.is_plugin: if inspect.isclass(obj) and hasattr(obj, 'is_plugin') and obj.is_plugin:
print('Plugin', elem) print('Plugin', elem)
try: # create instance of plugin class try: # create instance of plugin class
inst = obj(self._tox, self._profile, self._settings, self._encr) inst = obj(self._tox, self._profile, self._settings, self._toxes)
autostart = inst.get_short_name() in self._settings['plugins'] autostart = inst.get_short_name() in self._settings['plugins']
if autostart: if autostart:
inst.start() inst.start()
@ -158,7 +158,7 @@ class PluginLoader(util.Singleton):
try: try:
result.extend(elem[0].get_message_menu(menu, selected_text)) result.extend(elem[0].get_message_menu(menu, selected_text))
except: except:
continue pass
return result return result
def stop(self): def stop(self):

View File

@ -5,7 +5,7 @@ from collections import OrderedDict
from PyQt5 import QtCore from PyQt5 import QtCore
class SmileyLoader(util.Singleton): class SmileyLoader:
""" """
Class which loads smileys packs and insert smileys into messages Class which loads smileys packs and insert smileys into messages
""" """

View File

@ -1,11 +1,11 @@
from PyQt5 import QtCore from PyQt5 import QtCore
from communication.callbacks import init_callbacks
from bootstrap.bootstrap import * from bootstrap.bootstrap import *
import threading import threading
import queue import queue
from util import util from util import util
class InitThread(QtCore.QThread): class InitThread(QtCore.QThread):
def __init__(self, tox, ms, tray): def __init__(self, tox, ms, tray):

View File

@ -3,6 +3,19 @@ from util.ui import tr
from util.util import curr_directory from util.util import curr_directory
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
leftClicked = QtCore.pyqtSignal()
def __init__(self, icon, parent=None):
super().__init__(self, icon, parent)
self.activated.connect(self.iconActivated)
def iconActivated(self, reason):
if reason == QtGui.QSystemTrayIcon.Trigger:
self.leftClicked.emit()
class Menu(QtWidgets.QMenu): class Menu(QtWidgets.QMenu):
def __init__(self, settings, profile, *args): def __init__(self, settings, profile, *args):
@ -39,7 +52,7 @@ class Menu(QtWidgets.QMenu):
def init_tray(profile, settings, main_screen): def init_tray(profile, settings, main_screen):
tray = QtWidgets.QSystemTrayIcon(QtGui.QIcon(curr_directory() + '/images/icon.png')) tray = SystemTrayIcon(QtGui.QIcon(curr_directory() + '/images/icon.png'))
tray.setObjectName('tray') tray.setObjectName('tray')
m = Menu(settings, profile) m = Menu(settings, profile)

View File

@ -5,7 +5,7 @@ import util
import pyaudio import pyaudio
import wave import wave
from user_data import settings from user_data import settings
from util import curr_directory from util.util import curr_directory
class IncomingCallWidget(widgets.CenteredWidget): class IncomingCallWidget(widgets.CenteredWidget):

View File

@ -2,7 +2,7 @@ from wrapper.toxcore_enums_and_consts import *
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from contacts import profile from contacts import profile
from file_transfers.file_transfers import TOX_FILE_TRANSFER_STATE, PAUSED_FILE_TRANSFERS, DO_NOT_SHOW_ACCEPT_BUTTON, ACTIVE_FILE_TRANSFERS, SHOW_PROGRESS_BAR from file_transfers.file_transfers import TOX_FILE_TRANSFER_STATE, PAUSED_FILE_TRANSFERS, DO_NOT_SHOW_ACCEPT_BUTTON, ACTIVE_FILE_TRANSFERS, SHOW_PROGRESS_BAR
from util import curr_directory, convert_time, curr_time from util.util import curr_directory, convert_time, curr_time
from ui.widgets import DataLabel, create_menu from ui.widgets import DataLabel, create_menu
import html as h import html as h
import smileys import smileys
@ -60,8 +60,8 @@ class MessageEdit(QtWidgets.QTextBrowser):
def quote_text(self): def quote_text(self):
text = self.textCursor().selection().toPlainText() text = self.textCursor().selection().toPlainText()
if text: if text:
from ui import mainscreen from ui import main_screen
window = mainscreen.MainWindow.get_instance() window = main_screen.MainWindow.get_instance()
text = '>' + '\n>'.join(text.split('\n')) text = '>' + '\n>'.join(text.split('\n'))
if window.messageEdit.toPlainText(): if window.messageEdit.toPlainText():
text = '\n' + text text = '\n' + text

View File

@ -1,4 +1,5 @@
from ui.widgets import * from ui.widgets import *
import os.path
class NickEdit(LineEdit): class NickEdit(LineEdit):
@ -14,12 +15,40 @@ class NickEdit(LineEdit):
super(NickEdit, self).keyPressEvent(event) super(NickEdit, self).keyPressEvent(event)
class LoginScreen(CenteredWidget): class LoginScreenResult:
def __init__(self, profile_path, load_as_default, password=None):
self._profile_path = profile_path
self._load_as_default = load_as_default
self._password = password
def get_profile_path(self):
return self._profile_path
profile_path = property(get_profile_path)
def get_load_as_default(self):
return self._load_as_default
load_as_default = property(get_load_as_default)
def get_password(self):
return self._password
password = property(get_password)
def is_new_profile(self):
return not os.path.isfile(self._profile_path)
class LoginScreen(CenteredWidget, DialogWithResult):
def __init__(self): def __init__(self):
super(LoginScreen, self).__init__() CenteredWidget.__init__(self)
DialogWithResult.__init__(self)
self.initUI() self.initUI()
self.center() self.center()
self._profiles = []
def initUI(self): def initUI(self):
self.resize(400, 200) self.resize(400, 200)
@ -34,7 +63,7 @@ class LoginScreen(CenteredWidget):
self.new_name.setGeometry(QtCore.QRect(20, 100, 171, 31)) self.new_name.setGeometry(QtCore.QRect(20, 100, 171, 31))
self.load_profile = QtWidgets.QPushButton(self) self.load_profile = QtWidgets.QPushButton(self)
self.load_profile.setGeometry(QtCore.QRect(220, 150, 161, 27)) self.load_profile.setGeometry(QtCore.QRect(220, 150, 161, 27))
self.load_profile.clicked.connect(self.load_ex_profile) self.load_profile.clicked.connect(self.load_existing_profile)
self.default = QtWidgets.QCheckBox(self) self.default = QtWidgets.QCheckBox(self)
self.default.setGeometry(QtCore.QRect(220, 110, 131, 22)) self.default.setGeometry(QtCore.QRect(220, 110, 131, 22))
self.groupBox = QtWidgets.QGroupBox(self) self.groupBox = QtWidgets.QGroupBox(self)
@ -44,6 +73,7 @@ class LoginScreen(CenteredWidget):
self.groupBox_2 = QtWidgets.QGroupBox(self) self.groupBox_2 = QtWidgets.QGroupBox(self)
self.groupBox_2.setGeometry(QtCore.QRect(10, 40, 191, 151)) self.groupBox_2.setGeometry(QtCore.QRect(10, 40, 191, 151))
self.toxygen = QtWidgets.QLabel(self) self.toxygen = QtWidgets.QLabel(self)
self.toxygen.setGeometry(QtCore.QRect(160, 8, 90, 25))
self.groupBox.raise_() self.groupBox.raise_()
self.groupBox_2.raise_() self.groupBox_2.raise_()
self.comboBox.raise_() self.comboBox.raise_()
@ -51,16 +81,11 @@ class LoginScreen(CenteredWidget):
self.load_profile.raise_() self.load_profile.raise_()
self.new_name.raise_() self.new_name.raise_()
self.new_profile.raise_() self.new_profile.raise_()
self.toxygen.setGeometry(QtCore.QRect(160, 8, 90, 25))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Impact") font.setFamily("Impact")
font.setPointSize(16) font.setPointSize(16)
self.toxygen.setFont(font) self.toxygen.setFont(font)
self.toxygen.setObjectName("toxygen") self.toxygen.setObjectName("toxygen")
self.type = 0
self.number = -1
self.load_as_default = False
self.name = None
self.retranslateUi() self.retranslateUi()
QtCore.QMetaObject.connectSlotsByName(self) QtCore.QMetaObject.connectSlotsByName(self)
@ -80,19 +105,18 @@ class LoginScreen(CenteredWidget):
self.name = self.new_name.text() self.name = self.new_name.text()
self.close() self.close()
def load_ex_profile(self): def load_existing_profile(self):
if not self.create_only: index = self.comboBox.currentIndex()
self.type = 2 load_as_default = self.default.isChecked()
self.number = self.comboBox.currentIndex() path = os.path.join(self._profiles[index][0], self._profiles[index][1] + '.tox')
self.load_as_default = self.default.isChecked() result = LoginScreenResult(path, load_as_default)
self.close() self.close_with_result(result)
def update_select(self, data): def update_select(self, profiles):
list_of_profiles = [] profiles = sorted(profiles, key=lambda p: p[1])
for elem in data: self._profiles = list(profiles)
list_of_profiles.append(elem) self.comboBox.addItems(list(map(lambda p: p[1], profiles)))
self.comboBox.addItems(list_of_profiles) self.load_profile.setEnabled(len(profiles) > 0)
self.create_only = not list_of_profiles
def update_on_close(self, func): def update_on_close(self, func):
self.onclose = func self.onclose = func

View File

@ -3,7 +3,7 @@ from contacts.profile import *
from ui.list_items import * from ui.list_items import *
from ui.widgets import MultilineEdit, ComboBox from ui.widgets import MultilineEdit, ComboBox
import plugin_support import plugin_support
from ui.mainscreen_widgets import * from ui.main_screen_widgets import *
from user_data import toxes, settings from user_data import toxes, settings

View File

@ -1,4 +1,4 @@
from ui.widgets import CenteredWidget, LineEdit from ui.widgets import CenteredWidget, LineEdit, DialogWithResult
from PyQt5 import QtCore, QtWidgets from PyQt5 import QtCore, QtWidgets
@ -16,10 +16,11 @@ class PasswordArea(LineEdit):
super(PasswordArea, self).keyPressEvent(event) super(PasswordArea, self).keyPressEvent(event)
class PasswordScreenBase(CenteredWidget): class PasswordScreenBase(CenteredWidget, DialogWithResult):
def __init__(self, encrypt): def __init__(self, encrypt):
super(PasswordScreenBase, self).__init__() CenteredWidget.__init__(self)
DialogWithResult.__init__(self)
self._encrypt = encrypt self._encrypt = encrypt
self.initUI() self.initUI()
@ -73,13 +74,12 @@ class PasswordScreen(PasswordScreenBase):
if self.password.text(): if self.password.text():
try: try:
self._encrypt.set_password(self.password.text()) self._encrypt.set_password(self.password.text())
new_data = self._encrypt.pass_decrypt(self._data[0]) new_data = self._encrypt.pass_decrypt(self._data)
except Exception as ex: except Exception as ex:
self.warning.setVisible(True) self.warning.setVisible(True)
print('Decryption error:', ex) print('Decryption error:', ex)
else: else:
self._data[0] = new_data self.close_with_result(new_data)
self.close()
class UnlockAppScreen(PasswordScreenBase): class UnlockAppScreen(PasswordScreenBase):

View File

@ -32,6 +32,22 @@ class CenteredWidget(QtWidgets.QWidget):
self.move(qr.topLeft()) self.move(qr.topLeft())
class DialogWithResult(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self._result = None
def get_result(self):
return self._result
result = property(get_result)
def close_with_result(self, result):
self._result = result
self.close()
class LineEdit(QtWidgets.QLineEdit): class LineEdit(QtWidgets.QLineEdit):
def __init__(self, parent=None): def __init__(self, parent=None):

View File

@ -1,11 +1,17 @@
import util.util as util
import os
from user_data.settings import Settings
class ProfileManager: class ProfileManager:
""" """
Class with methods for search, load and save profiles Class with methods for search, load and save profiles
""" """
def __init__(self, path, name): def __init__(self, settings, toxes, path):
path = append_slash(path) self._settings = settings
self._path = path + name + '.tox' self._toxes = toxes
self._directory = path self._path = path
self._directory = os.path.basename(path)
# create /avatars if not exists: # create /avatars if not exists:
directory = path + 'avatars' directory = path + 'avatars'
if not os.path.exists(directory): if not os.path.exists(directory):
@ -23,9 +29,8 @@ class ProfileManager:
return self._directory return self._directory
def save_profile(self, data): def save_profile(self, data):
inst = ToxES.get_instance() if self._toxes.has_password():
if inst.has_password(): data = self._toxes.pass_encrypt(data)
data = inst.pass_encrypt(data)
with open(self._path, 'wb') as fl: with open(self._path, 'wb') as fl:
fl.write(data) fl.write(data)
print('Profile saved successfully') print('Profile saved successfully')
@ -37,11 +42,11 @@ class ProfileManager:
with open(path, 'wb') as fout: with open(path, 'wb') as fout:
fout.write(data) fout.write(data)
print('Profile exported successfully') print('Profile exported successfully')
copy(self._directory + 'avatars', new_path + 'avatars') util.copy(self._directory + 'avatars', new_path + 'avatars')
if use_new_path: if use_new_path:
self._path = new_path + os.path.basename(self._path) self._path = new_path + os.path.basename(self._path)
self._directory = new_path self._directory = new_path
Settings.get_instance().update_path() self._settings.update_path()
@staticmethod @staticmethod
def find_profiles(): def find_profiles():
@ -57,7 +62,7 @@ class ProfileManager:
if fl.endswith('.tox'): if fl.endswith('.tox'):
name = fl[:-4] name = fl[:-4]
result.append((path, name)) result.append((path, name))
path = curr_directory() path = util.get_base_directory(__file__)
# check current directory # check current directory
for fl in os.listdir(path): for fl in os.listdir(path):
if fl.endswith('.tox'): if fl.endswith('.tox'):

View File

@ -1,28 +1,26 @@
from platform import system from platform import system
import json import json
import os import os
from util import Singleton, curr_directory, log, copy, append_slash from util.util import log, curr_directory, append_slash
import pyaudio import pyaudio
from user_data.toxes import ToxES from user_data.toxes import ToxES
import smileys import smileys_and_stickers as smileys
class Settings(dict, Singleton): class Settings(dict):
""" """
Settings of current profile + global app settings Settings of current profile + global app settings
""" """
def __init__(self, name): def __init__(self, toxes, path):
Singleton.__init__(self) self._path = path
self.path = ProfileManager.get_path() + str(name) + '.json' self._toxes = toxes
self.name = name if os.path.isfile(path):
if os.path.isfile(self.path): with open(path, 'rb') as fl:
with open(self.path, 'rb') as fl:
data = fl.read() data = fl.read()
inst = ToxES.get_instance()
try: try:
if inst.is_data_encrypted(data): if toxes.is_data_encrypted(data):
data = inst.pass_decrypt(data) data = toxes.pass_decrypt(data)
info = json.loads(str(data, 'utf-8')) info = json.loads(str(data, 'utf-8'))
except Exception as ex: except Exception as ex:
info = Settings.get_default_settings() info = Settings.get_default_settings()
@ -175,12 +173,11 @@ class Settings(dict, Singleton):
def save(self): def save(self):
text = json.dumps(self) text = json.dumps(self)
inst = ToxES.get_instance() if self._toxes.has_password():
if inst.has_password(): text = bytes(self._toxes.pass_encrypt(bytes(text, 'utf-8')))
text = bytes(inst.pass_encrypt(bytes(text, 'utf-8')))
else: else:
text = bytes(text, 'utf-8') text = bytes(text, 'utf-8')
with open(self.path, 'wb') as fl: with open(self._path, 'wb') as fl:
fl.write(text) fl.write(text)
def close(self): def close(self):

View File

@ -3,9 +3,7 @@ import time
import shutil import shutil
import sys import sys
import re import re
import platform
program_version = '0.5.0'
def cached(func): def cached(func):
@ -33,6 +31,18 @@ def curr_directory(current_file=None):
return os.path.dirname(os.path.realpath(current_file or __file__)) return os.path.dirname(os.path.realpath(current_file or __file__))
def get_base_directory(current_file=None):
return os.path.dirname(curr_directory())
def get_images_directory():
return os.path.join(get_base_directory(), 'images')
def get_styles_directory():
return os.path.join(get_base_directory(), 'styles')
def curr_time(): def curr_time():
return time.strftime('%H:%M') return time.strftime('%H:%M')
@ -95,12 +105,5 @@ def is_re_valid(regex):
return True return True
class Singleton: def get_platform():
_instance = None return platform.system()
def __init__(self):
self.__class__._instance = self
@classmethod
def get_instance(cls):
return cls._instance

View File

@ -1,6 +1,6 @@
from platform import system from platform import system
from ctypes import CDLL from ctypes import CDLL
import util import util.util as util
class LibToxCore: class LibToxCore: