13 Commits

Author SHA1 Message Date
337601f2a1 reconnection timeout++ and fix 2016-09-15 00:21:06 +03:00
42e0ec005b db timeout 2016-09-08 00:10:32 +03:00
fb1caa244a fix #25 2016-09-03 14:10:36 +03:00
0fd75c5517 fix #23 2016-08-30 20:23:55 +03:00
d81e3e781b fix #20 2016-08-28 16:11:40 +03:00
43d9a41dae bug fixes 2016-08-28 15:32:02 +03:00
1caf7cd63c readme update 2016-08-19 20:12:51 +03:00
14816588f1 some updates 2016-08-18 19:08:12 +03:00
47b710acdd bug fixes and docs update 2016-08-08 22:11:43 +03:00
3668088f3e some fixes 2016-08-08 14:07:18 +03:00
9f702afcb8 short update 2016-08-05 22:44:01 +03:00
18775ff4b2 missing () 2016-08-05 17:30:08 +03:00
a7431cadd1 v0.2.4 2016-08-05 16:58:46 +03:00
19 changed files with 857 additions and 529 deletions

4
.gitignore vendored
View File

@ -15,9 +15,11 @@ toxygen/libs
toxygen/build
toxygen/dist
*.spec
dist/
dist
toxygen/avatars
toxygen/__pycache__
/*.egg-info
/*.egg
html
Toxygen.egg-info

View File

@ -1,21 +1,20 @@
# Toxygen
Toxygen is cross-platform [Tox](https://tox.chat/) client written in pure Python3
Toxygen is powerful cross-platform [Tox](https://tox.chat/) client written in pure Python3.
[![Release](https://img.shields.io/github/release/xveduk/toxygen.svg?style=flat)](https://github.com/toxygen-project/toxygen/releases/latest)
[![Stars](https://img.shields.io/github/stars/xveduk/toxygen.svg?style=flat)](https://github.com/toxygen-project/toxygen/stargazers)
[![Open issues](https://img.shields.io/github/issues/xveduk/toxygen.svg?style=flat)](https://github.com/toxygen-project/toxygen/issues)
[![License](https://img.shields.io/badge/license-GPLv3-blue.svg?style=flat)](https://raw.githubusercontent.com/toxygen-project/toxygen/master/LICENSE.md)
[![Build Status](https://travis-ci.org/toxygen-project/toxygen.svg?branch=master)](https://travis-ci.org/toxygen-project/toxygen)
### [Install](/docs/install.md) - [Contribute](/docs/contributing.md) - [Plugins](/docs/plugins.md) - [Compile](/docs/compile.md) - [Contact](/docs/contact.md)
### Supported OS:
- Windows
- Linux
- OS X
![Linux, Windows and OS X](/docs/os.png)
### Features
### Features:
- [x] 1v1 messages
- [x] File transfers
@ -61,3 +60,7 @@ Toxygen is cross-platform [Tox](https://tox.chat/) client written in pure Python
### Docs
[Check /docs/ for more info](/docs/)
Also visit [pythonhosted.org/Toxygen/](http://pythonhosted.org/Toxygen/)
[Wiki](https://wiki.tox.chat/clients/toxygen)

View File

@ -27,12 +27,14 @@ Run app using ``toxygen`` command.
2. Install PortAudio:
``brew install portaudio``
3. Install toxygen:
``pip3 install toxygen``
``pip3.4 install toxygen``
4. Run toxygen using ``toxygen`` command.
## Packages
Coming soon.
Arch Linux: [AUR](https://aur.archlinux.org/packages/toxygen-git/)
Debian/Ubuntu: [tox.chat](https://tox.chat/download.html#gnulinux)
## From source code (recommended for developers)

BIN
docs/os.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -23,7 +23,7 @@ class IncomingCallWidget(widgets.CenteredWidget):
self.name = widgets.DataLabel(self)
self.name.setGeometry(QtCore.QRect(90, 20, 300, 25))
font = QtGui.QFont()
font.setFamily(settings.Settings.get_instance['font'])
font.setFamily(settings.Settings.get_instance()['font'])
font.setPointSize(16)
font.setBold(True)
self.name.setFont(font)

View File

@ -340,3 +340,8 @@ class ReceiveAvatar(ReceiveTransfer):
chdir(dirname(avatar_path))
remove(avatar_path)
rename(self._path, avatar_path)
self.finished(True)
def finished(self, emit=False):
if emit:
super().finished()

View File

@ -1,4 +1,3 @@
# coding=utf-8
from sqlite3 import connect
import settings
from os import chdir
@ -8,6 +7,8 @@ from toxencryptsave import ToxEncryptSave
PAGE_SIZE = 42
TIMEOUT = 11
MESSAGE_OWNER = {
'ME': 0,
'FRIEND': 1,
@ -32,7 +33,7 @@ class History:
fout.write(data)
except:
os.remove(path)
db = connect(name + '.hstr')
db = connect(name + '.hstr', timeout=TIMEOUT)
cursor = db.cursor()
cursor.execute('CREATE TABLE IF NOT EXISTS friends('
' tox_id TEXT PRIMARY KEY'
@ -62,7 +63,7 @@ class History:
def add_friend_to_db(self, tox_id):
chdir(settings.ProfileHelper.get_path())
db = connect(self._name + '.hstr')
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try:
cursor = db.cursor()
cursor.execute('INSERT INTO friends VALUES (?);', (tox_id, ))
@ -82,7 +83,7 @@ class History:
def delete_friend_from_db(self, tox_id):
chdir(settings.ProfileHelper.get_path())
db = connect(self._name + '.hstr')
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try:
cursor = db.cursor()
cursor.execute('DELETE FROM friends WHERE tox_id=?;', (tox_id, ))
@ -96,7 +97,7 @@ class History:
def friend_exists_in_db(self, tox_id):
chdir(settings.ProfileHelper.get_path())
db = connect(self._name + '.hstr')
db = connect(self._name + '.hstr', timeout=TIMEOUT)
cursor = db.cursor()
cursor.execute('SELECT 0 FROM friends WHERE tox_id=?', (tox_id, ))
result = cursor.fetchone()
@ -105,7 +106,7 @@ class History:
def save_messages_to_db(self, tox_id, messages_iter):
chdir(settings.ProfileHelper.get_path())
db = connect(self._name + '.hstr')
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try:
cursor = db.cursor()
cursor.executemany('INSERT INTO id' + tox_id + '(message, owner, unix_time, message_type) '
@ -119,7 +120,7 @@ class History:
def update_messages(self, tox_id, unsent_time):
chdir(settings.ProfileHelper.get_path())
db = connect(self._name + '.hstr')
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try:
cursor = db.cursor()
cursor.execute('UPDATE id' + tox_id + ' SET owner = 0 '
@ -134,7 +135,7 @@ class History:
def delete_message(self, tox_id, time):
chdir(settings.ProfileHelper.get_path())
db = connect(self._name + '.hstr')
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try:
cursor = db.cursor()
cursor.execute('DELETE FROM id' + tox_id + ' WHERE unix_time = ' + str(time) + ';')
@ -147,7 +148,7 @@ class History:
def delete_messages(self, tox_id):
chdir(settings.ProfileHelper.get_path())
db = connect(self._name + '.hstr')
db = connect(self._name + '.hstr', timeout=TIMEOUT)
try:
cursor = db.cursor()
cursor.execute('DELETE FROM id' + tox_id + ';')
@ -162,9 +163,10 @@ class History:
return History.MessageGetter(self._name, tox_id)
class MessageGetter:
def __init__(self, name, tox_id):
chdir(settings.ProfileHelper.get_path())
self._db = connect(name + '.hstr')
self._db = connect(name + '.hstr', timeout=TIMEOUT)
self._cursor = self._db.cursor()
self._cursor.execute('SELECT message, owner, unix_time, message_type FROM id' + tox_id +
' ORDER BY unix_time DESC;')

View File

@ -25,7 +25,9 @@ class MessageEdit(QtGui.QTextBrowser):
self.setOpenExternalLinks(True)
self.setAcceptRichText(True)
self.setOpenLinks(False)
self.setSearchPaths([smileys.SmileyLoader.get_instance().get_smileys_path()])
path = smileys.SmileyLoader.get_instance().get_smileys_path()
if path is not None:
self.setSearchPaths([path])
self.document().setDefaultStyleSheet('a { color: #306EFF; }')
text = self.decoratedText(text)
if message_type != TOX_MESSAGE_TYPE['NORMAL']:
@ -127,7 +129,7 @@ class MessageItem(QtGui.QWidget):
def __init__(self, text, time, user='', sent=True, message_type=TOX_MESSAGE_TYPE['NORMAL'], parent=None):
QtGui.QWidget.__init__(self, parent)
self.name = DataLabel(self)
self.name.setGeometry(QtCore.QRect(2, 2, 95, 20))
self.name.setGeometry(QtCore.QRect(2, 2, 95, 23))
self.name.setTextFormat(QtCore.Qt.PlainText)
font = QtGui.QFont()
font.setFamily(settings.Settings.get_instance()['font'])
@ -137,7 +139,7 @@ class MessageItem(QtGui.QWidget):
self.name.setText(user)
self.time = QtGui.QLabel(self)
self.time.setGeometry(QtCore.QRect(parent.width() - 50, 0, 50, 20))
self.time.setGeometry(QtCore.QRect(parent.width() - 60, 0, 50, 25))
font.setPointSize(10)
font.setBold(False)
self.time.setFont(font)
@ -151,12 +153,12 @@ class MessageItem(QtGui.QWidget):
self.time.setText(convert_time(time))
self.t = False
self.message = MessageEdit(text, parent.width() - 150, message_type, self)
self.message = MessageEdit(text, parent.width() - 160, message_type, self)
if message_type != TOX_MESSAGE_TYPE['NORMAL']:
self.name.setStyleSheet("QLabel { color: #5CB3FF; }")
self.message.setAlignment(QtCore.Qt.AlignCenter)
self.time.setStyleSheet("QLabel { color: #5CB3FF; }")
self.message.setGeometry(QtCore.QRect(100, 0, parent.width() - 150, self.message.height()))
self.message.setGeometry(QtCore.QRect(100, 0, parent.width() - 160, self.message.height()))
self.setFixedHeight(self.message.height())
def mouseReleaseEvent(self, event):
@ -295,7 +297,7 @@ class FileTransferItem(QtGui.QListWidget):
self.state = state
self.name = DataLabel(self)
self.name.setGeometry(QtCore.QRect(3, 7, 95, 20))
self.name.setGeometry(QtCore.QRect(3, 7, 95, 25))
self.name.setTextFormat(QtCore.Qt.PlainText)
font = QtGui.QFont()
font.setFamily(settings.Settings.get_instance()['font'])
@ -305,14 +307,14 @@ class FileTransferItem(QtGui.QListWidget):
self.name.setText(user)
self.time = QtGui.QLabel(self)
self.time.setGeometry(QtCore.QRect(width - 53, 7, 50, 20))
self.time.setGeometry(QtCore.QRect(width - 60, 7, 50, 25))
font.setPointSize(10)
font.setBold(False)
self.time.setFont(font)
self.time.setText(convert_time(time))
self.cancel = QtGui.QPushButton(self)
self.cancel.setGeometry(QtCore.QRect(width - 120, 2, 30, 30))
self.cancel.setGeometry(QtCore.QRect(width - 125, 2, 30, 30))
pixmap = QtGui.QPixmap(curr_directory() + '/images/decline.png')
icon = QtGui.QIcon(pixmap)
self.cancel.setIcon(icon)
@ -360,7 +362,7 @@ class FileTransferItem(QtGui.QListWidget):
self.file_name.setToolTip(file_name)
self.saved_name = file_name
self.time_left = QtGui.QLabel(self)
self.time_left.setGeometry(QtCore.QRect(width - 87, 7, 30, 20))
self.time_left.setGeometry(QtCore.QRect(width - 92, 7, 30, 20))
font.setPointSize(10)
self.time_left.setFont(font)
self.time_left.setVisible(state == TOX_FILE_TRANSFER_STATE['RUNNING'])

View File

@ -127,7 +127,7 @@ class MainWindow(QtGui.QMainWindow, Singleton):
self.messageEdit.setGeometry(QtCore.QRect(0, 3, 450, 55))
self.messageEdit.setObjectName("messageEdit")
font = QtGui.QFont()
font.setPointSize(10)
font.setPointSize(11)
font.setFamily(settings.Settings.get_instance()['font'])
self.messageEdit.setFont(font)
@ -260,7 +260,7 @@ class MainWindow(QtGui.QMainWindow, Singleton):
self.messages.setSpacing(1)
self.messages.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.messages.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
# self.messages.setFocusPolicy(QtCore.Qt.NoFocus)
self.messages.focusOutEvent = lambda event: self.messages.clearSelection()
def load(pos):
if not pos:
@ -326,10 +326,10 @@ class MainWindow(QtGui.QMainWindow, Singleton):
self.profile = Profile(tox, self)
def closeEvent(self, event):
self.profile.save_history()
self.profile.close()
s = Settings.get_instance()
if not s['close_to_tray'] or s.closing:
self.profile.save_history()
self.profile.close()
s['x'] = self.geometry().x()
s['y'] = self.geometry().y()
s['width'] = self.width()

View File

@ -365,7 +365,7 @@ class WelcomeScreen(CenteredWidget):
None, QtGui.QApplication.UnicodeUTF8)
elif num == 6:
text = QtGui.QApplication.translate('WelcomeScreen',
'New in Toxygen v0.2.3:<br>TCS compliance<br>Plugins, smileys and stickers import<br>Bug fixes',
'New in Toxygen v0.2.4:<br>File transfers update<br>Autoreconnection<br>Improvements<br>Bug fixes',
None, QtGui.QApplication.UnicodeUTF8)
elif num == 7:
text = QtGui.QApplication.translate('WelcomeScreen',

View File

@ -714,10 +714,10 @@ class InterfaceSettings(CenteredWidget):
msgBox.exec_()
def select_color(self):
col = QtGui.QColorDialog.getColor()
settings = Settings.get_instance()
col = QtGui.QColorDialog.getColor(settings['unread_color'])
if col.isValid():
settings = Settings.get_instance()
name = col.name()
settings['unread_color'] = name
settings.save()

View File

@ -237,7 +237,7 @@ class Profile(contact.Contact, Singleton):
self.update_filtration()
except Exception as ex: # no friend found. ignore
log('Friend value: ' + str(value))
log('Error: ' + str(ex))
log('Error in set active: ' + str(ex))
raise
active_friend = property(get_active, set_active)
@ -313,7 +313,7 @@ class Profile(contact.Contact, Singleton):
ft = self._file_transfers[(friend_num, file_num)]
if type(ft) is SendTransfer:
self._paused_file_transfers[ft.get_id()] = [ft.get_path(), friend_num, False, -1]
elif type(ft) is ReceiveTransfer:
elif type(ft) is ReceiveTransfer and ft.state != TOX_FILE_TRANSFER_STATE['INCOMING_NOT_STARTED']:
self._paused_file_transfers[ft.get_id()] = [ft.get_path(), friend_num, True, ft.total_size()]
self.cancel_transfer(friend_num, file_num, True)
@ -838,7 +838,7 @@ class Profile(contact.Contact, Singleton):
def reconnect(self):
if self.status is None or all(list(map(lambda x: x.status is None, self._friends))):
self.reset(self._screen.reset)
QtCore.QTimer.singleShot(30000, self.reconnect)
QtCore.QTimer.singleShot(45000, self.reconnect)
def close(self):
for friend in self._friends:
@ -1100,6 +1100,7 @@ class Profile(contact.Contact, Singleton):
t = type(transfer)
if t is ReceiveAvatar:
self.get_friend_by_number(friend_number).load_avatar()
if friend_number == self.get_active_number():
self.set_active(None)
elif t is ReceiveToBuffer or (t is SendFromBuffer and Settings.get_instance()['allow_inline']): # inline image
print('inline')
@ -1115,6 +1116,7 @@ class Profile(contact.Contact, Singleton):
elem.setSizeHint(QtCore.QSize(self._messages.width(), item.height()))
self._messages.insertItem(count + i + 1, elem)
self._messages.setItemWidget(elem, item)
self._messages.scrollToBottom()
elif t is not SendAvatar:
self.get_friend_by_number(friend_number).update_transfer_data(file_number,
TOX_FILE_TRANSFER_STATE['FINISHED'])

View File

@ -48,7 +48,7 @@ class SmileyLoader(util.Singleton):
print('Smiley pack {} was not loaded. Error: {}'.format(pack_name, ex))
def get_smileys_path(self):
return util.curr_directory() + '/smileys/' + self._curr_pack + '/'
return util.curr_directory() + '/smileys/' + self._curr_pack + '/' if self._curr_pack is not None else None
def get_packs_list(self):
d = util.curr_directory() + '/smileys/'

View File

@ -1,2 +1,2 @@
SOURCES = main.py profile.py menu.py list_items.py loginscreen.py mainscreen.py plugins/plugin_super_class.py callbacks.py widgets.py avwidgets.py mainscreen_widgets.py
SOURCES = main.py profile.py menu.py list_items.py loginscreen.py mainscreen.py plugins/plugin_super_class.py callbacks.py widgets.py avwidgets.py mainscreen_widgets.py passwordscreen.py
TRANSLATIONS = translations/en_GB.ts translations/ru_RU.ts translations/fr_FR.ts

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@ import os
import time
import shutil
program_version = '0.2.3'
program_version = '0.2.5'
def log(data):
@ -31,7 +31,8 @@ def copy(src, dest):
def convert_time(t):
sec = int(t) - time.timezone
offset = time.timezone - time.daylight * 3600
sec = int(t) - offset
m, s = divmod(sec, 60)
h, m = divmod(m, 60)
d, h = divmod(h, 24)