refactoring - app.py, files moved to different folders
This commit is contained in:
parent
91d3f885c0
commit
8a2665ed4d
26 changed files with 287 additions and 302 deletions
4
setup.py
4
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':
|
||||
|
|
|
@ -8,6 +8,8 @@ import toxygen.util as util
|
|||
import time
|
||||
|
||||
|
||||
# TODO: fic
|
||||
|
||||
class TestTox:
|
||||
|
||||
def test_creation(self):
|
||||
|
|
214
toxygen/app.py
214
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)
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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]
|
|
@ -4,6 +4,7 @@ from user_data.settings import *
|
|||
from util.util import curr_directory, remove
|
||||
import argparse
|
||||
|
||||
|
||||
__maintainer__ = 'Ingvar'
|
||||
__version__ = '0.5.0'
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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):
|
|
@ -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()
|
0
toxygen/notifications/__init__.py
Normal file
0
toxygen/notifications/__init__.py
Normal file
54
toxygen/notifications/sound.py
Normal file
54
toxygen/notifications/sound.py
Normal file
|
@ -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)
|
22
toxygen/notifications/tray.py
Normal file
22
toxygen/notifications/tray.py
Normal file
|
@ -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)
|
0
toxygen/smileys/__init__.py
Normal file
0
toxygen/smileys/__init__.py
Normal file
|
@ -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
|
0
toxygen/stickers/__init__.py
Normal file
0
toxygen/stickers/__init__.py
Normal file
18
toxygen/stickers/stickers.py
Normal file
18
toxygen/stickers/stickers.py
Normal file
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in a new issue