diff --git a/setup.py b/setup.py index 746163e..f586ec3 100644 --- a/setup.py +++ b/setup.py @@ -2,11 +2,11 @@ from setuptools import setup from setuptools.command.install import install from platform import system from subprocess import call -from toxygen.util import program_version +import main import sys -version = program_version + '.0' +version = main.__version__ + '.0' if system() == 'Windows': diff --git a/tests/tests.py b/tests/tests.py index b21854c..b61553e 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -8,6 +8,8 @@ import toxygen.util as util import time +# TODO: fic + class TestTox: def test_creation(self): diff --git a/toxygen/app.py b/toxygen/app.py index 8a7c799..3668c4b 100644 --- a/toxygen/app.py +++ b/toxygen/app.py @@ -1,11 +1,10 @@ -import communication.callbacks -import threads +from middleware import threads from PyQt5 import QtWidgets, QtGui, QtCore import ui.password_screen as passwordscreen from util.util import * import updater.updater as updater import os -from communication.tox_factory import tox_factory +from middleware.tox_factory import tox_factory import wrapper.toxencryptsave as tox_encrypt_save import user_data.toxes from user_data.settings import Settings @@ -13,6 +12,8 @@ from ui.login_screen import LoginScreen from user_data.profile_manager import ProfileManager from plugin_support.plugin_support import PluginLoader from ui.main_screen import MainWindow +from ui import tray +import util.ui as util_ui class App: @@ -20,21 +21,20 @@ class App: def __init__(self, version, path_to_profile=None, uri=None): self._version = version self._app = None - self.tox = self.ms = self.init = self.app = self.tray = self.mainloop = self.avloop = None - self.uri = self.path = self.toxes = None + self._tox = self._ms = self._init = self._app = self.tray = self._main_loop = self._av_loop = None + self.uri = self._toxes = self._tray = None if uri is not None and uri.startswith('tox:'): self.uri = uri[4:] - if path_to_profile is not None: - self.path = path_to_profile + self._path = path_to_profile def enter_pass(self, data): """ Show password screen """ - p = passwordscreen.PasswordScreen(self.toxes, data) + p = passwordscreen.PasswordScreen(self._toxes, data) p.show() - self.app.lastWindowClosed.connect(self.app.quit) - self.app.exec_() + self._app.lastWindowClosed.connect(self._app.quit) + self._app.exec_() result = p.result if result is None: raise SystemExit() @@ -45,30 +45,29 @@ class App: """ Main function of app. loads login screen if needed and starts main screen """ - app = QtWidgets.QApplication([]) + self._app= QtWidgets.QApplication([]) icon_file = os.path.join(get_images_directory(), 'icon.png') - app.setWindowIcon(QtGui.QIcon(icon_file)) - self._app = app + self._app.setWindowIcon(QtGui.QIcon(icon_file)) if get_platform() == 'Linux': QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads) with open(os.path.join(get_styles_directory(), 'dark_style.qss')) as fl: style = fl.read() - app.setStyleSheet(style) + self._app.setStyleSheet(style) encrypt_save = tox_encrypt_save.ToxEncryptSave() self._toxes = user_data.toxes.ToxES(encrypt_save) - if self.path is not None: - path = os.path.dirname(self.path) + '/' - name = os.path.basename(self.path)[:-4] - self._settings = Settings(self._toxes, self.path.replace('.tox', '.json')) + if self._path is not None: + path = os.path.dirname(self._path) + '/' + name = os.path.basename(self._path)[:-4] + self._settings = Settings(self._toxes, self._path.replace('.tox', '.json')) self._profile_manager = ProfileManager(self._settings, self._toxes, path) data = self._profile_manager.open_profile() if encrypt_save.is_data_encrypted(data): data = self.enter_pass(data) - self.tox = tox_factory(data, self._settings) + self._tox = self.create_tox(data) else: auto_profile = Settings.get_auto_profile() if not auto_profile[0]: @@ -79,15 +78,15 @@ class App: if curr_lang in langs: lang_path = langs[curr_lang] translator = QtCore.QTranslator() - translator.load(curr_directory() + '/translations/' + lang_path) - app.installTranslator(translator) - app.translator = translator + translator.load(get_translations_directory() + lang_path) + self._app.installTranslator(translator) + self._app.translator = translator ls = LoginScreen() ls.setWindowIconText("Toxygen") profiles = ProfileManager.find_profiles() ls.update_select(profiles) ls.show() - app.exec_() + self._app.exec_() result = ls.result if result is None: return @@ -95,47 +94,22 @@ class App: name = get_profile_name_from_path(result.profile_path) or 'toxygen_user' pr = map(lambda x: x[1], ProfileManager.find_profiles()) if name in list(pr): - msgBox = QtWidgets.QMessageBox() - msgBox.setWindowTitle( - QtWidgets.QApplication.translate("MainWindow", "Error")) - text = (QtWidgets.QApplication.translate("MainWindow", - 'Profile with this name already exists')) - msgBox.setText(text) - msgBox.exec_() + util_ui.message_box(util_ui.tr('Profile with this name already exists'), + util_ui.tr('Error')) return - self.tox = tox_factory() - self.tox.self_set_name(bytes(name, 'utf-8') if name else b'Toxygen User') - self.tox.self_set_status_message(b'Toxing on Toxygen') - reply = QtWidgets.QMessageBox.question(None, - 'Profile {}'.format(name), - QtWidgets.QApplication.translate("login", - 'Do you want to set profile password?'), - QtWidgets.QMessageBox.Yes, - QtWidgets.QMessageBox.No) - if reply == QtWidgets.QMessageBox.Yes: - set_pass = SetProfilePasswordScreen(encrypt_save) - set_pass.show() - self.app.lastWindowClosed.connect(self.app.quit) - self.app.exec_() - reply = QtWidgets.QMessageBox.question(None, - 'Profile {}'.format(name), - QtWidgets.QApplication.translate("login", - 'Do you want to save profile in default folder? If no, profile will be saved in program folder'), - QtWidgets.QMessageBox.Yes, - QtWidgets.QMessageBox.No) - if reply == QtWidgets.QMessageBox.Yes: - path = Settings.get_default_path() - else: - path = curr_directory() + '/' + self._tox = tox_factory() + self._tox.self_set_name(bytes(name, 'utf-8') if name else b'Toxygen User') + self._tox.self_set_status_message(b'Toxing on Toxygen') + # TODO: set profile password + path = result.profile_path + self._profile_manager = ProfileManager(self._toxes, path) try: - ProfileManager(path, name).save_profile(self.tox.get_savedata()) + self._profile_manager.save_profile(self._tox.get_savedata()) except Exception as ex: print(str(ex)) log('Profile creation exception: ' + str(ex)) - msgBox = QtWidgets.QMessageBox() - msgBox.setText(QtWidgets.QApplication.translate("login", - 'Profile saving error! Does Toxygen have permission to write to this directory?')) - msgBox.exec_() + text = util_ui.tr('Profile saving error! Does Toxygen have permission to write to this directory?') + util_ui.message_box(text, util_ui.tr('Error')) return path = Settings.get_default_path() self._settings = Settings() @@ -151,7 +125,7 @@ class App: data = self._profile_manager.open_profile() if self._toxes.is_data_encrypted(data): data = self.enter_pass(data) - self._tox = tox_factory(data, self._settings) + self._tox = self.create_tox(data) else: path, name = auto_profile self._settings = Settings(self._toxes, path + name + '.json') @@ -159,15 +133,13 @@ class App: data = self._profile_manager.open_profile() if encrypt_save.is_data_encrypted(data): data = self.enter_pass(data) - self.tox = tox_factory(data, self._settings) + self.tox = self.create_tox(data) if Settings.is_active_profile(path, get_profile_name_from_path(path)): # profile is in use - reply = QtWidgets.QMessageBox.question(None, - 'Profile {}'.format(name), - QtWidgets.QApplication.translate("login", 'Other instance of Toxygen uses this profile or profile was not properly closed. Continue?'), - QtWidgets.QMessageBox.Yes, - QtWidgets.QMessageBox.No) - if reply != QtWidgets.QMessageBox.Yes: + title = util_ui.tr('Profile {}').format(name) + text = util_ui.tr('Other instance of Toxygen uses this profile or profile was not properly closed. Continue?') + reply = util_ui.question(text, title) + if not reply: return else: self._settings.set_active_profile() @@ -175,82 +147,49 @@ class App: self.load_app_styles() self.load_app_translations() - # tray icon - - self.ms = MainWindow(self._settings, self._tox, self.reset, self.tray) - self._profile = self.ms.profile - self.ms.show() - - updating = updater.start_update_if_needed(self._version, self._settings) - if updating: - data = self.tox.get_savedata() - self._profile_manager.save_profile(data) - self._settings.close() - del self.tox + if self.try_to_update(): return - plugin_helper = PluginLoader(self._tox, self._toxes, self._profile, self._settings) # plugin support - plugin_helper.load() + self._ms = MainWindow(self._settings, self._tox, self.reset, self._tray) + self._profile = self._ms.profile + self._ms.show() - # init thread - self.init = threads.InitThread(self.tox, self.ms, self.tray) - self.init.start() + self._tray = tray.init_tray(self._profile, self._settings, self._ms) + self._tray.show() - # starting threads for tox iterate and toxav iterate - self.mainloop = threads.ToxIterateThread(self._tox) - self.mainloop.start() - self.avloop = threads.ToxAVIterateThread(self._tox.AV) - self.avloop.start() + self._plugin_loader = PluginLoader(self._tox, self._toxes, self._profile, self._settings) # plugins support + self._plugin_loader.load() # TODO; move to separate thread? if self.uri is not None: - self.ms.add_contact(self.uri) + self._ms.add_contact(self.uri) - app.lastWindowClosed.connect(app.quit) - app.exec_() + self._app.lastWindowClosed.connect(self._app.quit) + self._app.exec_() - self.init.stop = True - self.mainloop.stop = True - self.avloop.stop = True - plugin_helper.stop() - self.mainloop.wait() - self.init.wait() - self.avloop.wait() - self.tray.hide() - data = self.tox.get_savedata() + self._plugin_loader.stop() + self.stop_threads() + self._tray.hide() + data = self._tox.get_savedata() self._profile_manager.save_profile(data) self._settings.close() - del self.tox + del self._tox def reset(self): """ Create new tox instance (new network settings) :return: tox instance """ - self.mainloop.stop = True - self.init.stop = True - self.avloop.stop = True - self.mainloop.wait() - self.init.wait() - self.avloop.wait() - data = self.tox.get_savedata() + self.stop_threads() + data = self._tox.get_savedata() self._profile_manager.save_profile(data) - del self.tox + del self._tox # create new tox instance - self.tox = tox_factory(data, self._settings) - # init thread - self.init = threads.InitThread(self.tox, self.ms, self.tray) - self.init.start() + self._tox = tox_factory(data, self._settings) + self.start_threads() - # starting threads for tox iterate and toxav iterate - self.mainloop = threads.ToxIterateThread(self.tox) - self.mainloop.start() + self._plugin_loader.set_tox(self._tox) - self.avloop = threads.ToxAVIterateThread(self.tox.AV) - self.avloop.start() - - self._plugin_loader.set_tox(self.tox) - - return self.tox + return self._tox def load_app_styles(self): # application color scheme @@ -266,3 +205,32 @@ class App: translator.load(curr_directory(__file__) + '/translations/' + lang) self._app.installTranslator(translator) self._app.translator = translator + + def try_to_update(self): + updating = updater.start_update_if_needed(self._version, self._settings) + if updating: + data = self._tox.get_savedata() + self._profile_manager.save_profile(data) + self._settings.close() + del self._tox + return updating + + def start_threads(self): + # init thread + self._init = threads.InitThread(self._tox, self._ms, self._tray) + self._init.start() + + # starting threads for tox iterate and toxav iterate + self._main_loop = threads.ToxIterateThread(self._tox) + self._main_loop.start() + self._av_loop = threads.ToxAVIterateThread(self._tox.AV) + self._av_loop.start() + + def stop_threads(self): + self._init.stop_thread() + + self._main_loop.stop_thread() + self._av_loop.stop_thread() + + def create_tox(self, data): + return tox_factory(data, self._settings) diff --git a/toxygen/contacts/profile.py b/toxygen/contacts/profile.py index ae7767a..ef26a51 100644 --- a/toxygen/contacts/profile.py +++ b/toxygen/contacts/profile.py @@ -11,7 +11,7 @@ import time from av import calls import plugin_support from contacts import basecontact -from ui import items_factory, avwidgets +from ui import items_factory, av_widgets import cv2 import threading from contacts.group_chat import * diff --git a/toxygen/login.py b/toxygen/login.py deleted file mode 100644 index d68629a..0000000 --- a/toxygen/login.py +++ /dev/null @@ -1,19 +0,0 @@ -class Login: - - def __init__(self, arr): - self.arr = arr - - def login_screen_close(self, t, number=-1, default=False, name=None): - """ Function which processes data from login screen - :param t: 0 - window was closed, 1 - new profile was created, 2 - profile loaded - :param number: num of chosen profile in list (-1 by default) - :param default: was or not chosen profile marked as default - :param name: name of new profile - """ - self.t = t - self.num = number - self.default = default - self.name = name - - def get_data(self): - return self.arr[self.num] \ No newline at end of file diff --git a/toxygen/main.py b/toxygen/main.py index 4230668..97a5363 100644 --- a/toxygen/main.py +++ b/toxygen/main.py @@ -4,6 +4,7 @@ from user_data.settings import * from util.util import curr_directory, remove import argparse + __maintainer__ = 'Ingvar' __version__ = '0.5.0' diff --git a/toxygen/communication/__init__.py b/toxygen/middleware/__init__.py similarity index 100% rename from toxygen/communication/__init__.py rename to toxygen/middleware/__init__.py diff --git a/toxygen/communication/callbacks.py b/toxygen/middleware/callbacks.py similarity index 99% rename from toxygen/communication/callbacks.py rename to toxygen/middleware/callbacks.py index 0566325..4db161e 100644 --- a/toxygen/communication/callbacks.py +++ b/toxygen/middleware/callbacks.py @@ -1,5 +1,4 @@ from PyQt5 import QtGui -from notifications import * from user_data.settings import Settings from contacts.profile import Profile from wrapper.toxcore_enums_and_consts import * @@ -8,7 +7,7 @@ from wrapper.tox import bin_to_string from plugin_support.plugin_support import PluginLoader import cv2 import numpy as np -from threads import invoke_in_main_thread, execute +from middleware.threads import invoke_in_main_thread, execute # TODO: use closures diff --git a/toxygen/threads.py b/toxygen/middleware/threads.py similarity index 71% rename from toxygen/threads.py rename to toxygen/middleware/threads.py index 4a129d1..eb5a9d7 100644 --- a/toxygen/threads.py +++ b/toxygen/middleware/threads.py @@ -1,17 +1,26 @@ -from PyQt5 import QtCore from bootstrap.bootstrap import * import threading import queue from util import util +import time +class BaseThread(threading.Thread): -class InitThread(QtCore.QThread): + def __init__(self): + super().__init__() + self._stop = False + + def stop_thread(self): + self._stop = True + self.join() + + +class InitThread(BaseThread): def __init__(self, tox, ms, tray): - QtCore.QThread.__init__(self) + super().__init__() self.tox, self.ms, self.tray = tox, ms, tray - self.stop = False def run(self): # initializing callbacks @@ -21,71 +30,65 @@ class InitThread(QtCore.QThread): # bootstrap try: for data in generate_nodes(): - if self.stop: + if self._stop: return self.tox.bootstrap(*data) self.tox.add_tcp_relay(*data) except: pass for _ in range(10): - if self.stop: + if self._stop: return - self.msleep(1000) + time.sleep(1) while not self.tox.self_get_connection_status(): try: for data in generate_nodes(): - if self.stop: + if self._stop: return self.tox.bootstrap(*data) self.tox.add_tcp_relay(*data) except: pass finally: - self.msleep(5000) + time.sleep(5) -class ToxIterateThread(QtCore.QThread): +class ToxIterateThread(BaseThread): def __init__(self, tox): - QtCore.QThread.__init__(self) - self.tox = tox - self.stop = False + super().__init__() + self._tox = tox def run(self): - while not self.stop: - self.tox.iterate() - self.msleep(self.tox.iteration_interval()) + while not self._stop: + self._tox.iterate() + time.sleep(self._tox.iteration_interval() / 1000) -class ToxAVIterateThread(QtCore.QThread): +class ToxAVIterateThread(BaseThread): def __init__(self, toxav): - QtCore.QThread.__init__(self) - self.toxav = toxav - self.stop = False + super().__init__() + self._toxav = toxav def run(self): - while not self.stop: - self.toxav.iterate() - self.msleep(self.toxav.iteration_interval()) + while not self._stop: + self._toxav.iterate() + time.sleep(self._toxav.iteration_interval() / 1000) -class FileTransfersThread(threading.Thread): +class FileTransfersThread(BaseThread): def __init__(self): + super().__init__() self._queue = queue.Queue() self._timeout = 0.01 - self._continue = True - super().__init__() def execute(self, func, *args, **kwargs): self._queue.put((func, args, kwargs)) - def stop(self): - self._continue = False - def run(self): - while self._continue: + while not self._stop: try: func, args, kwargs = self._queue.get(timeout=self._timeout) func(*args, **kwargs) @@ -105,8 +108,7 @@ def start(): def stop(): - _thread.stop() - _thread.join() + _thread.stop_thread() def execute(func, *args, **kwargs): diff --git a/toxygen/communication/tox_factory.py b/toxygen/middleware/tox_factory.py similarity index 100% rename from toxygen/communication/tox_factory.py rename to toxygen/middleware/tox_factory.py diff --git a/toxygen/notifications.py b/toxygen/notifications.py deleted file mode 100644 index cf926d1..0000000 --- a/toxygen/notifications.py +++ /dev/null @@ -1,71 +0,0 @@ -from PyQt5 import QtCore, QtWidgets -from util.util import curr_directory -import wave -import pyaudio - - -SOUND_NOTIFICATION = { - 'MESSAGE': 0, - 'FRIEND_CONNECTION_STATUS': 1, - 'FILE_TRANSFER': 2 -} - - -def tray_notification(title, text, tray, window): - """ - Show tray notification and activate window icon - NOTE: different behaviour on different OS - :param title: Name of user who sent message or file - :param text: text of message or file info - :param tray: ref to tray icon - :param window: main window - """ - if QtWidgets.QSystemTrayIcon.isSystemTrayAvailable(): - if len(text) > 30: - text = text[:27] + '...' - tray.showMessage(title, text, QtWidgets.QSystemTrayIcon.NoIcon, 3000) - QtWidgets.QApplication.alert(window, 0) - - def message_clicked(): - window.setWindowState(window.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) - window.activateWindow() - tray.messageClicked.connect(message_clicked) - - -class AudioFile: - chunk = 1024 - - def __init__(self, fl): - self.wf = wave.open(fl, 'rb') - self.p = pyaudio.PyAudio() - self.stream = self.p.open( - format=self.p.get_format_from_width(self.wf.getsampwidth()), - channels=self.wf.getnchannels(), - rate=self.wf.getframerate(), - output=True) - - def play(self): - data = self.wf.readframes(self.chunk) - while data: - self.stream.write(data) - data = self.wf.readframes(self.chunk) - - def close(self): - self.stream.close() - self.p.terminate() - - -def sound_notification(t): - """ - Plays sound notification - :param t: type of notification - """ - if t == SOUND_NOTIFICATION['MESSAGE']: - f = curr_directory() + '/sounds/message.wav' - elif t == SOUND_NOTIFICATION['FILE_TRANSFER']: - f = curr_directory() + '/sounds/file.wav' - else: - f = curr_directory() + '/sounds/contact.wav' - a = AudioFile(f) - a.play() - a.close() diff --git a/toxygen/notifications/__init__.py b/toxygen/notifications/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/toxygen/notifications/sound.py b/toxygen/notifications/sound.py new file mode 100644 index 0000000..a0b93f0 --- /dev/null +++ b/toxygen/notifications/sound.py @@ -0,0 +1,54 @@ +import util.util +import wave +import pyaudio +import os.path + + +SOUND_NOTIFICATION = { + 'MESSAGE': 0, + 'FRIEND_CONNECTION_STATUS': 1, + 'FILE_TRANSFER': 2 +} + + +class AudioFile: + chunk = 1024 + + def __init__(self, fl): + self.wf = wave.open(fl, 'rb') + self.p = pyaudio.PyAudio() + self.stream = self.p.open( + format=self.p.get_format_from_width(self.wf.getsampwidth()), + channels=self.wf.getnchannels(), + rate=self.wf.getframerate(), + output=True) + + def play(self): + data = self.wf.readframes(self.chunk) + while data: + self.stream.write(data) + data = self.wf.readframes(self.chunk) + + def close(self): + self.stream.close() + self.p.terminate() + + +def sound_notification(t): + """ + Plays sound notification + :param t: type of notification + """ + if t == SOUND_NOTIFICATION['MESSAGE']: + f = get_file_path('message.wav') + elif t == SOUND_NOTIFICATION['FILE_TRANSFER']: + f = get_file_path('file.wav') + else: + f = get_file_path('contact.wav') + a = AudioFile(f) + a.play() + a.close() + + +def get_file_path(file_name): + return os.path.join(util.util.get_sounds_directory(), file_name) diff --git a/toxygen/notifications/tray.py b/toxygen/notifications/tray.py new file mode 100644 index 0000000..4232253 --- /dev/null +++ b/toxygen/notifications/tray.py @@ -0,0 +1,22 @@ +from PyQt5 import QtCore, QtWidgets + + +def tray_notification(title, text, tray, window): + """ + Show tray notification and activate window icon + NOTE: different behaviour on different OS + :param title: Name of user who sent message or file + :param text: text of message or file info + :param tray: ref to tray icon + :param window: main window + """ + if QtWidgets.QSystemTrayIcon.isSystemTrayAvailable(): + if len(text) > 30: + text = text[:27] + '...' + tray.showMessage(title, text, QtWidgets.QSystemTrayIcon.NoIcon, 3000) + QtWidgets.QApplication.alert(window, 0) + + def message_clicked(): + window.setWindowState(window.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) + window.activateWindow() + tray.messageClicked.connect(message_clicked) diff --git a/toxygen/smileys/__init__.py b/toxygen/smileys/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/toxygen/smileys_and_stickers.py b/toxygen/smileys/smileys.py similarity index 87% rename from toxygen/smileys_and_stickers.py rename to toxygen/smileys/smileys.py index dd72fd9..abf6990 100644 --- a/toxygen/smileys_and_stickers.py +++ b/toxygen/smileys/smileys.py @@ -47,6 +47,7 @@ class SmileyLoader: def get_smileys_path(self): return util.curr_directory() + '/smileys/' + self._curr_pack + '/' if self._curr_pack is not None else None + @staticmethod def get_packs_list(self): d = util.curr_directory() + '/smileys/' return [x[1] for x in os.walk(d)][0] @@ -71,18 +72,3 @@ class SmileyLoader: if file_name.endswith('.gif'): # animated smiley edit.addAnimation(QtCore.QUrl(file_name), self.get_smileys_path() + file_name) return ' '.join(arr) - - -def sticker_loader(): - """ - :return list of stickers - """ - result = [] - d = util.curr_directory() + '/stickers/' - keys = [x[1] for x in os.walk(d)][0] - for key in keys: - path = d + key + '/' - files = filter(lambda f: f.endswith('.png'), os.listdir(path)) - files = map(lambda f: str(path + f), files) - result.extend(files) - return result diff --git a/toxygen/stickers/__init__.py b/toxygen/stickers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/toxygen/stickers/stickers.py b/toxygen/stickers/stickers.py new file mode 100644 index 0000000..5ad6aa1 --- /dev/null +++ b/toxygen/stickers/stickers.py @@ -0,0 +1,18 @@ +import os +import util.util as util + + +def load_stickers(): + """ + :return list of stickers + """ + result = [] + d = util.get_stickers_directory() + keys = [x[1] for x in os.walk(d)][0] + for key in keys: + path = d + key + '/' + files = filter(lambda f: f.endswith('.png'), os.listdir(path)) + files = map(lambda f: str(path + f), files) + result.extend(files) + + return result diff --git a/toxygen/ui/avwidgets.py b/toxygen/ui/av_widgets.py similarity index 100% rename from toxygen/ui/avwidgets.py rename to toxygen/ui/av_widgets.py diff --git a/toxygen/ui/main_screen.py b/toxygen/ui/main_screen.py index d3896be..55e7c8e 100644 --- a/toxygen/ui/main_screen.py +++ b/toxygen/ui/main_screen.py @@ -6,6 +6,7 @@ import plugin_support from ui.main_screen_widgets import * from user_data import toxes, settings import util.util as util +import util.ui as util_ui class MainWindow(QtWidgets.QMainWindow): @@ -414,12 +415,10 @@ class MainWindow(QtWidgets.QMainWindow): # ----------------------------------------------------------------------------------------------------------------- def about_program(self): - import util - msgBox = QtWidgets.QMessageBox() - msgBox.setWindowTitle(QtWidgets.QApplication.translate("MainWindow", "About")) - text = (QtWidgets.QApplication.translate("MainWindow", 'Toxygen is Tox client written on Python.\nVersion: ')) - msgBox.setText(text + util.program_version + '\nGitHub: https://github.com/toxygen-project/toxygen/') - msgBox.exec_() + text = util_ui.tr('Toxygen is Tox client written on Python.\nVersion: ') + text += '' + '\nGitHub: https://github.com/toxygen-project/toxygen/' + title = util_ui.tr('About') + util_ui.message_box(text, title) def network_settings(self): self.n_s = NetworkSettings(self.reset) diff --git a/toxygen/ui/main_screen_widgets.py b/toxygen/ui/main_screen_widgets.py index bbf6c5a..319b3df 100644 --- a/toxygen/ui/main_screen_widgets.py +++ b/toxygen/ui/main_screen_widgets.py @@ -2,7 +2,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets from ui.widgets import RubberBandWindow, create_menu, QRightClickButton, CenteredWidget, LineEdit from contacts.profile import Profile import smileys -import util +import util.util as util class MessageArea(QtWidgets.QPlainTextEdit): @@ -194,7 +194,7 @@ class DropdownMenu(QtWidgets.QWidget): self.stickerButton = QtWidgets.QPushButton(self) self.stickerButton.setGeometry(QtCore.QRect(60, 0, 60, 60)) - pixmap = QtGui.QPixmap(util.curr_directory() + '/images/file.png') + pixmap = QtGui.QPixmap(util.get_images_directory() + 'file.png') icon = QtGui.QIcon(pixmap) self.fileTransferButton.setIcon(icon) self.fileTransferButton.setIconSize(QtCore.QSize(50, 50)) diff --git a/toxygen/tray.py b/toxygen/ui/tray.py similarity index 79% rename from toxygen/tray.py rename to toxygen/ui/tray.py index 0c474b4..ebdbd33 100644 --- a/toxygen/tray.py +++ b/toxygen/ui/tray.py @@ -1,6 +1,7 @@ from PyQt5 import QtWidgets, QtGui, QtCore from util.ui import tr -from util.util import curr_directory +from util.util import get_images_directory +import os.path class SystemTrayIcon(QtWidgets.QSystemTrayIcon): @@ -8,11 +9,11 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon): leftClicked = QtCore.pyqtSignal() def __init__(self, icon, parent=None): - super().__init__(self, icon, parent) - self.activated.connect(self.iconActivated) + super().__init__(icon, parent) + self.activated.connect(self.icon_activated) - def iconActivated(self, reason): - if reason == QtGui.QSystemTrayIcon.Trigger: + def icon_activated(self, reason): + if reason == QtWidgets.QSystemTrayIcon.Trigger: self.leftClicked.emit() @@ -52,20 +53,21 @@ class Menu(QtWidgets.QMenu): def init_tray(profile, settings, main_screen): - tray = SystemTrayIcon(QtGui.QIcon(curr_directory() + '/images/icon.png')) + icon = os.path.join(get_images_directory(), 'icon.png') + tray = SystemTrayIcon(QtGui.QIcon(icon)) tray.setObjectName('tray') - m = Menu(settings, profile) - show = m.addAction(tr('Open Toxygen')) - sub = m.addMenu(tr('Set status')) + menu = Menu(settings, profile) + show = menu.addAction(tr('Open Toxygen')) + sub = menu.addMenu(tr('Set status')) online = sub.addAction(tr('Online')) away = sub.addAction(tr('Away')) busy = sub.addAction(tr('Busy')) online.setCheckable(True) away.setCheckable(True) busy.setCheckable(True) - m.act = sub - exit = m.addAction(tr('Exit')) + menu.act = sub + exit = menu.addAction(tr('Exit')) def show_window(): def show(): @@ -96,12 +98,12 @@ def init_tray(profile, settings, main_screen): show.triggered.connect(show_window) exit.triggered.connect(close_app) - m.aboutToShow.connect(lambda: m.aboutToShowHandler()) - online.triggered.connect(lambda: m.newStatus(0)) - away.triggered.connect(lambda: m.newStatus(1)) - busy.triggered.connect(lambda: m.newStatus(2)) + menu.aboutToShow.connect(lambda: menu.aboutToShowHandler()) + online.triggered.connect(lambda: menu.newStatus(0)) + away.triggered.connect(lambda: menu.newStatus(1)) + busy.triggered.connect(lambda: menu.newStatus(2)) - tray.setContextMenu(m) + tray.setContextMenu(menu) tray.show() tray.activated.connect(tray_activated) diff --git a/toxygen/updater/updater.py b/toxygen/updater/updater.py index 575dbfe..f274161 100644 --- a/toxygen/updater/updater.py +++ b/toxygen/updater/updater.py @@ -118,14 +118,8 @@ def start_update_if_needed(version, settings): download(version) updating = True else: - reply = QtWidgets.QMessageBox.question(None, - 'Toxygen', - QtWidgets.QApplication.translate("login", - 'Update for Toxygen was found. Download and install it?'), - QtWidgets.QMessageBox.Yes, - QtWidgets.QMessageBox.No) - if reply == QtWidgets.QMessageBox.Yes: + reply = util_ui.question(util_ui.tr('Update for Toxygen was found. Download and install it?')) + if reply: download(version) updating = True - return updating diff --git a/toxygen/user_data/settings.py b/toxygen/user_data/settings.py index 39fd333..9226a81 100644 --- a/toxygen/user_data/settings.py +++ b/toxygen/user_data/settings.py @@ -4,7 +4,7 @@ import os from util.util import log, curr_directory, append_slash import pyaudio from user_data.toxes import ToxES -import smileys_and_stickers as smileys +import smileys.smileys as smileys class Settings(dict): diff --git a/toxygen/util/ui.py b/toxygen/util/ui.py index be613cb..c485de4 100644 --- a/toxygen/util/ui.py +++ b/toxygen/util/ui.py @@ -5,10 +5,17 @@ def tr(s): return PyQt5.QtWidgets.QApplication.translate('Toxygen', s) -def question(text): - reply = PyQt5.QtWidgets.QMessageBox.question(None, 'Toxygen', text, +def question(text, title=None): + reply = PyQt5.QtWidgets.QMessageBox.question(None, title or 'Toxygen', text, PyQt5.QtWidgets.QMessageBox.Yes, PyQt5.QtWidgets.QMessageBox.No) return reply == PyQt5.QtWidgets.QMessageBox.Yes + +def message_box(text, title=None): + m_box = PyQt5.QtWidgets.QMessageBox() + m_box.setText(tr(text)) + m_box.setWindowTitle(title or 'Toxygen') + m_box.exec_() + # TODO: move all dialogs here diff --git a/toxygen/util/util.py b/toxygen/util/util.py index 91a4aec..5bf5f99 100644 --- a/toxygen/util/util.py +++ b/toxygen/util/util.py @@ -35,12 +35,33 @@ def get_base_directory(current_file=None): return os.path.dirname(curr_directory(current_file or __file__)) +@cached def get_images_directory(): - return os.path.join(get_base_directory(), 'images') + return get_app_directory('images') +@cached def get_styles_directory(): - return os.path.join(get_base_directory(), 'styles') + return get_app_directory('styles') + + +@cached +def get_sounds_directory(): + return get_app_directory('sounds') + + +@cached +def get_stickers_directory(): + return get_app_directory('stickers') + + +@cached +def get_translations_directory(): + return get_app_directory('translations') + + +def get_app_directory(directory_name): + return os.path.join(get_base_directory(), directory_name) def get_profile_name_from_path(path):