diff --git a/README.md b/README.md index 659bd3e..090cc2a 100644 --- a/README.md +++ b/README.md @@ -2,29 +2,32 @@ Toxygen is simple [Tox](https://tox.chat/) client written on pure Python ### [How to install](/docs/install.md) +### [Contributing](/docs/contributing.md) + # Supported OS: - Windows - Linux ###Features - [x] 1v1 messages -- [x] Contact aliases +- [x] File transfers +- [x] Audio - [x] Chat history - [x] Name lookups (TOX DNS 4 support) - [x] Profile import/export +- [x] Inline images - [x] Message splitting - [x] Proxy support -- [x] File transfers - [x] Avatars - [x] Multiprofile - [x] Multilingual - [x] Sound notifications -- [x] Inline images -- [x] Audio +- [x] Contact aliases +- [x] Contact blocking +- [x] Typing notifications - [ ] Video - [ ] Save file encryption - [ ] File resuming -- [ ] Typing notifications - [ ] Changing nospam - [ ] Plugins support - [ ] Group chats diff --git a/src/callbacks.py b/src/callbacks.py index 5e813ba..7e97137 100644 --- a/src/callbacks.py +++ b/src/callbacks.py @@ -137,6 +137,10 @@ def friend_request(tox, public_key, message, message_size, user_data): if tox_id not in Settings.get_instance()['blocked']: invoke_in_main_thread(profile.process_friend_request, tox_id, message.decode('utf-8')) + +def friend_typing(tox, friend_number, typing, user_data): + invoke_in_main_thread(Profile.get_instance().friend_typing, friend_number, typing) + # ----------------------------------------------------------------------------------------------------------------- # Callbacks - file transfers # ----------------------------------------------------------------------------------------------------------------- @@ -253,6 +257,7 @@ def init_callbacks(tox, window, tray): tox.callback_friend_name(friend_name, 0) tox.callback_friend_status_message(friend_status_message, 0) tox.callback_friend_request(friend_request, 0) + tox.callback_friend_typing(friend_typing, 0) tox.callback_file_recv(tox_file_recv(window, tray), 0) tox.callback_file_recv_chunk(file_recv_chunk, 0) diff --git a/src/images/typing.png b/src/images/typing.png new file mode 100755 index 0000000..26ad69b Binary files /dev/null and b/src/images/typing.png differ diff --git a/src/mainscreen.py b/src/mainscreen.py index 0dc8b9c..9145bce 100644 --- a/src/mainscreen.py +++ b/src/mainscreen.py @@ -10,6 +10,8 @@ class MessageArea(QtGui.QPlainTextEdit): def __init__(self, parent, form): super(MessageArea, self).__init__(parent) self.parent = form + self.timer = QtCore.QTimer(self) + self.timer.timeout.connect(lambda: self.parent.profile.send_typing(False)) def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Return: @@ -21,6 +23,10 @@ class MessageArea(QtGui.QPlainTextEdit): elif event.key() == QtCore.Qt.Key_Up and not self.toPlainText(): self.appendPlainText(Profile.get_instance().get_last_message()) else: + self.parent.profile.send_typing(True) + if self.timer.isActive(): + self.timer.stop() + self.timer.start(5000) super(MessageArea, self).keyPressEvent(event) @@ -208,6 +214,13 @@ class MainWindow(QtGui.QMainWindow): self.callButton.setObjectName("callButton") self.callButton.clicked.connect(self.call) self.update_call_state('call') + self.typing = QtGui.QLabel(Form) + self.typing.setGeometry(QtCore.QRect(500, 40, 50, 30)) + pixmap = QtGui.QPixmap(QtCore.QSize(50, 30)) + pixmap.load(curr_directory() + '/images/typing.png') + self.typing.setScaledContents(False) + self.typing.setPixmap(pixmap.scaled(50, 30, QtCore.Qt.KeepAspectRatio)) + self.typing.setVisible(False) QtCore.QMetaObject.connectSlotsByName(Form) def setup_left_center(self, widget): diff --git a/src/profile.py b/src/profile.py index 4dd0eb7..488f054 100644 --- a/src/profile.py +++ b/src/profile.py @@ -394,6 +394,8 @@ class Profile(Contact, Singleton): self._screen.messageEdit.clear() return try: + self.send_typing(False) + self._screen.typing.setVisible(False) if value is not None: self._active_friend = value friend = self._friends[value] @@ -454,6 +456,20 @@ class Profile(Contact, Singleton): def is_active_online(self): return self._active_friend + 1 and self._friends[self._active_friend].status is not None + # ----------------------------------------------------------------------------------------------------------------- + # Typing notifications + # ----------------------------------------------------------------------------------------------------------------- + + def send_typing(self, typing): + if Settings.get_instance()['typing_notifications']: + friend = self._friends[self._active_friend] + if friend.status is not None: + self._tox.self_set_typing(friend.number, typing) + + def friend_typing(self, friend_number, typing): + if friend_number == self.get_active_number(): + self._screen.typing.setVisible(typing) + # ----------------------------------------------------------------------------------------------------------------- # Private messages # ----------------------------------------------------------------------------------------------------------------- diff --git a/src/settings.py b/src/settings.py index e1b6986..8de65c9 100644 --- a/src/settings.py +++ b/src/settings.py @@ -62,7 +62,7 @@ class Settings(Singleton, dict): 'show_online_friends': False, 'auto_accept_from_friends': [], 'friends_aliases': [], - 'typing_notifications': True, + 'typing_notifications': False, 'calls_sound': True, 'blocked': [] }