update
This commit is contained in:
parent
f62e28f5b4
commit
ea454e27a1
5 changed files with 93 additions and 60 deletions
46
README.md
46
README.md
|
@ -4,7 +4,7 @@ Toxygen is powerful cross-platform [Tox](https://tox.chat/) client written in pu
|
|||
|
||||
### [Install](/docs/install.md) - [Contribute](/docs/contributing.md) - [Plugins](/docs/plugins.md) - [Compile](/docs/compile.md) - [Contact](/docs/contact.md)
|
||||
|
||||
### Supported OS: Linux and Windows
|
||||
### Supported OS: Linux and Windows (only Linux is tested at the moment)
|
||||
|
||||
### Features:
|
||||
|
||||
|
@ -26,7 +26,7 @@ Toxygen is powerful cross-platform [Tox](https://tox.chat/) client written in pu
|
|||
- Faux offline file transfers
|
||||
- Inline images
|
||||
- Message splitting
|
||||
- Proxy support
|
||||
- Proxy support - runs over tor
|
||||
- Avatars
|
||||
- Multiprofile
|
||||
- Multilingual
|
||||
|
@ -44,17 +44,20 @@ Toxygen is powerful cross-platform [Tox](https://tox.chat/) client written in pu
|
|||
![Ubuntu](/docs/ubuntu.png)
|
||||
![Windows](/docs/windows.png)
|
||||
|
||||
Windows was working but is not currently being tested. AV was working
|
||||
but is not currently being tested: we're unsure of handling the AV devices
|
||||
from the commandline. We need to get a working echobot that supports SOCKS5;
|
||||
we were working on one in https://git.plastiras.org/emdee/toxygen_wrapper
|
||||
|
||||
## Forked
|
||||
|
||||
This hard-forked from the dead https://github.com/toxygen-project/toxygen
|
||||
```next_gen``` branch.
|
||||
|
||||
https://git.plastiras.org/emdee/toxygen_wrapper needs packaging
|
||||
is making a dependency. Just download it and copy the two directories
|
||||
```wrapper``` and ```wrapper_tests``` into ```toxygen/toxygen```.
|
||||
|
||||
See ToDo.md to the current ToDo list.
|
||||
|
||||
## Wechat
|
||||
|
||||
You can have a [weechat](https://github.com/weechat/qweechat)
|
||||
console so that you can have IRC and jabber in a window as well as Tox.
|
||||
There's a copy of qweechat in ```thirdparty/qweechat``` backported to
|
||||
|
@ -79,13 +82,36 @@ Weechat has a Jabber plugin to enable XMPP:
|
|||
```
|
||||
so you can have Tox, IRC and XMPP in the same application!
|
||||
|
||||
Work on Tox on this project is suspended until the
|
||||
[MultiDevice](https://git.plastiras.org/emdee/tox_profile/wiki/MultiDevice-Announcements-POC) problem is solved. Fork me!
|
||||
## Install
|
||||
|
||||
This will probably be ported to Qt6 using qtpy
|
||||
https://github.com/spyder-ide/qtpy .
|
||||
To install read the requirements.txt and look at the comments; there
|
||||
may be things that need installing by hand or decisions to be made
|
||||
on supported alternatives.
|
||||
|
||||
https://git.plastiras.org/emdee/toxygen_wrapper needs packaging
|
||||
on pypi as it is a dependency. Just download and install it from
|
||||
https://git.plastiras.org/emdee/toxygen_wrapper
|
||||
|
||||
This is being ported to Qt6 using qtpy https://github.com/spyder-ide/qtpy
|
||||
It should run on PyQt5, PyQt6 and may run on PySide2 and PySide6 - YMMV.
|
||||
You should be able to choose between them by setting the environment variable
|
||||
QT_API to one of: pyqt5 pyqt6 pyside2 pyside6.
|
||||
|
||||
To install it, look in the Makefile for the install target and type
|
||||
```
|
||||
make install
|
||||
```
|
||||
You should set the PIP_EXE_MSYS and PYTHON_EXE_MSYS variables and it does
|
||||
```
|
||||
${PIP_EXE_MSYS} --python ${PYTHON_EXE_MSYS} install \
|
||||
--target ${PREFIX}/lib/python${PYTHON_MINOR}/site-packages/ \
|
||||
--upgrade .
|
||||
```
|
||||
and installs into PREFIX which is usually /usr/local
|
||||
|
||||
Up-to-date code is on https://git.plastiras.org/emdee/toxygen
|
||||
|
||||
## MultiDevice
|
||||
|
||||
Work on this project is suspended until the
|
||||
[MultiDevice](https://git.plastiras.org/emdee/tox_profile/wiki/MultiDevice-Announcements-POC) problem is solved. Fork me!
|
||||
|
|
15
ToDo.md
15
ToDo.md
|
@ -4,14 +4,14 @@
|
|||
|
||||
1. There is an agravating bug where new messages are not put in the
|
||||
current window, and a messages waiting indicator appears. You have
|
||||
to focus out of the window and then back in the window.
|
||||
|
||||
to focus out of the window and then back in the window. this may be
|
||||
fixed already
|
||||
|
||||
2. The tray icon is flaky and has been disabled - look in app.py
|
||||
for bSHOW_TRAY
|
||||
|
||||
## Fix history
|
||||
|
||||
The code is in there but it's not working.
|
||||
|
||||
## Fix Audio
|
||||
|
||||
The code is in there but it's not working. It looks like audio input
|
||||
|
@ -25,7 +25,7 @@ The code is in there but it's not working. I may have broken it
|
|||
trying to wire up the ability to set the video device from the command
|
||||
line.
|
||||
|
||||
## Groups
|
||||
## NGC Groups
|
||||
|
||||
1. peer_id There has been a change of API on a field named
|
||||
```group.peer_id``` The code is broken in places because I have not
|
||||
|
@ -50,3 +50,8 @@ line.
|
|||
|
||||
2. https://git.plastiras.org/emdee/toxygen_wrapper needs packaging
|
||||
and making a dependency.
|
||||
|
||||
## Standards
|
||||
|
||||
There's a standard for Tox clients that this has not been tested against:
|
||||
https://tox.gitbooks.io/tox-client-standard/content/general_requirements/general_requirements.html
|
||||
|
|
|
@ -17,9 +17,9 @@ classifiers =
|
|||
|
||||
[options]
|
||||
zip_safe = false
|
||||
python_requires = ~=3.6
|
||||
python_requires = ~=3.7
|
||||
include_package_data =
|
||||
"*" = ["*.ui", "*.txt"]
|
||||
"*" = ["*.ui", "*.txt", "*.png", "*.ico", "*.gif", "*.wav"]
|
||||
|
||||
[options.entry_points]
|
||||
console_scripts =
|
||||
|
|
|
@ -37,17 +37,17 @@ __version__ = '1.0.0' # was 0.5.0+
|
|||
|
||||
sleep = time.sleep
|
||||
|
||||
os.environ['QT_API'] = 'pyqt5'
|
||||
os.environ['QT_API'] = os.environ.get('QT_API', 'pyqt5')
|
||||
|
||||
def reset():
|
||||
def reset() -> None:
|
||||
Settings.reset_auto_profile()
|
||||
|
||||
def clean():
|
||||
def clean() -> None:
|
||||
"""Removes libs folder"""
|
||||
directory = util.get_libs_directory()
|
||||
util.remove(directory)
|
||||
|
||||
def print_toxygen_version():
|
||||
def print_toxygen_version() -> None:
|
||||
print('toxygen ' + __version__)
|
||||
|
||||
def setup_default_audio():
|
||||
|
@ -291,7 +291,7 @@ lKEEP_SETTINGS = ['uri',
|
|||
|
||||
class A(): pass
|
||||
|
||||
def main(lArgs=None):
|
||||
def main(lArgs=None) -> int:
|
||||
global oPYA
|
||||
from argparse import Namespace
|
||||
if lArgs is None:
|
||||
|
|
|
@ -87,7 +87,7 @@ IDLE_PERIOD = 0.10
|
|||
iNODES=8
|
||||
bSHOW_TRAY=False
|
||||
|
||||
def setup_logging(oArgs):
|
||||
def setup_logging(oArgs) -> None:
|
||||
global LOG
|
||||
logging._defaultFormatter = logging.Formatter(datefmt='%m-%d %H:%M:%S',
|
||||
fmt='%(levelname)s:%(name)s %(message)s')
|
||||
|
@ -185,14 +185,14 @@ class App:
|
|||
|
||||
# Public methods
|
||||
|
||||
def set_trace(self):
|
||||
def set_trace(self) -> None:
|
||||
"""unused"""
|
||||
LOG.debug('pdb.set_trace ')
|
||||
sys.stdin = sys.__stdin__
|
||||
sys.stdout = sys.__stdout__
|
||||
import pdb; pdb.set_trace()
|
||||
|
||||
def ten(self, i=0):
|
||||
def ten(self, i=0) -> None:
|
||||
"""unused"""
|
||||
global iI
|
||||
iI += 1
|
||||
|
@ -204,7 +204,7 @@ class App:
|
|||
#sys.stderr.write(f"ten '+str(iI)+' {i}"+' '+repr(LOG) +'\n')
|
||||
#LOG.debug('ten '+str(iI))
|
||||
|
||||
def iMain(self):
|
||||
def iMain(self) -> int:
|
||||
"""
|
||||
Main function of app. loads login screen if needed and starts main screen
|
||||
"""
|
||||
|
@ -257,7 +257,7 @@ class App:
|
|||
|
||||
# App executing
|
||||
|
||||
def _execute_app(self):
|
||||
def _execute_app(self) -> None:
|
||||
LOG.debug("_execute_app")
|
||||
|
||||
while True:
|
||||
|
@ -268,7 +268,7 @@ class App:
|
|||
else:
|
||||
break
|
||||
|
||||
def quit(self, retval=0):
|
||||
def quit(self, retval=0) -> None:
|
||||
LOG.debug("quit")
|
||||
self._stop_app()
|
||||
|
||||
|
@ -293,7 +293,7 @@ class App:
|
|||
|
||||
raise SystemExit(retval)
|
||||
|
||||
def _stop_app(self):
|
||||
def _stop_app(self) -> None:
|
||||
LOG.debug("_stop_app")
|
||||
self._save_profile()
|
||||
#? self._history.save_history()
|
||||
|
@ -321,7 +321,7 @@ class App:
|
|||
|
||||
# App loading
|
||||
|
||||
def _load_base_style(self):
|
||||
def _load_base_style(self) -> None:
|
||||
if self._args.theme in ['', 'default']: return
|
||||
|
||||
if qdarkstyle:
|
||||
|
@ -341,7 +341,7 @@ class App:
|
|||
style += '\n' +sSTYLE
|
||||
self._app.setStyleSheet(style)
|
||||
|
||||
def _load_app_styles(self):
|
||||
def _load_app_styles(self) -> None:
|
||||
LOG.debug(f"_load_app_styles {list(settings.built_in_themes().keys())!r}")
|
||||
# application color scheme
|
||||
if self._settings['theme'] in ['', 'default']: return
|
||||
|
@ -371,7 +371,7 @@ class App:
|
|||
LOG.info('_load_app_styles: loaded theme ' +self._args.theme)
|
||||
break
|
||||
|
||||
def _load_login_screen_translations(self):
|
||||
def _load_login_screen_translations(self) -> None:
|
||||
LOG.debug("_load_login_screen_translations")
|
||||
current_language, supported_languages = self._get_languages()
|
||||
if current_language not in supported_languages:
|
||||
|
@ -382,13 +382,13 @@ class App:
|
|||
self._app.installTranslator(translator)
|
||||
self._app.translator = translator
|
||||
|
||||
def _load_icon(self):
|
||||
def _load_icon(self) -> None:
|
||||
LOG.debug("_load_icon")
|
||||
icon_file = os.path.join(util.get_images_directory(), 'icon.png')
|
||||
self._app.setWindowIcon(QtGui.QIcon(icon_file))
|
||||
|
||||
@staticmethod
|
||||
def _get_languages():
|
||||
def _get_languages() -> tuple:
|
||||
LOG.debug("_get_languages")
|
||||
current_locale = QtCore.QLocale()
|
||||
curr_language = current_locale.languageToString(current_locale.language())
|
||||
|
@ -396,7 +396,7 @@ class App:
|
|||
|
||||
return curr_language, supported_languages
|
||||
|
||||
def _load_app_translations(self):
|
||||
def _load_app_translations(self) -> None:
|
||||
LOG.debug("_load_app_translations")
|
||||
lang = settings.supported_languages()[self._settings['language']]
|
||||
translator = QtCore.QTranslator()
|
||||
|
@ -404,7 +404,7 @@ class App:
|
|||
self._app.installTranslator(translator)
|
||||
self._app.translator = translator
|
||||
|
||||
def _select_and_load_profile(self):
|
||||
def _select_and_load_profile(self) -> bool:
|
||||
LOG.debug("_select_and_load_profile: " +repr(self._path))
|
||||
|
||||
if self._path is not None:
|
||||
|
@ -468,7 +468,7 @@ class App:
|
|||
|
||||
# Threads
|
||||
|
||||
def _start_threads(self, initial_start=True):
|
||||
def _start_threads(self, initial_start=True) -> None:
|
||||
LOG.debug(f"_start_threads before: {threading.enumerate()!r}")
|
||||
# init thread
|
||||
self._init = threads.InitThread(self._tox,
|
||||
|
@ -491,7 +491,7 @@ class App:
|
|||
threads.start_file_transfer_thread()
|
||||
LOG.debug(f"_start_threads after: {[t.name for t in threading.enumerate()]!r}")
|
||||
|
||||
def _stop_threads(self, is_app_closing=True):
|
||||
def _stop_threads(self, is_app_closing=True) -> None:
|
||||
LOG.debug("_stop_threads")
|
||||
self._init.stop_thread(1.0)
|
||||
|
||||
|
@ -501,7 +501,7 @@ class App:
|
|||
if is_app_closing:
|
||||
threads.stop_file_transfer_thread()
|
||||
|
||||
def iterate(self, n=100):
|
||||
def iterate(self, n=100) -> None:
|
||||
interval = self._tox.iteration_interval()
|
||||
for i in range(n):
|
||||
self._tox.iterate()
|
||||
|
@ -520,7 +520,7 @@ class App:
|
|||
self._app.exec_()
|
||||
return ls.result
|
||||
|
||||
def _load_existing_profile(self, profile_path):
|
||||
def _load_existing_profile(self, profile_path) -> None:
|
||||
LOG.info("_load_existing_profile " +repr(profile_path))
|
||||
assert os.path.exists(profile_path), profile_path
|
||||
self._profile_manager = ProfileManager(self._toxes, profile_path)
|
||||
|
@ -536,7 +536,7 @@ class App:
|
|||
self._tox = self._create_tox(data, self._settings)
|
||||
LOG.debug("created _tox")
|
||||
|
||||
def _create_new_profile(self, profile_name):
|
||||
def _create_new_profile(self, profile_name) -> bool:
|
||||
LOG.info("_create_new_profile " + profile_name)
|
||||
result = self._get_create_profile_screen_result()
|
||||
if result is None:
|
||||
|
@ -587,7 +587,7 @@ class App:
|
|||
|
||||
return cps.result
|
||||
|
||||
def _save_profile(self, data=None):
|
||||
def _save_profile(self, data=None) -> None:
|
||||
LOG.debug("_save_profile")
|
||||
data = data or self._tox.get_savedata()
|
||||
self._profile_manager.save_profile(data)
|
||||
|
@ -608,7 +608,7 @@ class App:
|
|||
self._force_exit(0)
|
||||
return None
|
||||
|
||||
def _reset(self):
|
||||
def _reset(self) -> None:
|
||||
LOG.debug("_reset")
|
||||
"""
|
||||
Create new tox instance (new network settings)
|
||||
|
@ -648,7 +648,7 @@ class App:
|
|||
text = util_ui.tr('Error:') + str(e)
|
||||
util_ui.message_box(text, title)
|
||||
|
||||
def _create_dependencies(self):
|
||||
def _create_dependencies(self) -> None:
|
||||
LOG.info(f"_create_dependencies toxygen version {self._version}")
|
||||
if hasattr(self._args, 'update') and self._args.update:
|
||||
self._backup_service = BackupService(self._settings,
|
||||
|
@ -794,11 +794,11 @@ class App:
|
|||
self._tox = retval
|
||||
return retval
|
||||
|
||||
def _force_exit(self, retval=0):
|
||||
def _force_exit(self, retval=0) -> None:
|
||||
LOG.debug("_force_exit")
|
||||
sys.exit(0)
|
||||
|
||||
def _init_callbacks(self, ms=None):
|
||||
def _init_callbacks(self, ms=None) -> None:
|
||||
LOG.debug("_init_callbacks")
|
||||
# this will block if you are not connected
|
||||
callbacks.init_callbacks(self._tox, self._profile, self._settings,
|
||||
|
@ -809,21 +809,21 @@ class App:
|
|||
self._messenger, self._groups_service,
|
||||
self._contacts_provider, self._ms)
|
||||
|
||||
def _init_profile(self):
|
||||
def _init_profile(self) -> None:
|
||||
LOG.debug("_init_profile")
|
||||
if not self._profile.has_avatar():
|
||||
self._profile.reset_avatar(self._settings['identicons'])
|
||||
|
||||
def _kill_toxav(self):
|
||||
def _kill_toxav(self) -> None:
|
||||
# LOG_debug("_kill_toxav")
|
||||
self._calls_manager.set_toxav(None)
|
||||
self._tox.AV.kill()
|
||||
|
||||
def _kill_tox(self):
|
||||
def _kill_tox(self) -> None:
|
||||
# LOG.debug("_kill_tox")
|
||||
self._tox.kill()
|
||||
|
||||
def loop(self, n):
|
||||
def loop(self, n) -> None:
|
||||
"""
|
||||
Im guessings - there are 3 sleeps - time, tox, and Qt
|
||||
"""
|
||||
|
@ -834,11 +834,11 @@ class App:
|
|||
# NO QtCore.QCoreApplication.processEvents()
|
||||
sleep(interval / 1000.0)
|
||||
|
||||
def _test_tox(self):
|
||||
def _test_tox(self) -> None:
|
||||
self.test_net(iMax=8)
|
||||
self._ms.log_console()
|
||||
|
||||
def test_net(self, lElts=None, oThread=None, iMax=4):
|
||||
def test_net(self, lElts=None, oThread=None, iMax=4) -> None:
|
||||
|
||||
# bootstrap
|
||||
LOG.debug('test_net: Calling generate_nodes: udp')
|
||||
|
@ -906,7 +906,7 @@ class App:
|
|||
LOG.trace(f"Connected status #{i}: {status!r}")
|
||||
self.loop(2)
|
||||
|
||||
def _test_env(self):
|
||||
def _test_env(self) -> None:
|
||||
_settings = self._settings
|
||||
if 'proxy_type' not in _settings or _settings['proxy_type'] == 0 or \
|
||||
not _settings['proxy_host'] or not _settings['proxy_port']:
|
||||
|
@ -929,7 +929,7 @@ class App:
|
|||
# LOG.debug(f"test_env {len(lElts)}")
|
||||
return env
|
||||
|
||||
def _test_bootstrap(self, lElts=None):
|
||||
def _test_bootstrap(self, lElts=None) -> None:
|
||||
if lElts is None:
|
||||
lElts = self._settings['current_nodes_udp']
|
||||
LOG.debug(f"_test_bootstrap #Elts={len(lElts)}")
|
||||
|
@ -939,14 +939,14 @@ class App:
|
|||
ts.bootstrap_udp(lElts[:iNODES], [self._tox])
|
||||
LOG.info("Connected status: " +repr(self._tox.self_get_connection_status()))
|
||||
|
||||
def _test_relays(self, lElts=None):
|
||||
def _test_relays(self, lElts=None) -> None:
|
||||
if lElts is None:
|
||||
lElts = self._settings['current_nodes_tcp']
|
||||
shuffle(lElts)
|
||||
LOG.debug(f"_test_relays {len(lElts)}")
|
||||
ts.bootstrap_tcp(lElts[:iNODES], [self._tox])
|
||||
|
||||
def _test_nmap(self, lElts=None):
|
||||
def _test_nmap(self, lElts=None) -> None:
|
||||
LOG.debug("_test_nmap")
|
||||
if not self._tox: return
|
||||
title = 'Extended Test Suite'
|
||||
|
@ -980,7 +980,7 @@ class App:
|
|||
# LOG.info("Connected status: " +repr(self._tox.self_get_connection_status()))
|
||||
self._ms.log_console()
|
||||
|
||||
def _test_main(self):
|
||||
def _test_main(self) -> None:
|
||||
from toxygen_tox_wrapper.tox_wrapper.tests.tests_wrapper import main as tests_main
|
||||
LOG.debug("_test_main")
|
||||
if not self._tox: return
|
||||
|
@ -1017,11 +1017,13 @@ class GEventProcessing:
|
|||
self._timer = QTimer()
|
||||
self._timer.timeout.connect(self.process_events)
|
||||
self._timer.start(0)
|
||||
def __enter__(self):
|
||||
def __enter__(self) -> None:
|
||||
pass
|
||||
def __exit__(self, *exc_info):
|
||||
|
||||
def __exit__(self, *exc_info) -> None:
|
||||
self._timer.stop()
|
||||
def process_events(self, idle_period=None):
|
||||
|
||||
def process_events(self, idle_period=None) -> None:
|
||||
if idle_period is None:
|
||||
idle_period = self._idle_period
|
||||
# Cooperative yield, allow gevent to monitor file handles via libevent
|
||||
|
|
Loading…
Reference in a new issue