Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
8672c5fb56 | |||
1c788a73c6 | |||
88e9317a41 | |||
27cf1a7348 | |||
326ebc155c | |||
5df82c6b3c | |||
8c6caab299 | |||
daa0053e4b | |||
3990487701 | |||
a6f47c6248 | |||
18935c5b10 | |||
5204cba58d | |||
c9358db883 |
14
.gitignore
vendored
@ -1,17 +1,23 @@
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.ui
|
||||
src/toxcore
|
||||
toxygen/toxcore
|
||||
tests/tests
|
||||
tests/libs
|
||||
tests/.cache
|
||||
tests/__pycache__
|
||||
src/libs
|
||||
toxygen/libs
|
||||
.idea
|
||||
*~
|
||||
*.iml
|
||||
*.so
|
||||
*.log
|
||||
src/build
|
||||
src/dist
|
||||
toxygen/build
|
||||
toxygen/dist
|
||||
*.spec
|
||||
dist/
|
||||
toxygen/avatars
|
||||
toxygen/__pycache__
|
||||
/*.egg-info
|
||||
/*.egg
|
||||
|
||||
|
18
MANIFEST.in
Normal file
@ -0,0 +1,18 @@
|
||||
include toxygen/images/*.png
|
||||
include toxygen/images/*.ico
|
||||
include toxygen/images/*.gif
|
||||
include toxygen/sounds/*.wav
|
||||
include toxygen/stickers/tox/*.png
|
||||
include toxygen/smileys/default/*.png
|
||||
include toxygen/smileys/default/config.json
|
||||
include toxygen/smileys/animated/*.gif
|
||||
include toxygen/smileys/animated/config.json
|
||||
include toxygen/smileys/starwars/*.gif
|
||||
include toxygen/smileys/starwars/*.png
|
||||
include toxygen/smileys/starwars/config.json
|
||||
include toxygen/styles/style.qss
|
||||
include toxygen/translations/*.qm
|
||||
include toxygen/libs/libtox.dll
|
||||
include toxygen/libs/libsodium.a
|
||||
include toxygen/libs/libtox64.dll
|
||||
include toxygen/libs/libsodium64.a
|
@ -3,17 +3,34 @@
|
||||
## Use precompiled binary:
|
||||
[Check our releases page](https://github.com/xveduk/toxygen/releases)
|
||||
|
||||
##Using pip3
|
||||
|
||||
### Windows (32-bit interpreter)
|
||||
|
||||
``pip3.4 install toxygen``
|
||||
Run app using ``toxygen`` command.
|
||||
|
||||
##Linux
|
||||
|
||||
1. Install [toxcore](https://github.com/irungentoo/toxcore/blob/master/INSTALL.md) with toxav support in your system (install in /usr/lib/)
|
||||
2. Install PortAudio:
|
||||
``sudo apt-get install portaudio19-dev``
|
||||
3. Install toxygen:
|
||||
``sudo pip3.4 install toxygen``
|
||||
4 Run toxygen using ``toxygen`` command.
|
||||
|
||||
## From source code (recommended for developers)
|
||||
|
||||
### Windows
|
||||
|
||||
1. [Download and install latest Python 3.4](https://www.python.org/downloads/windows/)
|
||||
2. [Install PySide](https://pypi.python.org/pypi/PySide/1.2.4) (recommended) or [PyQt4](https://riverbankcomputing.com/software/pyqt/download)
|
||||
3. Install PyAudio: ``pip3 install pyaudio``
|
||||
4. [Download toxygen](https://github.com/xveduk/toxygen/archive/master.zip)
|
||||
5. Unpack archive
|
||||
6. Download latest libtox.dll build, download latest libsodium.a build, put it into \src\libs\
|
||||
7. Run \src\main.py
|
||||
3. Install PyAudio: ``pip3.4 install pyaudio``
|
||||
4. Install PySocks: ``pip3.4 install PySocks``
|
||||
5. [Download toxygen](https://github.com/xveduk/toxygen/archive/master.zip)
|
||||
6. Unpack archive
|
||||
7. Download latest libtox.dll build, download latest libsodium.a build, put it into \src\libs\
|
||||
8. Run \src\main.py
|
||||
|
||||
[libtox.dll for 32-bit Python](https://build.tox.chat/view/libtoxcore/job/libtoxcore_build_windows_x86_shared_release/lastSuccessfulBuild/artifact/libtoxcore_build_windows_x86_shared_release.zip)
|
||||
|
||||
@ -30,19 +47,15 @@ Dependencies:
|
||||
|
||||
1. Install latest Python3.4:
|
||||
``sudo apt-get install python3``
|
||||
2. [Install PySide](https://wiki.qt.io/PySide_Binaries_Linux) (recommended) or [PyQt4](https://riverbankcomputing.com/software/pyqt/download)
|
||||
2. [Install PySide](https://wiki.qt.io/PySide_Binaries_Linux) (recommended), using terminal - ``sudo apt-get install python3-pyside``, or install [PyQt4](https://riverbankcomputing.com/software/pyqt/download).
|
||||
3. Install [toxcore](https://github.com/irungentoo/toxcore/blob/master/INSTALL.md) with toxav support in your system (install in /usr/lib/)
|
||||
4. Install PyAudio:
|
||||
```bash
|
||||
sudo apt-get install portaudio19-dev
|
||||
sudo apt-get install python3-pyaudio
|
||||
```
|
||||
Toxygen:
|
||||
|
||||
1. [Download toxygen](https://github.com/xveduk/toxygen/archive/master.zip)
|
||||
2. Unpack archive
|
||||
3. Run app:
|
||||
``python3 main.py``
|
||||
``sudo apt-get install portaudio19-dev`` and ``sudo apt-get install python3-pyaudio``
|
||||
5. Install PySocks: ``pip3.4 install PySocks``
|
||||
6. [Download toxygen](https://github.com/xveduk/toxygen/archive/master.zip)
|
||||
7. Unpack archive
|
||||
8. Run app:
|
||||
``python3.4 main.py``
|
||||
|
||||
## Compile Toxygen
|
||||
Check [compile.md](/docs/compile.md) for more info
|
||||
|
50
setup.py
Normal file
@ -0,0 +1,50 @@
|
||||
from setuptools import setup
|
||||
from setuptools.command.install import install
|
||||
from platform import system
|
||||
from subprocess import call
|
||||
from toxygen.util import program_version
|
||||
|
||||
|
||||
version = program_version + '.0'
|
||||
|
||||
MODULES = ['PyAudio', 'PySocks']
|
||||
|
||||
if system() == 'Windows':
|
||||
MODULES.append('PySide')
|
||||
|
||||
|
||||
class InstallScript(install):
|
||||
"""Install all required libs"""
|
||||
|
||||
def run(self):
|
||||
install.run(self)
|
||||
OS = system()
|
||||
if OS == 'Windows':
|
||||
call(["toxygen", "--configure"])
|
||||
elif OS == 'Linux':
|
||||
call(["toxygen", "--clean"])
|
||||
|
||||
setup(name='Toxygen',
|
||||
version=version,
|
||||
description='Toxygen - Tox client',
|
||||
long_description='Toxygen is powerful Tox client written in Python3',
|
||||
url='https://github.com/xveduk/toxygen/',
|
||||
keywords='toxygen tox',
|
||||
author='Ingvar',
|
||||
license='GPL3',
|
||||
packages=['toxygen', 'toxygen.plugins', 'toxygen.styles'],
|
||||
install_requires=MODULES,
|
||||
include_package_data=True,
|
||||
classifiers=[
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
],
|
||||
entry_points={
|
||||
'console_scripts': ['toxygen=toxygen.main:main'],
|
||||
},
|
||||
cmdclass={
|
||||
'install': InstallScript,
|
||||
},
|
||||
)
|
@ -1,30 +0,0 @@
|
||||
import json
|
||||
import urllib.request
|
||||
from util import log
|
||||
|
||||
|
||||
def tox_dns(email):
|
||||
"""
|
||||
TOX DNS 4
|
||||
:param email: data like 'groupbot@toxme.io'
|
||||
:return: tox id on success else None
|
||||
"""
|
||||
site = email.split('@')[1]
|
||||
data = {"action": 3, "name": "{}".format(email)}
|
||||
for url in ('https://{}/api'.format(site), 'http://{}/api'.format(site)):
|
||||
try:
|
||||
return send_request(url, data)
|
||||
except Exception as ex: # try http
|
||||
log('TOX DNS ERROR: ' + str(ex))
|
||||
return None # error
|
||||
|
||||
|
||||
def send_request(url, data):
|
||||
req = urllib.request.Request(url)
|
||||
req.add_header('Content-Type', 'application/json')
|
||||
response = urllib.request.urlopen(req, bytes(json.dumps(data), 'utf-8'))
|
||||
res = json.loads(str(response.read(), 'utf-8'))
|
||||
if not res['c']:
|
||||
return res['tox_id']
|
||||
else:
|
||||
raise LookupError()
|
@ -1,40 +1,22 @@
|
||||
from src.bootstrap import node_generator
|
||||
from src.profile import *
|
||||
from src.settings import ProfileHelper
|
||||
from src.tox_dns import tox_dns
|
||||
from src.toxencryptsave import LibToxEncryptSave
|
||||
from toxygen.bootstrap import node_generator
|
||||
from toxygen.profile import *
|
||||
from toxygen.settings import ProfileHelper
|
||||
from toxygen.tox_dns import tox_dns
|
||||
import toxygen.toxencryptsave as encr
|
||||
|
||||
|
||||
class TestProfile():
|
||||
class TestProfile:
|
||||
|
||||
def test_search(self):
|
||||
arr = ProfileHelper.find_profiles()
|
||||
assert arr
|
||||
assert len(arr) >= 2
|
||||
|
||||
def test_open(self):
|
||||
data = ProfileHelper(Settings.get_default_path(), 'alice').open_profile()
|
||||
assert data
|
||||
|
||||
def test_open_save(self):
|
||||
data = ProfileHelper(Settings.get_default_path(), 'alice').open_profile()
|
||||
ProfileHelper.get_instance().save_profile(data)
|
||||
new_data = ProfileHelper(Settings.get_default_path(), 'alice').open_profile()
|
||||
assert new_data == data
|
||||
|
||||
|
||||
class TestNodeGen():
|
||||
|
||||
def test_generator(self):
|
||||
for elem in node_generator():
|
||||
assert len(elem) == 3
|
||||
|
||||
def test_ports(self):
|
||||
for elem in node_generator():
|
||||
assert elem[1] in [33445, 443, 5190, 2306, 1813]
|
||||
|
||||
|
||||
class TestTox():
|
||||
class TestTox:
|
||||
|
||||
def test_loading(self):
|
||||
data = ProfileHelper(Settings.get_default_path(), 'alice').open_profile()
|
||||
@ -45,16 +27,16 @@ class TestTox():
|
||||
del tox
|
||||
|
||||
def test_creation(self):
|
||||
name = 'Toxygen User'
|
||||
status_message = 'Toxing on Toxygen'
|
||||
name = b'Toxygen User'
|
||||
status_message = b'Toxing on Toxygen'
|
||||
tox = tox_factory()
|
||||
tox.self_set_name(name)
|
||||
tox.self_set_status_message(status_message)
|
||||
data = tox.get_savedata()
|
||||
del tox
|
||||
tox = tox_factory(data)
|
||||
assert tox.self_get_name() == name
|
||||
assert tox.self_get_status_message() == status_message
|
||||
assert tox.self_get_name() == str(name, 'utf-8')
|
||||
assert tox.self_get_status_message() == str(status_message, 'utf-8')
|
||||
|
||||
def test_friend_list(self):
|
||||
data = ProfileHelper(Settings.get_default_path(), 'bob').open_profile()
|
||||
@ -67,7 +49,7 @@ class TestTox():
|
||||
del tox
|
||||
|
||||
|
||||
class TestDNS():
|
||||
class TestDNS:
|
||||
|
||||
def test_dns(self):
|
||||
bot_id = '56A1ADE4B65B86BCD51CC73E2CD4E542179F47959FE3E0E21B4B0ACDADE51855D34D34D37CB5'
|
||||
@ -75,12 +57,13 @@ class TestDNS():
|
||||
assert tox_id == bot_id
|
||||
|
||||
|
||||
class TestEncryption():
|
||||
class TestEncryption:
|
||||
|
||||
def test_encr_decr(self):
|
||||
with open(settings.Settings.get_default_path() + '/alice.tox') as fl:
|
||||
with open(settings.Settings.get_default_path() + '/alice.tox', 'rb') as fl:
|
||||
data = fl.read()
|
||||
lib = LibToxEncryptSave('easypassword')
|
||||
lib = encr.ToxEncryptSave()
|
||||
lib.set_password('easypassword')
|
||||
copy_data = data[:]
|
||||
data = lib.pass_encrypt(data)
|
||||
data = lib.pass_decrypt(data)
|
||||
|
8
toxygen/__init__.py
Normal file
@ -0,0 +1,8 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
path = os.path.dirname(os.path.realpath(__file__)) # curr dir
|
||||
|
||||
sys.path.insert(0, os.path.join(path, 'styles'))
|
||||
sys.path.insert(0, os.path.join(path, 'plugins'))
|
||||
sys.path.insert(0, path)
|
@ -6,7 +6,7 @@ class Node:
|
||||
self._ip, self._port, self._tox_key, self.rand = ip, port, tox_key, rand
|
||||
|
||||
def get_data(self):
|
||||
return self._ip, self._port, self._tox_key
|
||||
return bytes(self._ip, 'utf-8'), self._port, self._tox_key
|
||||
|
||||
|
||||
def node_generator():
|
@ -62,7 +62,7 @@ def friend_status(tox, friend_num, new_status, user_data):
|
||||
"""
|
||||
Check friend's status (none, busy, away)
|
||||
"""
|
||||
print("Friend's #{} status changed! New status: {}".format(friend_num, new_status))
|
||||
print("Friend's #{} status changed!".format(friend_num))
|
||||
profile = Profile.get_instance()
|
||||
friend = profile.get_friend_by_number(friend_num)
|
||||
if friend.status is None and Settings.get_instance()['sound_notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
|
||||
@ -94,7 +94,7 @@ def friend_name(tox, friend_num, name, size, user_data):
|
||||
Friend changed his name
|
||||
"""
|
||||
profile = Profile.get_instance()
|
||||
print('New name: ', friend_num, name)
|
||||
print('New name friend #' + str(friend_num))
|
||||
invoke_in_main_thread(profile.new_name, friend_num, name)
|
||||
|
||||
|
||||
@ -106,7 +106,7 @@ def friend_status_message(tox, friend_num, status_message, size, user_data):
|
||||
profile = Profile.get_instance()
|
||||
friend = profile.get_friend_by_number(friend_num)
|
||||
invoke_in_main_thread(friend.set_status_message, status_message)
|
||||
print('User #{} has new status: {}'.format(friend_num, status_message))
|
||||
print('User #{} has new status'.format(friend_num))
|
||||
invoke_in_main_thread(profile.send_messages, friend_num)
|
||||
if profile.get_active_number() == friend_num:
|
||||
invoke_in_main_thread(profile.set_active)
|
||||
@ -123,7 +123,7 @@ def friend_message(window, tray):
|
||||
invoke_in_main_thread(profile.new_message, friend_number, message_type, message)
|
||||
if not window.isActiveWindow():
|
||||
friend = profile.get_friend_by_number(friend_number)
|
||||
if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
|
||||
if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY'] and not settings.locked:
|
||||
invoke_in_main_thread(tray_notification, friend.name, message, tray, window)
|
||||
if settings['sound_notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
|
||||
sound_notification(SOUND_NOTIFICATION['MESSAGE'])
|
||||
@ -178,7 +178,7 @@ def tox_file_recv(window, tray):
|
||||
file_name)
|
||||
if not window.isActiveWindow():
|
||||
friend = profile.get_friend_by_number(friend_number)
|
||||
if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
|
||||
if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY'] and not settings.locked:
|
||||
file_from = QtGui.QApplication.translate("Callback", "File from", None, QtGui.QApplication.UnicodeUTF8)
|
||||
invoke_in_main_thread(tray_notification, file_from + ' ' + friend.name, file_name, tray, window)
|
||||
if settings['sound_notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
|
@ -91,10 +91,11 @@ class Contact:
|
||||
if not os.path.isfile(avatar_path): # load default image
|
||||
avatar_path = 'avatar.png'
|
||||
os.chdir(curr_directory() + '/images/')
|
||||
pixmap = QtGui.QPixmap(QtCore.QSize(64, 64))
|
||||
width = self._widget.avatar_label.width()
|
||||
pixmap = QtGui.QPixmap(QtCore.QSize(width, width))
|
||||
pixmap.load(avatar_path)
|
||||
self._widget.avatar_label.setScaledContents(False)
|
||||
self._widget.avatar_label.setPixmap(pixmap.scaled(64, 64, QtCore.Qt.KeepAspectRatio))
|
||||
self._widget.avatar_label.setPixmap(pixmap.scaled(width, width, QtCore.Qt.KeepAspectRatio))
|
||||
self._widget.avatar_label.repaint()
|
||||
|
||||
def reset_avatar(self):
|
@ -3,7 +3,7 @@ from sqlite3 import connect
|
||||
import settings
|
||||
from os import chdir
|
||||
import os.path
|
||||
from toxencryptsave import LibToxEncryptSave
|
||||
from toxencryptsave import ToxEncryptSave
|
||||
|
||||
|
||||
PAGE_SIZE = 42
|
||||
@ -22,7 +22,7 @@ class History:
|
||||
chdir(settings.ProfileHelper.get_path())
|
||||
path = settings.ProfileHelper.get_path() + self._name + '.hstr'
|
||||
if os.path.exists(path):
|
||||
decr = LibToxEncryptSave.get_instance()
|
||||
decr = ToxEncryptSave.get_instance()
|
||||
try:
|
||||
with open(path, 'rb') as fin:
|
||||
data = fin.read()
|
||||
@ -40,7 +40,7 @@ class History:
|
||||
db.close()
|
||||
|
||||
def save(self):
|
||||
encr = LibToxEncryptSave.get_instance()
|
||||
encr = ToxEncryptSave.get_instance()
|
||||
if encr.has_password():
|
||||
path = settings.ProfileHelper.get_path() + self._name + '.hstr'
|
||||
with open(path, 'rb') as fin:
|
||||
@ -54,7 +54,7 @@ class History:
|
||||
new_path = directory + self._name + '.hstr'
|
||||
with open(path, 'rb') as fin:
|
||||
data = fin.read()
|
||||
encr = LibToxEncryptSave.get_instance()
|
||||
encr = ToxEncryptSave.get_instance()
|
||||
if encr.has_password():
|
||||
data = encr.pass_encrypt(data)
|
||||
with open(new_path, 'wb') as fout:
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 329 B After Width: | Height: | Size: 329 B |
Before Width: | Height: | Size: 609 B After Width: | Height: | Size: 609 B |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 231 B After Width: | Height: | Size: 231 B |
Before Width: | Height: | Size: 405 B After Width: | Height: | Size: 405 B |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 159 B After Width: | Height: | Size: 159 B |
Before Width: | Height: | Size: 445 B After Width: | Height: | Size: 445 B |
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 351 B After Width: | Height: | Size: 351 B |
Before Width: | Height: | Size: 306 B After Width: | Height: | Size: 306 B |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 481 B After Width: | Height: | Size: 481 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
@ -167,26 +167,28 @@ class ContactItem(QtGui.QWidget):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
self.setBaseSize(QtCore.QSize(250, 70))
|
||||
mode = settings.Settings.get_instance()['compact_mode']
|
||||
self.setBaseSize(QtCore.QSize(250, 40 if mode else 70))
|
||||
self.avatar_label = QtGui.QLabel(self)
|
||||
self.avatar_label.setGeometry(QtCore.QRect(3, 3, 64, 64))
|
||||
size = 32 if mode else 64
|
||||
self.avatar_label.setGeometry(QtCore.QRect(3, 4, size, size))
|
||||
self.avatar_label.setScaledContents(True)
|
||||
self.name = DataLabel(self)
|
||||
self.name.setGeometry(QtCore.QRect(75, 10, 150, 25))
|
||||
self.name.setGeometry(QtCore.QRect(50 if mode else 75, 3 if mode else 10, 150, 15 if mode else 25))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Times New Roman")
|
||||
font.setPointSize(12)
|
||||
font.setPointSize(10 if mode else 12)
|
||||
font.setBold(True)
|
||||
self.name.setFont(font)
|
||||
self.status_message = DataLabel(self)
|
||||
self.status_message.setGeometry(QtCore.QRect(75, 30, 170, 20))
|
||||
self.status_message.setGeometry(QtCore.QRect(50 if mode else 75, 20 if mode else 30, 170, 15 if mode else 20))
|
||||
font.setPointSize(10)
|
||||
font.setBold(False)
|
||||
self.status_message.setFont(font)
|
||||
self.connection_status = StatusCircle(self)
|
||||
self.connection_status.setGeometry(QtCore.QRect(230, 5, 32, 32))
|
||||
self.connection_status.setGeometry(QtCore.QRect(230, -2 if mode else 5, 32, 32))
|
||||
self.messages = UnreadMessagesCount(self)
|
||||
self.messages.setGeometry(QtCore.QRect(52, 50, 30, 20))
|
||||
self.messages.setGeometry(QtCore.QRect(20 if mode else 52, 20 if mode else 50, 30, 20))
|
||||
|
||||
|
||||
class StatusCircle(QtGui.QWidget):
|
||||
@ -349,7 +351,7 @@ class FileTransferItem(QtGui.QListWidget):
|
||||
directory = QtGui.QFileDialog.getExistingDirectory(self,
|
||||
QtGui.QApplication.translate("MainWindow", 'Choose folder', None, QtGui.QApplication.UnicodeUTF8),
|
||||
curr_directory(),
|
||||
QtGui.QFileDialog.ShowDirsOnly)
|
||||
QtGui.QFileDialog.ShowDirsOnly | QtGui.QFileDialog.DontUseNativeDialog)
|
||||
self.pb.setVisible(True)
|
||||
if directory:
|
||||
pr = profile.Profile.get_instance()
|
||||
@ -483,7 +485,7 @@ class InlineImageItem(QtGui.QScrollArea):
|
||||
'Choose folder', None,
|
||||
QtGui.QApplication.UnicodeUTF8),
|
||||
curr_directory(),
|
||||
QtGui.QFileDialog.ShowDirsOnly)
|
||||
QtGui.QFileDialog.ShowDirsOnly | QtGui.QFileDialog.DontUseNativeDialog)
|
||||
if directory:
|
||||
fl = QtCore.QFile(directory + '/toxygen_inline_' + curr_time().replace(':', '_') + '.png')
|
||||
self._pixmap.save(fl, 'PNG')
|
@ -1,5 +1,6 @@
|
||||
import sys
|
||||
from loginscreen import LoginScreen
|
||||
import profile
|
||||
from settings import *
|
||||
try:
|
||||
from PySide import QtCore, QtGui
|
||||
@ -7,13 +8,11 @@ except ImportError:
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from bootstrap import node_generator
|
||||
from mainscreen import MainWindow
|
||||
from profile import tox_factory
|
||||
from callbacks import init_callbacks
|
||||
from util import curr_directory
|
||||
from util import curr_directory, program_version
|
||||
import styles.style
|
||||
import toxencryptsave
|
||||
from passwordscreen import PasswordScreen
|
||||
import profile
|
||||
from passwordscreen import PasswordScreen, UnlockAppScreen
|
||||
from plugin_support import PluginLoader
|
||||
|
||||
|
||||
@ -36,7 +35,7 @@ class Toxygen:
|
||||
Show password screen
|
||||
"""
|
||||
tmp = [data]
|
||||
p = PasswordScreen(toxencryptsave.LibToxEncryptSave.get_instance(), tmp)
|
||||
p = PasswordScreen(toxencryptsave.ToxEncryptSave.get_instance(), tmp)
|
||||
p.show()
|
||||
self.app.connect(self.app, QtCore.SIGNAL("lastWindowClosed()"), self.app, QtCore.SLOT("quit()"))
|
||||
self.app.exec_()
|
||||
@ -58,7 +57,7 @@ class Toxygen:
|
||||
dark_style = fl.read()
|
||||
app.setStyleSheet(dark_style)
|
||||
|
||||
encrypt_save = toxencryptsave.LibToxEncryptSave()
|
||||
encrypt_save = toxencryptsave.ToxEncryptSave()
|
||||
|
||||
if self.path is not None:
|
||||
path = os.path.dirname(self.path) + '/'
|
||||
@ -67,7 +66,7 @@ class Toxygen:
|
||||
if encrypt_save.is_data_encrypted(data):
|
||||
data = self.enter_pass(data)
|
||||
settings = Settings(name)
|
||||
self.tox = tox_factory(data, settings)
|
||||
self.tox = profile.tox_factory(data, settings)
|
||||
else:
|
||||
auto_profile = Settings.get_auto_profile()
|
||||
if not auto_profile[0]:
|
||||
@ -95,12 +94,15 @@ class Toxygen:
|
||||
elif _login.t == 1: # create new profile
|
||||
_login.name = _login.name.strip()
|
||||
name = _login.name if _login.name else 'toxygen_user'
|
||||
self.tox = tox_factory()
|
||||
self.tox = profile.tox_factory()
|
||||
self.tox.self_set_name(bytes(_login.name, 'utf-8') if _login.name else b'Toxygen User')
|
||||
self.tox.self_set_status_message(b'Toxing on Toxygen')
|
||||
ProfileHelper(Settings.get_default_path(), name).save_profile(self.tox.get_savedata())
|
||||
path = Settings.get_default_path()
|
||||
settings = Settings(name)
|
||||
if curr_lang in langs:
|
||||
settings['language'] = curr_lang
|
||||
settings.save()
|
||||
else: # load existing profile
|
||||
path, name = _login.get_data()
|
||||
if _login.default:
|
||||
@ -109,19 +111,19 @@ class Toxygen:
|
||||
if encrypt_save.is_data_encrypted(data):
|
||||
data = self.enter_pass(data)
|
||||
settings = Settings(name)
|
||||
self.tox = tox_factory(data, settings)
|
||||
self.tox = profile.tox_factory(data, settings)
|
||||
else:
|
||||
path, name = auto_profile
|
||||
data = ProfileHelper(path, name).open_profile()
|
||||
if encrypt_save.is_data_encrypted(data):
|
||||
data = self.enter_pass(data)
|
||||
settings = Settings(name)
|
||||
self.tox = tox_factory(data, settings)
|
||||
self.tox = profile.tox_factory(data, settings)
|
||||
|
||||
if Settings.is_active_profile(path, name): # profile is in use
|
||||
reply = QtGui.QMessageBox.question(None,
|
||||
'Profile {}'.format(name),
|
||||
QtGui.QApplication.translate("login", 'Looks like other instance of Toxygen uses this profile! Continue?', None, QtGui.QApplication.UnicodeUTF8),
|
||||
QtGui.QApplication.translate("login", 'Other instance of Toxygen uses this profile or profile was not properly closed. Continue?', None, QtGui.QApplication.UnicodeUTF8),
|
||||
QtGui.QMessageBox.Yes,
|
||||
QtGui.QMessageBox.No)
|
||||
if reply != QtGui.QMessageBox.Yes:
|
||||
@ -151,7 +153,7 @@ class Toxygen:
|
||||
def aboutToShow(self):
|
||||
status = profile.Profile.get_instance().status
|
||||
act = self.act
|
||||
if status is None:
|
||||
if status is None or Settings.get_instance().locked:
|
||||
self.actions()[1].setVisible(False)
|
||||
else:
|
||||
self.actions()[1].setVisible(True)
|
||||
@ -159,6 +161,7 @@ class Toxygen:
|
||||
act.actions()[1].setChecked(False)
|
||||
act.actions()[2].setChecked(False)
|
||||
act.actions()[status].setChecked(True)
|
||||
self.actions()[2].setVisible(not Settings.get_instance().locked)
|
||||
|
||||
def languageChange(self, *args, **kwargs):
|
||||
self.actions()[0].setText(QtGui.QApplication.translate('tray', 'Open Toxygen', None, QtGui.QApplication.UnicodeUTF8))
|
||||
@ -181,10 +184,19 @@ class Toxygen:
|
||||
exit = m.addAction(QtGui.QApplication.translate('tray', 'Exit', None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
def show_window():
|
||||
def show():
|
||||
if not self.ms.isActiveWindow():
|
||||
self.ms.setWindowState(self.ms.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
|
||||
self.ms.activateWindow()
|
||||
self.ms.show()
|
||||
if not Settings.get_instance().locked:
|
||||
show()
|
||||
else:
|
||||
def correct_pass():
|
||||
show()
|
||||
Settings.get_instance().locked = False
|
||||
self.p = UnlockAppScreen(toxencryptsave.ToxEncryptSave.get_instance(), correct_pass)
|
||||
self.p.show()
|
||||
|
||||
m.connect(show, QtCore.SIGNAL("triggered()"), show_window)
|
||||
m.connect(exit, QtCore.SIGNAL("triggered()"), lambda: app.exit())
|
||||
@ -243,7 +255,7 @@ class Toxygen:
|
||||
ProfileHelper.get_instance().save_profile(data)
|
||||
del self.tox
|
||||
# create new tox instance
|
||||
self.tox = tox_factory(data, Settings.get_instance())
|
||||
self.tox = profile.tox_factory(data, Settings.get_instance())
|
||||
# init thread
|
||||
self.init = self.InitThread(self.tox, self.ms, self.tray)
|
||||
self.init.start()
|
||||
@ -342,9 +354,55 @@ class Toxygen:
|
||||
return self.arr[self.num]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def clean():
|
||||
d = curr_directory() + '/libs/'
|
||||
for fl in ('libtox64.dll', 'libtox.dll', 'libsodium64.a', 'libsodium.a'):
|
||||
if os.path.exists(d + fl):
|
||||
os.remove(d + fl)
|
||||
|
||||
|
||||
def configure():
|
||||
d = curr_directory() + '/libs/'
|
||||
is_64bits = sys.maxsize > 2 ** 32
|
||||
if not is_64bits:
|
||||
if os.path.exists(d + 'libtox64.dll'):
|
||||
os.remove(d + 'libtox64.dll')
|
||||
if os.path.exists(d + 'libsodium64.a'):
|
||||
os.remove(d + 'libsodium64.a')
|
||||
else:
|
||||
if os.path.exists(d + 'libtox.dll'):
|
||||
os.remove(d + 'libtox.dll')
|
||||
if os.path.exists(d + 'libsodium.a'):
|
||||
os.remove(d + 'libsodium.a')
|
||||
try:
|
||||
os.rename(d + 'libtox64.dll', d + 'libtox.dll')
|
||||
os.rename(d + 'libsodium64.a', d + 'libsodium.a')
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) == 1:
|
||||
toxygen = Toxygen()
|
||||
else: # path to profile or tox: uri
|
||||
toxygen = Toxygen(sys.argv[1])
|
||||
else: # path to profile or tox: uri or --version or --help
|
||||
arg = sys.argv[1]
|
||||
if arg == '--version':
|
||||
print('Toxygen ' + program_version)
|
||||
return
|
||||
elif arg == '--help':
|
||||
print('Usage:\ntoxygen path_to_profile\ntoxygen tox_id\ntoxygen --version')
|
||||
return
|
||||
elif arg == '--configure':
|
||||
configure()
|
||||
return
|
||||
elif arg == '--clean':
|
||||
clean()
|
||||
return
|
||||
else:
|
||||
toxygen = Toxygen(arg)
|
||||
toxygen.main()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -16,6 +16,8 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.tray = tray
|
||||
self.setAcceptDrops(True)
|
||||
self.initUI(tox)
|
||||
if settings.Settings.get_instance()['show_welcome_screen']:
|
||||
self.ws = WelcomeScreen()
|
||||
|
||||
def setup_menu(self, MainWindow):
|
||||
self.menubar = QtGui.QMenuBar(MainWindow)
|
||||
@ -36,8 +38,8 @@ class MainWindow(QtGui.QMainWindow):
|
||||
|
||||
self.actionAdd_friend = QtGui.QAction(MainWindow)
|
||||
self.actionAdd_friend.setObjectName("actionAdd_friend")
|
||||
self.actionProfile_settings = QtGui.QAction(MainWindow)
|
||||
self.actionProfile_settings.setObjectName("actionProfile_settings")
|
||||
self.actionprofilesettings = QtGui.QAction(MainWindow)
|
||||
self.actionprofilesettings.setObjectName("actionprofilesettings")
|
||||
self.actionPrivacy_settings = QtGui.QAction(MainWindow)
|
||||
self.actionPrivacy_settings.setObjectName("actionPrivacy_settings")
|
||||
self.actionInterface_settings = QtGui.QAction(MainWindow)
|
||||
@ -52,8 +54,10 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.actionSettings.setObjectName("actionSettings")
|
||||
self.audioSettings = QtGui.QAction(MainWindow)
|
||||
self.pluginData = QtGui.QAction(MainWindow)
|
||||
self.lockApp = QtGui.QAction(MainWindow)
|
||||
self.menuProfile.addAction(self.actionAdd_friend)
|
||||
self.menuProfile.addAction(self.actionSettings)
|
||||
self.menuProfile.addAction(self.lockApp)
|
||||
self.menuSettings.addAction(self.actionPrivacy_settings)
|
||||
self.menuSettings.addAction(self.actionInterface_settings)
|
||||
self.menuSettings.addAction(self.actionNotifications)
|
||||
@ -69,12 +73,13 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.actionAbout_program.triggered.connect(self.about_program)
|
||||
self.actionNetwork.triggered.connect(self.network_settings)
|
||||
self.actionAdd_friend.triggered.connect(self.add_contact)
|
||||
self.actionSettings.triggered.connect(self.profile_settings)
|
||||
self.actionSettings.triggered.connect(self.profilesettings)
|
||||
self.actionPrivacy_settings.triggered.connect(self.privacy_settings)
|
||||
self.actionInterface_settings.triggered.connect(self.interface_settings)
|
||||
self.actionNotifications.triggered.connect(self.notification_settings)
|
||||
self.audioSettings.triggered.connect(self.audio_settings)
|
||||
self.pluginData.triggered.connect(self.plugins_menu)
|
||||
self.lockApp.triggered.connect(self.lock_app)
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
||||
def languageChange(self, *args, **kwargs):
|
||||
@ -86,13 +91,14 @@ class MainWindow(QtGui.QMainWindow):
|
||||
return super(MainWindow, self).event(event)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.lockApp.setText(QtGui.QApplication.translate("MainWindow", "Lock", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.menuPlugins.setTitle(QtGui.QApplication.translate("MainWindow", "Plugins", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.pluginData.setText(QtGui.QApplication.translate("MainWindow", "List of plugins", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.menuProfile.setTitle(QtGui.QApplication.translate("MainWindow", "Profile", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.menuSettings.setTitle(QtGui.QApplication.translate("MainWindow", "Settings", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.menuAbout.setTitle(QtGui.QApplication.translate("MainWindow", "About", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.actionAdd_friend.setText(QtGui.QApplication.translate("MainWindow", "Add contact", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.actionProfile_settings.setText(QtGui.QApplication.translate("MainWindow", "Profile", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.actionprofilesettings.setText(QtGui.QApplication.translate("MainWindow", "Profile", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.actionPrivacy_settings.setText(QtGui.QApplication.translate("MainWindow", "Privacy", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.actionInterface_settings.setText(QtGui.QApplication.translate("MainWindow", "Interface", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.actionNotifications.setText(QtGui.QApplication.translate("MainWindow", "Notifications", None, QtGui.QApplication.UnicodeUTF8))
|
||||
@ -183,9 +189,9 @@ class MainWindow(QtGui.QMainWindow):
|
||||
Form.status_message.setObjectName("status_message")
|
||||
self.connection_status = Form.connection_status = StatusCircle(Form)
|
||||
Form.connection_status.setGeometry(QtCore.QRect(230, 35, 32, 32))
|
||||
self.avatar_label.mouseReleaseEvent = self.profile_settings
|
||||
self.status_message.mouseReleaseEvent = self.profile_settings
|
||||
self.name.mouseReleaseEvent = self.profile_settings
|
||||
self.avatar_label.mouseReleaseEvent = self.profilesettings
|
||||
self.status_message.mouseReleaseEvent = self.profilesettings
|
||||
self.name.mouseReleaseEvent = self.profilesettings
|
||||
self.connection_status.raise_()
|
||||
Form.connection_status.setObjectName("connection_status")
|
||||
|
||||
@ -367,7 +373,7 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.a_c = AddContact(link)
|
||||
self.a_c.show()
|
||||
|
||||
def profile_settings(self, *args):
|
||||
def profilesettings(self, *args):
|
||||
self.p_s = ProfileSettings()
|
||||
self.p_s.show()
|
||||
|
||||
@ -387,13 +393,26 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.audio_s = AudioSettings()
|
||||
self.audio_s.show()
|
||||
|
||||
def lock_app(self):
|
||||
if toxencryptsave.ToxEncryptSave.get_instance().has_password():
|
||||
Settings.get_instance().locked = True
|
||||
self.hide()
|
||||
else:
|
||||
msgBox = QtGui.QMessageBox()
|
||||
msgBox.setWindowTitle(
|
||||
QtGui.QApplication.translate("MainWindow", "Cannot lock app", None, QtGui.QApplication.UnicodeUTF8))
|
||||
msgBox.setText(
|
||||
QtGui.QApplication.translate("MainWindow", 'Error. Profile password is not set.', None,
|
||||
QtGui.QApplication.UnicodeUTF8))
|
||||
msgBox.exec_()
|
||||
|
||||
def show_menu(self):
|
||||
if not hasattr(self, 'menu'):
|
||||
self.menu = DropdownMenu(self)
|
||||
self.menu.setGeometry(QtCore.QRect(0 if Settings.get_instance()['mirror_mode'] else 270,
|
||||
self.height() - 100,
|
||||
150,
|
||||
100))
|
||||
self.height() - 120,
|
||||
180,
|
||||
120))
|
||||
self.menu.show()
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
@ -408,7 +427,7 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.menu.hide()
|
||||
if self.profile.active_friend + 1:
|
||||
choose = QtGui.QApplication.translate("MainWindow", 'Choose file', None, QtGui.QApplication.UnicodeUTF8)
|
||||
name = QtGui.QFileDialog.getOpenFileName(self, choose)
|
||||
name = QtGui.QFileDialog.getOpenFileName(self, choose, options=QtGui.QFileDialog.DontUseNativeDialog)
|
||||
if name[0]:
|
||||
self.profile.send_file(name[0])
|
||||
|
||||
@ -476,7 +495,11 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.listMenu = QtGui.QMenu()
|
||||
set_alias_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Set alias', None, QtGui.QApplication.UnicodeUTF8))
|
||||
clear_history_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Clear history', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_key_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Copy public key', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_menu = self.listMenu.addMenu(QtGui.QApplication.translate("MainWindow", 'Copy', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_name_item = copy_menu.addAction(QtGui.QApplication.translate("MainWindow", 'Name', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_status_item = copy_menu.addAction(QtGui.QApplication.translate("MainWindow", 'Status message', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_key_item = copy_menu.addAction(QtGui.QApplication.translate("MainWindow", 'Public key', None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
auto_accept_item = self.listMenu.addAction(auto)
|
||||
remove_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Remove friend', None, QtGui.QApplication.UnicodeUTF8))
|
||||
notes_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Notes', None, QtGui.QApplication.UnicodeUTF8))
|
||||
@ -491,6 +514,8 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.connect(clear_history_item, QtCore.SIGNAL("triggered()"), lambda: self.clear_history(num))
|
||||
self.connect(auto_accept_item, QtCore.SIGNAL("triggered()"), lambda: self.auto_accept(num, not allowed))
|
||||
self.connect(notes_item, QtCore.SIGNAL("triggered()"), lambda: self.show_note(friend))
|
||||
self.connect(copy_name_item, QtCore.SIGNAL("triggered()"), lambda: self.copy_name(friend))
|
||||
self.connect(copy_status_item, QtCore.SIGNAL("triggered()"), lambda: self.copy_status(friend))
|
||||
parent_position = self.friends_list.mapToGlobal(QtCore.QPoint(0, 0))
|
||||
self.listMenu.move(parent_position + pos)
|
||||
self.listMenu.show()
|
||||
@ -521,6 +546,14 @@ class MainWindow(QtGui.QMainWindow):
|
||||
clipboard = QtGui.QApplication.clipboard()
|
||||
clipboard.setText(tox_id)
|
||||
|
||||
def copy_name(self, friend):
|
||||
clipboard = QtGui.QApplication.clipboard()
|
||||
clipboard.setText(friend.name)
|
||||
|
||||
def copy_status(self, friend):
|
||||
clipboard = QtGui.QApplication.clipboard()
|
||||
clipboard.setText(friend.status_message)
|
||||
|
||||
def clear_history(self, num):
|
||||
self.profile.clear_history(num)
|
||||
|
@ -2,7 +2,7 @@ try:
|
||||
from PySide import QtCore, QtGui
|
||||
except ImportError:
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from widgets import RubberBand, create_menu, QRightClickButton
|
||||
from widgets import RubberBand, create_menu, QRightClickButton, CenteredWidget
|
||||
from profile import Profile
|
||||
import smileys
|
||||
import util
|
||||
@ -198,52 +198,52 @@ class DropdownMenu(QtGui.QWidget):
|
||||
super(DropdownMenu, self).__init__(parent)
|
||||
self.installEventFilter(self)
|
||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
|
||||
self.setMaximumSize(150, 100)
|
||||
self.setMinimumSize(150, 100)
|
||||
self.setMaximumSize(180, 120)
|
||||
self.setMinimumSize(180, 120)
|
||||
self.screenshotButton = QRightClickButton(self)
|
||||
self.screenshotButton.setGeometry(QtCore.QRect(0, 50, 50, 50))
|
||||
self.screenshotButton.setGeometry(QtCore.QRect(0, 60, 60, 60))
|
||||
self.screenshotButton.setObjectName("screenshotButton")
|
||||
|
||||
self.fileTransferButton = QtGui.QPushButton(self)
|
||||
self.fileTransferButton.setGeometry(QtCore.QRect(50, 50, 50, 50))
|
||||
self.fileTransferButton.setGeometry(QtCore.QRect(60, 60, 60, 60))
|
||||
self.fileTransferButton.setObjectName("fileTransferButton")
|
||||
|
||||
self.audioMessageButton = QtGui.QPushButton(self)
|
||||
self.audioMessageButton.setGeometry(QtCore.QRect(100, 50, 50, 50))
|
||||
self.audioMessageButton.setGeometry(QtCore.QRect(120, 60, 60, 60))
|
||||
|
||||
self.smileyButton = QtGui.QPushButton(self)
|
||||
self.smileyButton.setGeometry(QtCore.QRect(0, 0, 50, 50))
|
||||
self.smileyButton.setGeometry(QtCore.QRect(0, 0, 60, 60))
|
||||
|
||||
self.videoMessageButton = QtGui.QPushButton(self)
|
||||
self.videoMessageButton.setGeometry(QtCore.QRect(100, 0, 50, 50))
|
||||
self.videoMessageButton.setGeometry(QtCore.QRect(120, 0, 60, 60))
|
||||
|
||||
self.stickerButton = QtGui.QPushButton(self)
|
||||
self.stickerButton.setGeometry(QtCore.QRect(50, 0, 50, 50))
|
||||
self.stickerButton.setGeometry(QtCore.QRect(60, 0, 60, 60))
|
||||
|
||||
pixmap = QtGui.QPixmap(util.curr_directory() + '/images/file.png')
|
||||
icon = QtGui.QIcon(pixmap)
|
||||
self.fileTransferButton.setIcon(icon)
|
||||
self.fileTransferButton.setIconSize(QtCore.QSize(40, 40))
|
||||
self.fileTransferButton.setIconSize(QtCore.QSize(50, 50))
|
||||
pixmap = QtGui.QPixmap(util.curr_directory() + '/images/screenshot.png')
|
||||
icon = QtGui.QIcon(pixmap)
|
||||
self.screenshotButton.setIcon(icon)
|
||||
self.screenshotButton.setIconSize(QtCore.QSize(40, 50))
|
||||
self.screenshotButton.setIconSize(QtCore.QSize(50, 60))
|
||||
pixmap = QtGui.QPixmap(util.curr_directory() + '/images/audio_message.png')
|
||||
icon = QtGui.QIcon(pixmap)
|
||||
self.audioMessageButton.setIcon(icon)
|
||||
self.audioMessageButton.setIconSize(QtCore.QSize(40, 40))
|
||||
self.audioMessageButton.setIconSize(QtCore.QSize(50, 50))
|
||||
pixmap = QtGui.QPixmap(util.curr_directory() + '/images/smiley.png')
|
||||
icon = QtGui.QIcon(pixmap)
|
||||
self.smileyButton.setIcon(icon)
|
||||
self.smileyButton.setIconSize(QtCore.QSize(40, 40))
|
||||
self.smileyButton.setIconSize(QtCore.QSize(50, 50))
|
||||
pixmap = QtGui.QPixmap(util.curr_directory() + '/images/video_message.png')
|
||||
icon = QtGui.QIcon(pixmap)
|
||||
self.videoMessageButton.setIcon(icon)
|
||||
self.videoMessageButton.setIconSize(QtCore.QSize(45, 45))
|
||||
self.videoMessageButton.setIconSize(QtCore.QSize(55, 55))
|
||||
pixmap = QtGui.QPixmap(util.curr_directory() + '/images/sticker.png')
|
||||
icon = QtGui.QIcon(pixmap)
|
||||
self.stickerButton.setIcon(icon)
|
||||
self.stickerButton.setIconSize(QtCore.QSize(45, 45))
|
||||
self.stickerButton.setIconSize(QtCore.QSize(55, 55))
|
||||
|
||||
self.screenshotButton.setToolTip(QtGui.QApplication.translate("MenuWindow", "Send screenshot", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.fileTransferButton.setToolTip(QtGui.QApplication.translate("MenuWindow", "Send file", None, QtGui.QApplication.UnicodeUTF8))
|
||||
@ -312,3 +312,67 @@ class StickerWindow(QtGui.QWidget):
|
||||
self.close()
|
||||
|
||||
|
||||
class WelcomeScreen(CenteredWidget):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setMaximumSize(250, 200)
|
||||
self.setMinimumSize(250, 200)
|
||||
self.center()
|
||||
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||||
self.text = QtGui.QTextBrowser(self)
|
||||
self.text.setGeometry(QtCore.QRect(0, 0, 250, 170))
|
||||
self.text.setOpenExternalLinks(True)
|
||||
self.checkbox = QtGui.QCheckBox(self)
|
||||
self.checkbox.setGeometry(QtCore.QRect(5, 170, 240, 30))
|
||||
self.checkbox.setText(QtGui.QApplication.translate('WelcomeScreen', "Don't show again",
|
||||
None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.setWindowTitle(QtGui.QApplication.translate('WelcomeScreen', 'Tip of the day',
|
||||
None, QtGui.QApplication.UnicodeUTF8))
|
||||
import random
|
||||
num = random.randint(0, 8)
|
||||
if num == 0:
|
||||
text = QtGui.QApplication.translate('WelcomeScreen', 'Press Esc if you want hide app to tray.',
|
||||
None, QtGui.QApplication.UnicodeUTF8)
|
||||
elif num == 1:
|
||||
text = QtGui.QApplication.translate('WelcomeScreen',
|
||||
'Right click on screenshot button hides app to tray during screenshot.',
|
||||
None, QtGui.QApplication.UnicodeUTF8)
|
||||
elif num == 2:
|
||||
text = QtGui.QApplication.translate('WelcomeScreen',
|
||||
'You can use Tox over Tor. For more info read <a href="https://wiki.tox.chat/users/tox_over_tor_tot">this post</a>',
|
||||
None, QtGui.QApplication.UnicodeUTF8)
|
||||
elif num == 3:
|
||||
text = QtGui.QApplication.translate('WelcomeScreen',
|
||||
'Use Settings -> Interface to customize interface.',
|
||||
None, QtGui.QApplication.UnicodeUTF8)
|
||||
elif num == 4:
|
||||
text = QtGui.QApplication.translate('WelcomeScreen',
|
||||
'Set profile password via Profile -> Settings. Password allows Toxygen encrypt your history and settings.',
|
||||
None, QtGui.QApplication.UnicodeUTF8)
|
||||
elif num == 5:
|
||||
text = QtGui.QApplication.translate('WelcomeScreen',
|
||||
'Since v0.1.3 Toxygen supports plugins. <a href="https://github.com/xveduk/toxygen/blob/master/docs/plugins.md">Read more</a>',
|
||||
None, QtGui.QApplication.UnicodeUTF8)
|
||||
elif num == 6:
|
||||
text = QtGui.QApplication.translate('WelcomeScreen',
|
||||
'New in Toxygen v0.2.2:<br>Users can lock application using profile password.<br>Compact contact list support<br>Bug fixes<br>Tox DNS improvements',
|
||||
None, QtGui.QApplication.UnicodeUTF8)
|
||||
elif num == 7:
|
||||
text = QtGui.QApplication.translate('WelcomeScreen',
|
||||
'Toxygen supports faux offline messages and file transfers. Send message or file to offline friend and he will get it later.',
|
||||
None, QtGui.QApplication.UnicodeUTF8)
|
||||
else:
|
||||
text = QtGui.QApplication.translate('WelcomeScreen',
|
||||
'Set new NoSpam to avoid spam friend requests: Profile -> Settings -> Set new NoSpam.',
|
||||
None, QtGui.QApplication.UnicodeUTF8)
|
||||
self.text.setHtml(text)
|
||||
self.checkbox.stateChanged.connect(self.not_show)
|
||||
QtCore.QTimer.singleShot(1000, self.show)
|
||||
|
||||
def not_show(self):
|
||||
import settings
|
||||
s = settings.Settings.get_instance()
|
||||
s['show_welcome_screen'] = False
|
||||
s.save()
|
||||
|
@ -122,17 +122,19 @@ class ProfileSettings(CenteredWidget):
|
||||
self.new_nospam = QtGui.QPushButton(self)
|
||||
self.new_nospam.setGeometry(QtCore.QRect(420, 250, 180, 30))
|
||||
self.new_nospam.clicked.connect(self.new_no_spam)
|
||||
|
||||
self.copy_pk = QtGui.QPushButton(self)
|
||||
self.copy_pk.setGeometry(QtCore.QRect(40, 300, 180, 30))
|
||||
self.copy_pk.clicked.connect(self.copy_public_key)
|
||||
self.new_avatar = QtGui.QPushButton(self)
|
||||
self.new_avatar.setGeometry(QtCore.QRect(40, 300, 180, 30))
|
||||
self.new_avatar.setGeometry(QtCore.QRect(230, 300, 180, 30))
|
||||
self.delete_avatar = QtGui.QPushButton(self)
|
||||
self.delete_avatar.setGeometry(QtCore.QRect(230, 300, 180, 30))
|
||||
self.delete_avatar.setGeometry(QtCore.QRect(420, 300, 180, 30))
|
||||
self.delete_avatar.clicked.connect(self.reset_avatar)
|
||||
self.new_avatar.clicked.connect(self.set_avatar)
|
||||
self.profile_pass = QtGui.QLabel(self)
|
||||
self.profile_pass.setGeometry(QtCore.QRect(40, 340, 300, 30))
|
||||
self.profilepass = QtGui.QLabel(self)
|
||||
self.profilepass.setGeometry(QtCore.QRect(40, 340, 300, 30))
|
||||
font.setPointSize(18)
|
||||
self.profile_pass.setFont(font)
|
||||
self.profilepass.setFont(font)
|
||||
self.password = LineEdit(self)
|
||||
self.password.setGeometry(QtCore.QRect(40, 380, 300, 30))
|
||||
self.password.setEchoMode(QtGui.QLineEdit.EchoMode.Password)
|
||||
@ -173,7 +175,7 @@ class ProfileSettings(CenteredWidget):
|
||||
self.new_avatar.setText(QtGui.QApplication.translate("ProfileSettingsForm", "New avatar", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.delete_avatar.setText(QtGui.QApplication.translate("ProfileSettingsForm", "Reset avatar", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.new_nospam.setText(QtGui.QApplication.translate("ProfileSettingsForm", "New NoSpam", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.profile_pass.setText(QtGui.QApplication.translate("ProfileSettingsForm", "Profile password", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.profilepass.setText(QtGui.QApplication.translate("ProfileSettingsForm", "Profile password", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.password.setPlaceholderText(QtGui.QApplication.translate("ProfileSettingsForm", "Password (at least 8 symbols)", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.confirm_password.setPlaceholderText(QtGui.QApplication.translate("ProfileSettingsForm", "Confirm password", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.set_password.setText(QtGui.QApplication.translate("ProfileSettingsForm", "Set password", None, QtGui.QApplication.UnicodeUTF8))
|
||||
@ -183,6 +185,7 @@ class ProfileSettings(CenteredWidget):
|
||||
self.status.addItem(QtGui.QApplication.translate("ProfileSettingsForm", "Online", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.status.addItem(QtGui.QApplication.translate("ProfileSettingsForm", "Away", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.status.addItem(QtGui.QApplication.translate("ProfileSettingsForm", "Busy", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.copy_pk.setText(QtGui.QApplication.translate("ProfileSettingsForm", "Copy public key", None, QtGui.QApplication.UnicodeUTF8))
|
||||
if self.auto:
|
||||
self.default.setText(QtGui.QApplication.translate("ProfileSettingsForm", "Mark as not default profile", None, QtGui.QApplication.UnicodeUTF8))
|
||||
else:
|
||||
@ -205,7 +208,7 @@ class ProfileSettings(CenteredWidget):
|
||||
def new_password(self):
|
||||
if self.password.text() == self.confirm_password.text():
|
||||
if not len(self.password.text()) or len(self.password.text()) >= 8:
|
||||
e = toxencryptsave.LibToxEncryptSave.get_instance()
|
||||
e = toxencryptsave.ToxEncryptSave.get_instance()
|
||||
e.set_password(self.password.text())
|
||||
self.close()
|
||||
else:
|
||||
@ -227,6 +230,15 @@ class ProfileSettings(CenteredWidget):
|
||||
self.copyId.setIcon(icon)
|
||||
self.copyId.setIconSize(QtCore.QSize(10, 10))
|
||||
|
||||
def copy_public_key(self):
|
||||
clipboard = QtGui.QApplication.clipboard()
|
||||
profile = Profile.get_instance()
|
||||
clipboard.setText(profile.tox_id[:64])
|
||||
pixmap = QtGui.QPixmap(curr_directory() + '/images/accept.png')
|
||||
icon = QtGui.QIcon(pixmap)
|
||||
self.copy_pk.setIcon(icon)
|
||||
self.copy_pk.setIconSize(QtCore.QSize(10, 10))
|
||||
|
||||
def new_no_spam(self):
|
||||
self.tox_id.setText(Profile.get_instance().new_nospam())
|
||||
|
||||
@ -235,7 +247,8 @@ class ProfileSettings(CenteredWidget):
|
||||
|
||||
def set_avatar(self):
|
||||
choose = QtGui.QApplication.translate("ProfileSettingsForm", "Choose avatar", None, QtGui.QApplication.UnicodeUTF8)
|
||||
name = QtGui.QFileDialog.getOpenFileName(self, choose, None, 'Images (*.png)')
|
||||
name = QtGui.QFileDialog.getOpenFileName(self, choose, None, 'Images (*.png)',
|
||||
options=QtGui.QFileDialog.DontUseNativeDialog)
|
||||
if name[0]:
|
||||
bitmap = QtGui.QPixmap(name[0])
|
||||
bitmap.scaled(QtCore.QSize(128, 128), aspectMode=QtCore.Qt.KeepAspectRatio,
|
||||
@ -248,7 +261,7 @@ class ProfileSettings(CenteredWidget):
|
||||
Profile.get_instance().set_avatar(str(byte_array.data()))
|
||||
|
||||
def export_profile(self):
|
||||
directory = QtGui.QFileDialog.getExistingDirectory() + '/'
|
||||
directory = QtGui.QFileDialog.getExistingDirectory(options=QtGui.QFileDialog.DontUseNativeDialog) + '/'
|
||||
if directory != '/':
|
||||
ProfileHelper.get_instance().export_profile(directory)
|
||||
settings = Settings.get_instance()
|
||||
@ -378,7 +391,7 @@ class PrivacySettings(CenteredWidget):
|
||||
self.auto_path = QtGui.QLabel(self)
|
||||
self.auto_path.setGeometry(QtCore.QRect(10, 230, 350, 30))
|
||||
self.path = QtGui.QPlainTextEdit(self)
|
||||
self.path.setGeometry(QtCore.QRect(10, 265, 330, 45))
|
||||
self.path.setGeometry(QtCore.QRect(10, 265, 350, 45))
|
||||
self.change_path = QtGui.QPushButton(self)
|
||||
self.change_path.setGeometry(QtCore.QRect(10, 320, 350, 30))
|
||||
settings = Settings.get_instance()
|
||||
@ -477,7 +490,7 @@ class PrivacySettings(CenteredWidget):
|
||||
settings.save()
|
||||
|
||||
def new_path(self):
|
||||
directory = QtGui.QFileDialog.getExistingDirectory() + '/'
|
||||
directory = QtGui.QFileDialog.getExistingDirectory(options=QtGui.QFileDialog.DontUseNativeDialog) + '/'
|
||||
if directory != '/':
|
||||
self.path.setPlainText(directory)
|
||||
|
||||
@ -557,7 +570,7 @@ class InterfaceSettings(CenteredWidget):
|
||||
self.themeSelect.setCurrentIndex(index)
|
||||
self.lang_choose = QtGui.QComboBox(self)
|
||||
self.lang_choose.setGeometry(QtCore.QRect(30, 110, 120, 30))
|
||||
supported = Settings.supported_languages()
|
||||
supported = sorted(Settings.supported_languages().keys(), reverse=True)
|
||||
for key in supported:
|
||||
self.lang_choose.insertItem(0, key)
|
||||
if settings['language'] == key:
|
||||
@ -592,9 +605,13 @@ class InterfaceSettings(CenteredWidget):
|
||||
self.messages_font_size.setCurrentIndex(settings['message_font_size'] - 10)
|
||||
|
||||
self.unread = QtGui.QPushButton(self)
|
||||
self.unread.setGeometry(QtCore.QRect(30, 380, 340, 40))
|
||||
self.unread.setGeometry(QtCore.QRect(30, 380, 340, 30))
|
||||
self.unread.clicked.connect(self.select_color)
|
||||
|
||||
self.compact_mode = QtGui.QCheckBox(self)
|
||||
self.compact_mode.setGeometry(QtCore.QRect(30, 425, 370, 20))
|
||||
self.compact_mode.setChecked(settings['compact_mode'])
|
||||
|
||||
self.retranslateUi()
|
||||
QtCore.QMetaObject.connectSlotsByName(self)
|
||||
|
||||
@ -607,6 +624,7 @@ class InterfaceSettings(CenteredWidget):
|
||||
self.mirror_mode.setText(QtGui.QApplication.translate("interfaceForm", "Mirror mode", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.messages_font_size_label.setText(QtGui.QApplication.translate("interfaceForm", "Messages font size:", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.unread.setText(QtGui.QApplication.translate("interfaceForm", "Select unread messages notification color", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.compact_mode.setText(QtGui.QApplication.translate("interfaceForm", "Compact contact list", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
def select_color(self):
|
||||
col = QtGui.QColorDialog.getColor()
|
||||
@ -621,15 +639,13 @@ class InterfaceSettings(CenteredWidget):
|
||||
settings = Settings.get_instance()
|
||||
settings['theme'] = str(self.themeSelect.currentText())
|
||||
settings['smileys'] = self.smileys.isChecked()
|
||||
restart = False
|
||||
if settings['mirror_mode'] != self.mirror_mode.isChecked():
|
||||
settings['mirror_mode'] = self.mirror_mode.isChecked()
|
||||
msgBox = QtGui.QMessageBox()
|
||||
text = QtGui.QApplication.translate("interfaceForm", 'Restart app to apply settings', None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
msgBox.setWindowTitle(QtGui.QApplication.translate("interfaceForm", 'Restart required', None,
|
||||
QtGui.QApplication.UnicodeUTF8))
|
||||
msgBox.setText(text)
|
||||
msgBox.exec_()
|
||||
restart = True
|
||||
if settings['compact_mode'] != self.compact_mode.isChecked():
|
||||
settings['compact_mode'] = self.compact_mode.isChecked()
|
||||
restart = True
|
||||
settings['smiley_pack'] = self.smiley_pack.currentText()
|
||||
smileys.SmileyLoader.get_instance().load_pack()
|
||||
language = self.lang_choose.currentText()
|
||||
@ -644,6 +660,14 @@ class InterfaceSettings(CenteredWidget):
|
||||
settings['message_font_size'] = self.messages_font_size.currentIndex() + 10
|
||||
Profile.get_instance().update()
|
||||
settings.save()
|
||||
if restart:
|
||||
msgBox = QtGui.QMessageBox()
|
||||
text = QtGui.QApplication.translate("interfaceForm", 'Restart app to apply settings', None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
msgBox.setWindowTitle(QtGui.QApplication.translate("interfaceForm", 'Restart required', None,
|
||||
QtGui.QApplication.UnicodeUTF8))
|
||||
msgBox.setText(text)
|
||||
msgBox.exec_()
|
||||
|
||||
|
||||
class AudioSettings(CenteredWidget):
|
@ -19,12 +19,11 @@ class PasswordArea(LineEdit):
|
||||
super(PasswordArea, self).keyPressEvent(event)
|
||||
|
||||
|
||||
class PasswordScreen(CenteredWidget):
|
||||
class PasswordScreenBase(CenteredWidget):
|
||||
|
||||
def __init__(self, encrypt, data):
|
||||
super(PasswordScreen, self).__init__()
|
||||
def __init__(self, encrypt):
|
||||
super(PasswordScreenBase, self).__init__()
|
||||
self._encrypt = encrypt
|
||||
self._data = data
|
||||
self.initUI()
|
||||
|
||||
def initUI(self):
|
||||
@ -52,6 +51,27 @@ class PasswordScreen(CenteredWidget):
|
||||
self.center()
|
||||
QtCore.QMetaObject.connectSlotsByName(self)
|
||||
|
||||
def button_click(self):
|
||||
pass
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if event.key() == QtCore.Qt.Key_Enter:
|
||||
self.button_click()
|
||||
else:
|
||||
super(PasswordScreenBase, self).keyPressEvent(event)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.setWindowTitle(QtGui.QApplication.translate("pass", "Enter password", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.enter_pass.setText(QtGui.QApplication.translate("pass", "Password:", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.warning.setText(QtGui.QApplication.translate("pass", "Incorrect password", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
|
||||
class PasswordScreen(PasswordScreenBase):
|
||||
|
||||
def __init__(self, encrypt, data):
|
||||
super(PasswordScreen, self).__init__(encrypt)
|
||||
self._data = data
|
||||
|
||||
def button_click(self):
|
||||
if self.password.text():
|
||||
try:
|
||||
@ -64,14 +84,19 @@ class PasswordScreen(CenteredWidget):
|
||||
self._data[0] = new_data
|
||||
self.close()
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if event.key() == QtCore.Qt.Key_Enter:
|
||||
self.button_click()
|
||||
|
||||
class UnlockAppScreen(PasswordScreenBase):
|
||||
|
||||
def __init__(self, encrypt, callback):
|
||||
super(UnlockAppScreen, self).__init__(encrypt)
|
||||
self._callback = callback
|
||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
|
||||
|
||||
def button_click(self):
|
||||
if self.password.text():
|
||||
if self._encrypt.is_password(self.password.text()):
|
||||
self._callback()
|
||||
self.close()
|
||||
else:
|
||||
super(PasswordScreen, self).keyPressEvent(event)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.setWindowTitle(QtGui.QApplication.translate("pass", "Enter password", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.enter_pass.setText(QtGui.QApplication.translate("pass", "Password:", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.warning.setText(QtGui.QApplication.translate("pass", "Incorrect password", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
self.warning.setVisible(True)
|
||||
print('Wrong password!')
|
@ -16,7 +16,7 @@ class PluginLoader(util.Singleton):
|
||||
self._settings = settings
|
||||
self._plugins = {} # dict. key - plugin unique short name, value - tuple (plugin instance, is active)
|
||||
self._tox = tox
|
||||
self._encr = toxencryptsave.LibToxEncryptSave.get_instance()
|
||||
self._encr = toxencryptsave.ToxEncryptSave.get_instance()
|
||||
|
||||
def set_tox(self, tox):
|
||||
"""
|
@ -38,6 +38,7 @@ class Profile(contact.Contact, Singleton):
|
||||
self._file_transfers = {} # dict of file transfers. key - tuple (friend_number, file_number)
|
||||
self._call = calls.AV(tox.AV) # object with data about calls
|
||||
self._incoming_calls = set()
|
||||
self._load_history = True
|
||||
settings = Settings.get_instance()
|
||||
self._show_online = settings['show_online_friends']
|
||||
screen.online_contacts.setCurrentIndex(int(self._show_online))
|
||||
@ -54,6 +55,8 @@ class Profile(contact.Contact, Singleton):
|
||||
item = self.create_friend_item()
|
||||
name = alias or tox.friend_get_name(i) or tox_id
|
||||
status_message = tox.friend_get_status_message(i)
|
||||
if not self._history.friend_exists_in_db(tox_id):
|
||||
self._history.add_friend_to_db(tox_id)
|
||||
message_getter = self._history.messages_getter(tox_id)
|
||||
friend = Friend(message_getter, i, name, status_message, item, tox_id)
|
||||
friend.set_alias(alias)
|
||||
@ -113,15 +116,16 @@ class Profile(contact.Contact, Singleton):
|
||||
:param filter_str: show contacts which name contains this substring
|
||||
"""
|
||||
filter_str = filter_str.lower()
|
||||
settings = Settings.get_instance()
|
||||
for index, friend in enumerate(self._friends):
|
||||
friend.visibility = (friend.status is not None or not show_online) and (filter_str in friend.name.lower())
|
||||
friend.visibility = friend.visibility or friend.messages or friend.actions
|
||||
if friend.visibility:
|
||||
self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250, 70))
|
||||
self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250,
|
||||
40 if settings['compact_mode'] else 70))
|
||||
else:
|
||||
self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250, 0))
|
||||
self._show_online, self._filter_string = show_online, filter_str
|
||||
settings = Settings.get_instance()
|
||||
settings['show_online_friends'] = self._show_online
|
||||
settings.save()
|
||||
|
||||
@ -175,6 +179,7 @@ class Profile(contact.Contact, Singleton):
|
||||
self._messages.clear()
|
||||
friend.load_corr()
|
||||
messages = friend.get_corr()[-PAGE_SIZE:]
|
||||
self._load_history = False
|
||||
for message in messages:
|
||||
if message.get_type() <= 1:
|
||||
data = message.get_data()
|
||||
@ -203,6 +208,7 @@ class Profile(contact.Contact, Singleton):
|
||||
'',
|
||||
data[3])
|
||||
self._messages.scrollToBottom()
|
||||
self._load_history = True
|
||||
if value in self._call:
|
||||
self._screen.active_call()
|
||||
elif value in self._incoming_calls:
|
||||
@ -223,6 +229,7 @@ class Profile(contact.Contact, Singleton):
|
||||
self._screen.account_avatar.setScaledContents(False)
|
||||
self._screen.account_avatar.setPixmap(pixmap.scaled(64, 64, QtCore.Qt.KeepAspectRatio))
|
||||
self._screen.account_avatar.repaint() # comment?
|
||||
self.update_filtration()
|
||||
except Exception as ex: # no friend found. ignore
|
||||
log('Friend value: ' + str(value))
|
||||
log('Error: ' + str(ex))
|
||||
@ -387,6 +394,7 @@ class Profile(contact.Contact, Singleton):
|
||||
plugin_support.PluginLoader.get_instance().command(text[8:])
|
||||
self._screen.messageEdit.clear()
|
||||
elif text and self._active_friend + 1:
|
||||
text = ''.join(c if c <= '\u10FFFF' else '\u25AF' for c in text)
|
||||
if text.startswith('/me '):
|
||||
message_type = TOX_MESSAGE_TYPE['ACTION']
|
||||
text = text[4:]
|
||||
@ -454,6 +462,9 @@ class Profile(contact.Contact, Singleton):
|
||||
"""
|
||||
Tries to load next part of messages
|
||||
"""
|
||||
if not self._load_history:
|
||||
return
|
||||
self._load_history = False
|
||||
friend = self._friends[self._active_friend]
|
||||
friend.load_corr(False)
|
||||
data = friend.get_corr()
|
||||
@ -489,6 +500,7 @@ class Profile(contact.Contact, Singleton):
|
||||
data[2],
|
||||
'',
|
||||
data[3])
|
||||
self._load_history = True
|
||||
|
||||
def export_history(self, directory):
|
||||
self._history.export(directory)
|
||||
@ -504,7 +516,7 @@ class Profile(contact.Contact, Singleton):
|
||||
"""
|
||||
item = ContactItem()
|
||||
elem = QtGui.QListWidgetItem(self._screen.friends_list)
|
||||
elem.setSizeHint(QtCore.QSize(250, 70))
|
||||
elem.setSizeHint(QtCore.QSize(250, item.height()))
|
||||
self._screen.friends_list.addItem(elem)
|
||||
self._screen.friends_list.setItemWidget(elem, item)
|
||||
return item
|
||||
@ -757,8 +769,9 @@ class Profile(contact.Contact, Singleton):
|
||||
Recreate tox instance
|
||||
:param restart: method which calls restart and returns new tox instance
|
||||
"""
|
||||
for key in self._file_transfers.keys():
|
||||
self._file_transfers[key].cancel()
|
||||
# TODO: file transfers!!
|
||||
for key in list(self._file_transfers.keys()):
|
||||
self._file_transfers[key].cancelled()
|
||||
del self._file_transfers[key]
|
||||
self._call.stop()
|
||||
del self._tox
|
||||
@ -766,6 +779,7 @@ class Profile(contact.Contact, Singleton):
|
||||
self.status = None
|
||||
for friend in self._friends:
|
||||
friend.status = None
|
||||
self.update_filtration()
|
||||
|
||||
def close(self):
|
||||
if hasattr(self, '_call'):
|
@ -4,7 +4,7 @@ import os
|
||||
import locale
|
||||
from util import Singleton, curr_directory, log
|
||||
import pyaudio
|
||||
from toxencryptsave import LibToxEncryptSave
|
||||
from toxencryptsave import ToxEncryptSave
|
||||
import smileys
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ class Settings(dict, Singleton):
|
||||
if os.path.isfile(self.path):
|
||||
with open(self.path, 'rb') as fl:
|
||||
data = fl.read()
|
||||
inst = LibToxEncryptSave.get_instance()
|
||||
inst = ToxEncryptSave.get_instance()
|
||||
try:
|
||||
if inst.is_data_encrypted(data):
|
||||
data = inst.pass_decrypt(data)
|
||||
@ -35,6 +35,7 @@ class Settings(dict, Singleton):
|
||||
self.save()
|
||||
smileys.SmileyLoader(self)
|
||||
p = pyaudio.PyAudio()
|
||||
self.locked = False
|
||||
self.audio = {'input': p.get_default_input_device_info()['index'],
|
||||
'output': p.get_default_output_device_info()['index']}
|
||||
|
||||
@ -94,8 +95,8 @@ class Settings(dict, Singleton):
|
||||
'ipv6_enabled': True,
|
||||
'udp_enabled': True,
|
||||
'proxy_type': 0,
|
||||
'proxy_host': '0',
|
||||
'proxy_port': 0,
|
||||
'proxy_host': '127.0.0.1',
|
||||
'proxy_port': 9050,
|
||||
'start_port': 0,
|
||||
'end_port': 0,
|
||||
'tcp_port': 0,
|
||||
@ -123,7 +124,9 @@ class Settings(dict, Singleton):
|
||||
'y': 400,
|
||||
'message_font_size': 14,
|
||||
'unread_color': 'red',
|
||||
'save_unsent_only': False
|
||||
'save_unsent_only': False,
|
||||
'compact_mode': False,
|
||||
'show_welcome_screen': True
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@ -144,7 +147,7 @@ class Settings(dict, Singleton):
|
||||
|
||||
def save(self):
|
||||
text = json.dumps(self)
|
||||
inst = LibToxEncryptSave.get_instance()
|
||||
inst = ToxEncryptSave.get_instance()
|
||||
if inst.has_password():
|
||||
text = bytes(inst.pass_encrypt(bytes(text, 'utf-8')))
|
||||
else:
|
||||
@ -179,8 +182,8 @@ class Settings(dict, Singleton):
|
||||
app_settings = {}
|
||||
if 'active_profile' not in app_settings:
|
||||
app_settings['active_profile'] = []
|
||||
profile_path = ProfileHelper.get_path()
|
||||
app_settings['active_profile'].append(str(profile_path + str(self.name) + '.tox'))
|
||||
profilepath = ProfileHelper.get_path()
|
||||
app_settings['active_profile'].append(str(profilepath + str(self.name) + '.tox'))
|
||||
data = json.dumps(app_settings)
|
||||
with open(path, 'w') as fl:
|
||||
fl.write(data)
|
||||
@ -223,7 +226,7 @@ class ProfileHelper(Singleton):
|
||||
return self._directory
|
||||
|
||||
def save_profile(self, data):
|
||||
inst = LibToxEncryptSave.get_instance()
|
||||
inst = ToxEncryptSave.get_instance()
|
||||
if inst.has_password():
|
||||
data = inst.pass_encrypt(data)
|
||||
with open(self._path, 'wb') as fl:
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 868 B After Width: | Height: | Size: 868 B |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 1010 B After Width: | Height: | Size: 1010 B |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |