From 3602b3433e145d133dff5f0dfe42ef44508e4656 Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Tue, 12 Jul 2016 17:53:38 +0300 Subject: [PATCH 01/10] contact.py fixes and right click menu update --- toxygen/contact.py | 73 +++++++++++++++++++++------ toxygen/friend.py | 113 ------------------------------------------ toxygen/mainscreen.py | 28 ++++++++++- toxygen/profile.py | 19 +++++-- toxygen/tox.py | 3 +- 5 files changed, 100 insertions(+), 136 deletions(-) diff --git a/toxygen/contact.py b/toxygen/contact.py index 5d78c63..8673bab 100644 --- a/toxygen/contact.py +++ b/toxygen/contact.py @@ -5,6 +5,8 @@ except ImportError: import basecontact from messages import * from history import * +import file_transfers as ft +import util class Contact(basecontact.BaseContact): @@ -25,6 +27,7 @@ class Contact(basecontact.BaseContact): self._message_getter = message_getter self._new_messages = False self._visible = True + self._alias = False self._number = number self._corr = [] self._unsaved_messages = 0 @@ -57,11 +60,8 @@ class Contact(basecontact.BaseContact): Get data to save in db :return: list of unsaved messages or [] """ - if hasattr(self, '_message_getter'): - del self._message_getter messages = list(filter(lambda x: x.get_type() <= 1, self._corr)) - return list( - map(lambda x: x.get_data(), list(messages[-self._unsaved_messages:]))) if self._unsaved_messages else [] + return list(map(lambda x: x.get_data(), messages[-self._unsaved_messages:])) if self._unsaved_messages else [] def get_corr(self): return self._corr[:] @@ -81,24 +81,50 @@ class Contact(basecontact.BaseContact): else: return '' - def clear_corr(self): + def get_unsent_messages(self): + """ + :return list of unsent messages + """ + messages = filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr) + return list(messages) + + def get_unsent_messages_for_saving(self): + """ + :return list of unsent messages for saving + """ + messages = filter(lambda x: x.get_type() <= 1 and x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr) + return list(map(lambda x: x.get_data(), messages)) + + def delete_message(self, time): + elem = list(filter(lambda x: type(x) is TextMessage and x.get_data()[2] == time, self._corr))[0] + tmp = list(filter(lambda x: x.get_type() <= 1, self._corr)) + if elem in tmp[-self._unsaved_messages:]: + self._unsaved_messages -= 1 + self._corr.remove(elem) + + def mark_as_sent(self): + try: + message = list(filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr))[0] + message.mark_as_sent() + except Exception as ex: + util.log('Mark as sent ex: ' + str(ex)) + + def clear_corr(self, save_unsent=False): """ Clear messages list """ if hasattr(self, '_message_getter'): del self._message_getter # don't delete data about active file transfer - self._corr = list(filter(lambda x: x.get_type() in (2, 3) and (x.get_status() >= 2 or x.get_status() is None), - self._corr)) - self._unsaved_messages = 0 - - def delete_old_messages(self): - old = filter(lambda x: x.get_type() in (2, 3) and (x.get_status() >= 2 or x.get_status() is None), - self._corr[:-SAVE_MESSAGES]) - old = list(old) - l = max(len(self._corr) - SAVE_MESSAGES, 0) - len(old) - self._unsaved_messages -= l - self._corr = old + self._corr[-SAVE_MESSAGES:] + if not save_unsent: + self._corr = list(filter(lambda x: x.get_type() in (2, 3) and + x.get_status() in ft.ACTIVE_FILE_TRANSFERS, self._corr)) + self._unsaved_messages = 0 + else: + self._corr = list(filter(lambda x: (x.get_type() in (2, 3) and x.get_status() in ft.ACTIVE_FILE_TRANSFERS) + or (x.get_type() <= 1 and x.get_owner() == MESSAGE_OWNER['NOT_SENT']), + self._corr)) + self._unsaved_messages = len(self.get_unsent_messages()) def get_curr_text(self): return self._curr_text @@ -161,3 +187,18 @@ class Contact(basecontact.BaseContact): self._number = value number = property(get_number, set_number) + + # ----------------------------------------------------------------------------------------------------------------- + # Alias support + # ----------------------------------------------------------------------------------------------------------------- + + def set_name(self, value): + """ + Set new name or ignore if alias exists + :param value: new name + """ + if not self._alias: + super(Contact, self).set_name(value) + + def set_alias(self, alias): + self._alias = bool(alias) diff --git a/toxygen/friend.py b/toxygen/friend.py index 0045dcc..e9a5657 100644 --- a/toxygen/friend.py +++ b/toxygen/friend.py @@ -1,8 +1,5 @@ import contact from messages import * -from history import * -import util -import file_transfers as ft class Friend(contact.Contact): @@ -15,7 +12,6 @@ class Friend(contact.Contact): :param number: number of friend. """ super(Friend, self).__init__(*args) - self._alias = False self._receipts = 0 def __del__(self): @@ -38,100 +34,6 @@ class Friend(contact.Contact): self._receipts -= 1 self.mark_as_sent() - def load_corr(self, first_time=True): - """ - :param first_time: friend became active, load first part of messages - """ - if (first_time and self._history_loaded) or (not hasattr(self, '_message_getter')): - return - data = list(self._message_getter.get(PAGE_SIZE)) - if data is not None and len(data): - data.reverse() - else: - return - data = list(map(lambda tupl: TextMessage(*tupl), data)) - self._corr = data + self._corr - self._history_loaded = True - - def get_corr_for_saving(self): - """ - Get data to save in db - :return: list of unsaved messages or [] - """ - messages = list(filter(lambda x: x.get_type() <= 1, self._corr)) - return list(map(lambda x: x.get_data(), messages[-self._unsaved_messages:])) if self._unsaved_messages else [] - - def get_corr(self): - return self._corr[:] - - def append_message(self, message): - """ - :param message: text or file transfer message - """ - self._corr.append(message) - if message.get_type() <= 1: - self._unsaved_messages += 1 - - def get_last_message_text(self): - messages = list(filter(lambda x: x.get_type() <= 1 and x.get_owner() != MESSAGE_OWNER['FRIEND'], self._corr)) - if messages: - return messages[-1].get_data()[0] - else: - return '' - - def get_unsent_messages(self): - """ - :return list of unsent messages - """ - messages = filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr) - return list(messages) - - def get_unsent_messages_for_saving(self): - """ - :return list of unsent messages for saving - """ - messages = filter(lambda x: x.get_type() <= 1 and x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr) - return list(map(lambda x: x.get_data(), messages)) - - def delete_message(self, time): - elem = list(filter(lambda x: type(x) is TextMessage and x.get_data()[2] == time, self._corr))[0] - tmp = list(filter(lambda x: x.get_type() <= 1, self._corr)) - if elem in tmp[-self._unsaved_messages:]: - self._unsaved_messages -= 1 - self._corr.remove(elem) - - def mark_as_sent(self): - try: - message = list(filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr))[0] - message.mark_as_sent() - except Exception as ex: - util.log('Mark as sent ex: ' + str(ex)) - - def clear_corr(self, save_unsent=False): - """ - Clear messages list - """ - if hasattr(self, '_message_getter'): - del self._message_getter - # don't delete data about active file transfer - if not save_unsent: - self._corr = list(filter(lambda x: x.get_type() in (2, 3) and - x.get_status() in ft.ACTIVE_FILE_TRANSFERS, self._corr)) - self._unsaved_messages = 0 - else: - self._corr = list(filter(lambda x: (x.get_type() in (2, 3) and x.get_status() in ft.ACTIVE_FILE_TRANSFERS) - or (x.get_type() <= 1 and x.get_owner() == MESSAGE_OWNER['NOT_SENT']), - self._corr)) - self._unsaved_messages = len(self.get_unsent_messages()) - - def get_curr_text(self): - return self._curr_text - - def set_curr_text(self, value): - self._curr_text = value - - curr_text = property(get_curr_text, set_curr_text) - # ----------------------------------------------------------------------------------------------------------------- # File transfers support # ----------------------------------------------------------------------------------------------------------------- @@ -160,18 +62,3 @@ class Friend(contact.Contact): def delete_one_unsent_file(self, time): self._corr = list(filter(lambda x: not (type(x) is UnsentFile and x.get_data()[2] == time), self._corr)) - - # ----------------------------------------------------------------------------------------------------------------- - # Alias support - # ----------------------------------------------------------------------------------------------------------------- - - def set_name(self, value): - """ - Set new name or ignore if alias exists - :param value: new name - """ - if not self._alias: - super(Friend, self).set_name(value) - - def set_alias(self, alias): - self._alias = bool(alias) diff --git a/toxygen/mainscreen.py b/toxygen/mainscreen.py index 5d00ba7..98ea01c 100644 --- a/toxygen/mainscreen.py +++ b/toxygen/mainscreen.py @@ -559,6 +559,14 @@ class MainWindow(QtGui.QMainWindow): if item is not None: self.listMenu = QtGui.QMenu() if type(friend) is Friend: # TODO: add `invite to gc` submenu + arr = Profile.get_instance().get_all_gc() + if arr: + gc_menu = self.listMenu.addMenu(QtGui.QApplication.translate("MainWindow", 'Invite to group chat', None, QtGui.QApplication.UnicodeUTF8)) + for gc in arr: + item = gc.menu.addAction(gc_menu.name) + self.connect(item, QtCore.SIGNAL("triggered()"), + lambda: Profile.get_instance().invite_friend(gc.number), friend.number) + 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_menu = self.listMenu.addMenu(QtGui.QApplication.translate("MainWindow", 'Copy', None, QtGui.QApplication.UnicodeUTF8)) @@ -583,7 +591,23 @@ class MainWindow(QtGui.QMainWindow): 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)) else: - pass # TODO: add menu for gc + 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", 'Topic', None, QtGui.QApplication.UnicodeUTF8)) + copy_key_item = copy_menu.addAction( + QtGui.QApplication.translate("MainWindow", 'Public key', None, QtGui.QApplication.UnicodeUTF8)) + leave_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Leave group', None, QtGui.QApplication.UnicodeUTF8)) + set_alias_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Set alias', None, QtGui.QApplication.UnicodeUTF8)) + notes_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Notes', None, QtGui.QApplication.UnicodeUTF8)) + 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)) + self.connect(copy_key_item, QtCore.SIGNAL("triggered()"), lambda: self.copy_friend_key(num)) + self.connect(leave_item, QtCore.SIGNAL("triggered()"), lambda: Profile.get_instance().leave_group(num)) + self.connect(set_alias_item, QtCore.SIGNAL("triggered()"), lambda: self.set_alias(num)) parent_position = self.friends_list.mapToGlobal(QtCore.QPoint(0, 0)) self.listMenu.move(parent_position + pos) self.listMenu.show() @@ -607,7 +631,7 @@ class MainWindow(QtGui.QMainWindow): self.profile.set_alias(num) def remove_friend(self, num): - self.profile.delete_friend(num) + self.profile.delete_friend_or_gc(num) def copy_friend_key(self, num): tox_id = self.profile.friend_public_key(num) diff --git a/toxygen/profile.py b/toxygen/profile.py index d2d03a3..4842811 100644 --- a/toxygen/profile.py +++ b/toxygen/profile.py @@ -674,10 +674,10 @@ class Profile(basecontact.BaseContact, Singleton): def friend_public_key(self, num): return self._friends_and_gc[num].tox_id - def delete_friend(self, num): + def delete_friend_or_gc(self, num): """ - Removes friend from contact list - :param num: number of friend in list + Removes friend or gc from contact list + :param num: number of friend or gc in list """ friend = self._friends_and_gc[num] settings = Settings.get_instance() @@ -732,7 +732,7 @@ class Profile(basecontact.BaseContact, Singleton): settings.save() try: num = self._tox.friend_by_public_key(tox_id) - self.delete_friend(num) + self.delete_friend_or_gc(num) data = self._tox.get_savedata() ProfileHelper.get_instance().save_profile(data) except: # not in friend list @@ -1228,6 +1228,9 @@ class Profile(basecontact.BaseContact, Singleton): # Group chats support # ----------------------------------------------------------------------------------------------------------------- + def get_all_gc(self): + return list(filter(lambda x: type(x) is GroupChat, self._friends_and_gc)) + def add_gc(self, num): tox_id = self._tox.group_get_chat_id(num) name = self._tox.group_get_name(num) @@ -1278,6 +1281,14 @@ class Profile(basecontact.BaseContact, Singleton): except Exception as ex: # something is wrong log('Accept group chat invite failed! ' + str(ex)) + def invite_friend(self, group_number, friend_number): + self._tox.group_invite_friend(group_number, friend_number) + + def leave_group(self, num, message=None): + number = self._friends_and_gc[num].number + self._tox.group_leave(number, message) + self.delete_friend_or_gc(num) + def tox_factory(data=None, settings=None): """ diff --git a/toxygen/tox.py b/toxygen/tox.py index 5f55628..f33b7df 100644 --- a/toxygen/tox.py +++ b/toxygen/tox.py @@ -1607,7 +1607,8 @@ class Tox: """ error = c_int() - result = Tox.libtoxcore.tox_group_leave(self._tox_pointer, groupnumber, message, len(message), byref(error)) + result = Tox.libtoxcore.tox_group_leave(self._tox_pointer, groupnumber, message, + len(message) if message is not None else 0, byref(error)) return result # ----------------------------------------------------------------------------------------------------------------- From bb4e80ca095ec146a587846ea204e2bc39668141 Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Tue, 12 Jul 2016 22:53:02 +0300 Subject: [PATCH 02/10] fixes, gc loading on start --- toxygen/contact.py | 8 ++++++ toxygen/mainscreen.py | 6 ++-- toxygen/profile.py | 64 +++++++++++++++++++++++++++++-------------- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/toxygen/contact.py b/toxygen/contact.py index 8673bab..03fad92 100644 --- a/toxygen/contact.py +++ b/toxygen/contact.py @@ -102,6 +102,14 @@ class Contact(basecontact.BaseContact): self._unsaved_messages -= 1 self._corr.remove(elem) + def delete_old_messages(self): + old = filter(lambda x: x.get_type() in (2, 3) and (x.get_status() >= 2 or x.get_status() is None), + self._corr[:-SAVE_MESSAGES]) + old = list(old) + l = max(len(self._corr) - SAVE_MESSAGES, 0) - len(old) + self._unsaved_messages -= l + self._corr = old + self._corr[-SAVE_MESSAGES:] + def mark_as_sent(self): try: message = list(filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr))[0] diff --git a/toxygen/mainscreen.py b/toxygen/mainscreen.py index 98ea01c..c6383f4 100644 --- a/toxygen/mainscreen.py +++ b/toxygen/mainscreen.py @@ -558,14 +558,14 @@ class MainWindow(QtGui.QMainWindow): auto = QtGui.QApplication.translate("MainWindow", 'Disallow auto accept', None, QtGui.QApplication.UnicodeUTF8) if allowed else QtGui.QApplication.translate("MainWindow", 'Allow auto accept', None, QtGui.QApplication.UnicodeUTF8) if item is not None: self.listMenu = QtGui.QMenu() - if type(friend) is Friend: # TODO: add `invite to gc` submenu + if type(friend) is Friend: arr = Profile.get_instance().get_all_gc() if arr: gc_menu = self.listMenu.addMenu(QtGui.QApplication.translate("MainWindow", 'Invite to group chat', None, QtGui.QApplication.UnicodeUTF8)) for gc in arr: - item = gc.menu.addAction(gc_menu.name) + item = gc_menu.addAction(gc.name) self.connect(item, QtCore.SIGNAL("triggered()"), - lambda: Profile.get_instance().invite_friend(gc.number), friend.number) + lambda: Profile.get_instance().invite_friend(gc.number, friend.number)) 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)) diff --git a/toxygen/profile.py b/toxygen/profile.py index 4842811..00431e2 100644 --- a/toxygen/profile.py +++ b/toxygen/profile.py @@ -64,7 +64,24 @@ class Profile(basecontact.BaseContact, Singleton): friend = Friend(i, message_getter, name, status_message, item, tox_id) friend.set_alias(alias) self._friends_and_gc.append(friend) - # TODO: list of gc + + l = self._tox.group_get_number_groups() + for i in range(l): # creates list of group chats + tox_id = tox.group_get_chat_id(i) + try: + alias = list(filter(lambda x: x[0] == tox_id, aliases))[0][1] + except: + alias = '' + item = self.create_friend_item() + name = alias or tox.group_get_name(i) or tox_id + status_message = tox.group_get_topic(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) + gc = GroupChat(self._tox, i, message_getter, name, status_message, item, tox_id) + gc.set_alias(alias) + self._friends_and_gc.append(gc) + self.filtration(self._show_online) # ----------------------------------------------------------------------------------------------------------------- @@ -394,24 +411,27 @@ class Profile(basecontact.BaseContact, Singleton): :param is_group: is group chat message or not :param peer_id: if gc - peer id """ + t = time.time() + if num == self.get_active_number() and is_group != self.is_active_a_friend(): # add message to list - t = time.time() - self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type) - self._messages.scrollToBottom() - self._friends_and_gc[self._active_friend_or_gc].append_message( - TextMessage(message, MESSAGE_OWNER['FRIEND'], t, message_type)) - else: - if is_group: - friend_or_gc = self.get_gc_by_number(num) - friend_or_gc.append_message(GroupChatTextMessage(self._tox.group_peer_get_name(num, peer_id), - message, MESSAGE_OWNER['FRIEND'], - time.time(), message_type)) + if not is_group: + self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type) else: - friend_or_gc = self.get_friend_by_number(num) - friend_or_gc.inc_messages() - friend_or_gc.append_message(TextMessage(message, MESSAGE_OWNER['FRIEND'], time.time(), message_type)) - if not friend_or_gc.visibility: - self.update_filtration() + self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type, True, + self._tox.group_peer_get_name(num, peer_id)) + self._messages.scrollToBottom() + if is_group: + friend_or_gc = self.get_gc_by_number(num) + friend_or_gc.append_message(GroupChatTextMessage(self._tox.group_peer_get_name(num, peer_id), + message, MESSAGE_OWNER['FRIEND'], + time.time(), message_type)) + else: + friend_or_gc = self.get_friend_by_number(num) + friend_or_gc.inc_messages() + friend_or_gc.append_message(TextMessage(message, MESSAGE_OWNER['FRIEND'], time.time(), message_type)) + + if not friend_or_gc.visibility: + self.update_filtration() def send_message(self, text, number=None, is_gc=False): """ @@ -674,10 +694,11 @@ class Profile(basecontact.BaseContact, Singleton): def friend_public_key(self, num): return self._friends_and_gc[num].tox_id - def delete_friend_or_gc(self, num): + def delete_friend_or_gc(self, num, is_gc=False): """ Removes friend or gc from contact list :param num: number of friend or gc in list + :param is_gc: is a group chat """ friend = self._friends_and_gc[num] settings = Settings.get_instance() @@ -692,7 +713,8 @@ class Profile(basecontact.BaseContact, Singleton): self.clear_history(num) if self._history.friend_exists_in_db(friend.tox_id): self._history.delete_friend_from_db(friend.tox_id) - self._tox.friend_delete(friend.number) + if not is_gc: + self._tox.friend_delete(friend.number) del self._friends_and_gc[num] self._screen.friends_list.takeItem(num) if num == self._active_friend_or_gc: # active friend was deleted @@ -1155,6 +1177,8 @@ class Profile(basecontact.BaseContact, Singleton): def call_click(self, audio=True, video=False): """User clicked audio button in main window""" + if not self.is_active_a_friend(): + return num = self.get_active_number() if num not in self._call and self.is_active_online(): # start call self._call(num, audio, video) @@ -1287,7 +1311,7 @@ class Profile(basecontact.BaseContact, Singleton): def leave_group(self, num, message=None): number = self._friends_and_gc[num].number self._tox.group_leave(number, message) - self.delete_friend_or_gc(num) + self.delete_friend_or_gc(num, False) def tox_factory(data=None, settings=None): From 8a53fc87279ff3d19e0df9b614fd3055261d0825 Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Tue, 12 Jul 2016 23:31:32 +0300 Subject: [PATCH 03/10] menu update + group leaving --- toxygen/mainscreen.py | 20 +++++++++----------- toxygen/profile.py | 13 +++++++------ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/toxygen/mainscreen.py b/toxygen/mainscreen.py index c6383f4..b828907 100644 --- a/toxygen/mainscreen.py +++ b/toxygen/mainscreen.py @@ -582,14 +582,8 @@ class MainWindow(QtGui.QMainWindow): if len(submenu): plug = self.listMenu.addMenu(QtGui.QApplication.translate("MainWindow", 'Plugins', None, QtGui.QApplication.UnicodeUTF8)) plug.addActions(submenu) - self.connect(set_alias_item, QtCore.SIGNAL("triggered()"), lambda: self.set_alias(num)) self.connect(remove_item, QtCore.SIGNAL("triggered()"), lambda: self.remove_friend(num)) - self.connect(copy_key_item, QtCore.SIGNAL("triggered()"), lambda: self.copy_friend_key(num)) - 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)) else: copy_menu = self.listMenu.addMenu( QtGui.QApplication.translate("MainWindow", 'Copy', None, QtGui.QApplication.UnicodeUTF8)) @@ -601,13 +595,17 @@ class MainWindow(QtGui.QMainWindow): QtGui.QApplication.translate("MainWindow", 'Public key', None, QtGui.QApplication.UnicodeUTF8)) leave_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Leave group', None, QtGui.QApplication.UnicodeUTF8)) 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)) notes_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Notes', None, QtGui.QApplication.UnicodeUTF8)) - 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)) - self.connect(copy_key_item, QtCore.SIGNAL("triggered()"), lambda: self.copy_friend_key(num)) self.connect(leave_item, QtCore.SIGNAL("triggered()"), lambda: Profile.get_instance().leave_group(num)) - self.connect(set_alias_item, QtCore.SIGNAL("triggered()"), lambda: self.set_alias(num)) + + self.connect(notes_item, QtCore.SIGNAL("triggered()"), lambda: self.show_note(friend)) + self.connect(set_alias_item, QtCore.SIGNAL("triggered()"), lambda: self.set_alias(num)) + self.connect(clear_history_item, QtCore.SIGNAL("triggered()"), lambda: self.clear_history(num)) + 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)) + self.connect(copy_key_item, QtCore.SIGNAL("triggered()"), lambda: self.copy_friend_key(num)) + parent_position = self.friends_list.mapToGlobal(QtCore.QPoint(0, 0)) self.listMenu.move(parent_position + pos) self.listMenu.show() diff --git a/toxygen/profile.py b/toxygen/profile.py index 00431e2..b33b38b 100644 --- a/toxygen/profile.py +++ b/toxygen/profile.py @@ -694,11 +694,12 @@ class Profile(basecontact.BaseContact, Singleton): def friend_public_key(self, num): return self._friends_and_gc[num].tox_id - def delete_friend_or_gc(self, num, is_gc=False): + def delete_friend_or_gc(self, num, is_gc=False, message=None): """ Removes friend or gc from contact list :param num: number of friend or gc in list :param is_gc: is a group chat + :param message: message in gc """ friend = self._friends_and_gc[num] settings = Settings.get_instance() @@ -715,10 +716,12 @@ class Profile(basecontact.BaseContact, Singleton): self._history.delete_friend_from_db(friend.tox_id) if not is_gc: self._tox.friend_delete(friend.number) + else: + self._tox.group_leave(num, message) del self._friends_and_gc[num] self._screen.friends_list.takeItem(num) - if num == self._active_friend_or_gc: # active friend was deleted - if not len(self._friends_and_gc): # last friend was deleted + if num == self._active_friend_or_gc: # active friend or gc was deleted + if not len(self._friends_and_gc): # last contact was deleted self.set_active(-1) else: self.set_active(0) @@ -1309,9 +1312,7 @@ class Profile(basecontact.BaseContact, Singleton): self._tox.group_invite_friend(group_number, friend_number) def leave_group(self, num, message=None): - number = self._friends_and_gc[num].number - self._tox.group_leave(number, message) - self.delete_friend_or_gc(num, False) + self.delete_friend_or_gc(num, True, message) def tox_factory(data=None, settings=None): From f775203f4cbfd840b3d8333bc3f57b3f01f49938 Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Wed, 13 Jul 2016 16:12:15 +0300 Subject: [PATCH 04/10] some fixes --- toxygen/profile.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/toxygen/profile.py b/toxygen/profile.py index b33b38b..446bc8b 100644 --- a/toxygen/profile.py +++ b/toxygen/profile.py @@ -250,7 +250,10 @@ class Profile(basecontact.BaseContact, Singleton): self._screen.account_status.setText(friend_or_gc.status_message) avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(friend_or_gc.tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) if not os.path.isfile(avatar_path): # load default image - avatar_path = curr_directory() + '/images/avatar.png' + if type(friend_or_gc) is Friend: + avatar_path = curr_directory() + '/images/avatar.png' + else: + avatar_path = curr_directory() + '/images/group.png' os.chdir(os.path.dirname(avatar_path)) pixmap = QtGui.QPixmap(QtCore.QSize(64, 64)) pixmap.load(avatar_path) @@ -427,9 +430,8 @@ class Profile(basecontact.BaseContact, Singleton): time.time(), message_type)) else: friend_or_gc = self.get_friend_by_number(num) - friend_or_gc.inc_messages() friend_or_gc.append_message(TextMessage(message, MESSAGE_OWNER['FRIEND'], time.time(), message_type)) - + friend_or_gc.inc_messages() if not friend_or_gc.visibility: self.update_filtration() @@ -493,6 +495,7 @@ class Profile(basecontact.BaseContact, Singleton): Save history to db """ s = Settings.get_instance() + # TODO: different saving for friends and gc if hasattr(self, '_history'): if s['save_history']: for friend_or_gc in self._friends_and_gc: From 4abd72e27883001d92228a0f6d5a8d493864f296 Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Thu, 14 Jul 2016 22:23:56 +0300 Subject: [PATCH 05/10] more callbacks, fixes, peers --- toxygen/basecontact.py | 4 ++-- toxygen/callbacks.py | 15 +++++++++++++++ toxygen/groupchat.py | 24 +++++++++++++++++++++++- toxygen/profile.py | 2 +- toxygen/tox.py | 27 +++++++++++++++++++-------- 5 files changed, 60 insertions(+), 12 deletions(-) diff --git a/toxygen/basecontact.py b/toxygen/basecontact.py index a484173..b0accb3 100644 --- a/toxygen/basecontact.py +++ b/toxygen/basecontact.py @@ -29,7 +29,7 @@ class BaseContact: self.load_avatar() # ----------------------------------------------------------------------------------------------------------------- - # name - current name or alias of user + # Name - current name or alias of user # ----------------------------------------------------------------------------------------------------------------- def get_name(self): @@ -43,7 +43,7 @@ class BaseContact: name = property(get_name, set_name) # ----------------------------------------------------------------------------------------------------------------- - # Status message + # Status message or group topic # ----------------------------------------------------------------------------------------------------------------- def get_status_message(self): diff --git a/toxygen/callbacks.py b/toxygen/callbacks.py index 12e72d1..f763604 100644 --- a/toxygen/callbacks.py +++ b/toxygen/callbacks.py @@ -317,6 +317,19 @@ def group_invite(tox, friend_number, invite_data, length, user_data): invite_data[:length]) +def group_self_join(tox, group_number, user_data): + pr = Profile.get_instance() + gc = pr.get_gc_by_number(group_number) + invoke_in_main_thread(gc.set_status, TOX_USER_STATUS['NONE']) + if not pr.is_active_a_friend() and pr.get_active_number() == group_number: + invoke_in_main_thread(pr.set_active) + + +def group_peer_join(tox, group_number, peer_id, user_data): + gc = Profile.get_instance().get_gc_by_number(group_number) + gc.add_peer(peer_id) + + # ----------------------------------------------------------------------------------------------------------------- # Callbacks - initialization # ----------------------------------------------------------------------------------------------------------------- @@ -355,4 +368,6 @@ def init_callbacks(tox, window, tray): tox.callback_group_message(group_message(window, tray, tox), 0) tox.callback_group_invite(group_invite, 0) + tox.callback_group_self_join(group_self_join, 0) + tox.callback_group_peer_join(group_peer_join, 0) diff --git a/toxygen/groupchat.py b/toxygen/groupchat.py index 1038407..3437696 100644 --- a/toxygen/groupchat.py +++ b/toxygen/groupchat.py @@ -10,4 +10,26 @@ class GroupChat(contact.Contact): def load_avatar(self, default_path='group.png'): super().load_avatar(default_path) -# TODO: get peers list and add other methods + def set_status(self, value): + print('In gc set_status') + self.name = self._tox.group_get_name(self._number) + self._tox_id = self._tox.group_get_chat_id(self._number) + self.status_message = self._tox.group_get_topic(self._number) + + def add_peer(self, peer_id): + print(peer_id) + print(self._tox.group_peer_get_name(self._number, peer_id)) + + # TODO: get peers list and add other methods + + def get_peers_list(self): + return [] + + +class Peer: + + def __init__(self, peer_id, name, status, role): + self._data = (peer_id, name, status, role) + + def get_data(self): + return self._data diff --git a/toxygen/profile.py b/toxygen/profile.py index 446bc8b..a27a9e7 100644 --- a/toxygen/profile.py +++ b/toxygen/profile.py @@ -720,7 +720,7 @@ class Profile(basecontact.BaseContact, Singleton): if not is_gc: self._tox.friend_delete(friend.number) else: - self._tox.group_leave(num, message) + self._tox.group_leave(num, message.encode('utf-8') if message is not None else None) del self._friends_and_gc[num] self._screen.friends_list.takeItem(num) if num == self._active_friend_or_gc: # active friend or gc was deleted diff --git a/toxygen/tox.py b/toxygen/tox.py index f33b7df..66b7210 100644 --- a/toxygen/tox.py +++ b/toxygen/tox.py @@ -1607,9 +1607,11 @@ class Tox: """ error = c_int() - result = Tox.libtoxcore.tox_group_leave(self._tox_pointer, groupnumber, message, - len(message) if message is not None else 0, byref(error)) - return result + f = Tox.libtoxcore.tox_group_leave + f.restype = c_bool + result = f(self._tox_pointer, groupnumber, message, + len(message) if message is not None else 0, byref(error)) + return result.value # ----------------------------------------------------------------------------------------------------------------- # Group user-visible client information (nickname/status/role/public key) @@ -1965,7 +1967,7 @@ class Tox: see the `Group chat founder controls` section for the respective set function. - :return true on success. + :return password """ error = c_int() @@ -2165,10 +2167,10 @@ class Tox: """ error = c_int() - result = Tox.libtoxcore.tox_group_invite_accept(self._tox_pointer, invite_data, len(invite_data), - password, - len(password) if password is not None else 0, - byref(error)) + f = Tox.libtoxcore.tox_group_invite_accept + f.restype = c_uint32 + result = f(self._tox_pointer, invite_data, len(invite_data), password, + len(password) if password is not None else 0, byref(error)) return result def callback_group_invite(self, callback, user_data): @@ -2195,6 +2197,11 @@ class Tox: Set the callback for the `group_peer_join` event. Pass NULL to unset. This event is triggered when a peer other than self joins the group. + Callback: python function with params: + tox - Tox* + group_number - group number + peer_id - peer id + user_data - user data """ c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_void_p) @@ -2218,6 +2225,10 @@ class Tox: This event is triggered when the client has successfully joined a group. Use this to initialize any group information the client may need. + Callback: python fucntion with params: + tox - *Tox + group_number - group number + user_data - user data """ c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_void_p) From 2745caa5316acee436dcf3abdc2c7f3f20243393 Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Fri, 15 Jul 2016 12:12:06 +0300 Subject: [PATCH 06/10] invite fix --- toxygen/callbacks.py | 2 +- toxygen/groupchat.py | 5 +++-- toxygen/profile.py | 11 ++++++++--- toxygen/tox.py | 10 +++++----- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/toxygen/callbacks.py b/toxygen/callbacks.py index f763604..72eeb66 100644 --- a/toxygen/callbacks.py +++ b/toxygen/callbacks.py @@ -314,7 +314,7 @@ def group_message(window, tray, tox): def group_invite(tox, friend_number, invite_data, length, user_data): invoke_in_main_thread(Profile.get_instance().process_group_invite, friend_number, - invite_data[:length]) + bytes(invite_data[:length])) def group_self_join(tox, group_number, user_data): diff --git a/toxygen/groupchat.py b/toxygen/groupchat.py index 3437696..b692761 100644 --- a/toxygen/groupchat.py +++ b/toxygen/groupchat.py @@ -12,9 +12,10 @@ class GroupChat(contact.Contact): def set_status(self, value): print('In gc set_status') - self.name = self._tox.group_get_name(self._number) + super().set_status(value) + self.name = bytes(self._tox.group_get_name(self._number), 'utf-8') self._tox_id = self._tox.group_get_chat_id(self._number) - self.status_message = self._tox.group_get_topic(self._number) + self.status_message = bytes(self._tox.group_get_topic(self._number), 'utf-8') def add_peer(self, peer_id): print(peer_id) diff --git a/toxygen/profile.py b/toxygen/profile.py index a27a9e7..f1ed62b 100644 --- a/toxygen/profile.py +++ b/toxygen/profile.py @@ -1262,9 +1262,12 @@ class Profile(basecontact.BaseContact, Singleton): return list(filter(lambda x: type(x) is GroupChat, self._friends_and_gc)) def add_gc(self, num): - tox_id = self._tox.group_get_chat_id(num) - name = self._tox.group_get_name(num) - topic = self._tox.group_get_topic(num) + try: + tox_id = self._tox.group_get_chat_id(num) + name = self._tox.group_get_name(num) + topic = self._tox.group_get_topic(num) + except: + tox_id = name = topic = '' item = self.create_friend_item() try: if not self._history.friend_exists_in_db(tox_id): @@ -1289,6 +1292,7 @@ class Profile(basecontact.BaseContact, Singleton): if password: self._tox.group_founder_set_password(num, bytes(password, 'utf-8')) self.add_gc(num) + self.get_gc_by_number(num).set_status(TOX_USER_STATUS['NONE']) def process_group_invite(self, friend_num, data): # TODO: support password @@ -1302,6 +1306,7 @@ class Profile(basecontact.BaseContact, Singleton): num = self._tox.group_invite_accept(data) data = self._tox.get_savedata() ProfileHelper.get_instance().save_profile(data) + print('In gc invite', num) self.add_gc(num) elif reply != QtGui.QMessageBox.No: if friend_num in self._gc_invites: diff --git a/toxygen/tox.py b/toxygen/tox.py index 66b7210..a80900b 100644 --- a/toxygen/tox.py +++ b/toxygen/tox.py @@ -1549,9 +1549,7 @@ class Tox: """ error = c_int() - func = Tox.libtoxcore.tox_group_new - func.restype = c_uint32 - result = func(self._tox_pointer, privacy_state, group_name, + result = Tox.libtoxcore.tox_group_new(self._tox_pointer, privacy_state, group_name, len(group_name), byref(error)) return result @@ -1611,7 +1609,8 @@ class Tox: f.restype = c_bool result = f(self._tox_pointer, groupnumber, message, len(message) if message is not None else 0, byref(error)) - return result.value + print('In group leave. Result:', result, 'Error:', error.value) + return result # ----------------------------------------------------------------------------------------------------------------- # Group user-visible client information (nickname/status/role/public key) @@ -2171,6 +2170,7 @@ class Tox: f.restype = c_uint32 result = f(self._tox_pointer, invite_data, len(invite_data), password, len(password) if password is not None else 0, byref(error)) + print('Invite accept. Result:', result, 'Error:', error.value) return result def callback_group_invite(self, callback, user_data): @@ -2188,7 +2188,7 @@ class Tox: user_data - user data """ - c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_char_p, c_size_t, c_void_p) + c_callback = CFUNCTYPE(None, c_void_p, c_uint32, POINTER(c_uint8), c_size_t, c_void_p) self.group_invite_cb = c_callback(callback) Tox.libtoxcore.tox_callback_group_invite(self._tox_pointer, self.group_invite_cb, user_data) From 735c88d5bf0d7d2a07df7d6236b0d27cc67c27af Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Fri, 15 Jul 2016 03:10:41 -0700 Subject: [PATCH 07/10] notifications fix, reconnect added --- toxygen/callbacks.py | 6 +++--- toxygen/menu.py | 1 + toxygen/profile.py | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/toxygen/callbacks.py b/toxygen/callbacks.py index 72eeb66..450df1e 100644 --- a/toxygen/callbacks.py +++ b/toxygen/callbacks.py @@ -293,7 +293,7 @@ def callback_audio(toxav, friend_number, samples, audio_samples_per_channel, aud def group_message(window, tray, tox): """ - New message from friend + New message in group chat """ def wrapped(tox_link, group_number, peer_id, message_type, message, length, user_data): profile = Profile.get_instance() @@ -303,9 +303,9 @@ def group_message(window, tray, tox): if not window.isActiveWindow(): bl = settings['notify_all_gc'] or profile.name in message name = tox.group_peer_get_name(group_number, peer_id) - if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY'] and not settings.locked and bl: + if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY'] and (not settings.locked) and bl: invoke_in_main_thread(tray_notification, name, message, tray, window) - if (settings['sound_notifications'] or bl) and profile.status != TOX_USER_STATUS['BUSY']: + if settings['sound_notifications'] and bl and profile.status != TOX_USER_STATUS['BUSY']: sound_notification(SOUND_NOTIFICATION['MESSAGE']) invoke_in_main_thread(tray.setIcon, QtGui.QIcon(curr_directory() + '/images/icon_new_messages.png')) return wrapped diff --git a/toxygen/menu.py b/toxygen/menu.py index 725ee60..8dc9621 100644 --- a/toxygen/menu.py +++ b/toxygen/menu.py @@ -638,6 +638,7 @@ class NotificationsSettings(CenteredWidget): settings['notifications'] = self.enableNotifications.isChecked() settings['sound_notifications'] = self.soundNotifications.isChecked() settings['calls_sound'] = self.callsSound.isChecked() + settings['notify_all_gc'] = self.gcNotifications.isChecked() settings.save() diff --git a/toxygen/profile.py b/toxygen/profile.py index f1ed62b..edd4255 100644 --- a/toxygen/profile.py +++ b/toxygen/profile.py @@ -96,6 +96,9 @@ class Profile(basecontact.BaseContact, Singleton): self.set_status((self._status + 1) % 3) def set_status(self, status): + if self.status is None: + for gc in filter(lambda x: type(x) is GroupChat, self._friends_and_gc): + self._tox.group_reconnect(gc.number) super(Profile, self).set_status(status) if status is not None: self._tox.self_set_status(status) From 1ab59ee42256ead8c39d834dfc64306d6519ea30 Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Fri, 15 Jul 2016 13:03:44 -0700 Subject: [PATCH 08/10] group leave fix --- toxygen/profile.py | 8 +++++--- toxygen/tox.py | 1 - 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/toxygen/profile.py b/toxygen/profile.py index edd4255..2cb8e29 100644 --- a/toxygen/profile.py +++ b/toxygen/profile.py @@ -418,7 +418,7 @@ class Profile(basecontact.BaseContact, Singleton): :param peer_id: if gc - peer id """ t = time.time() - + active = False if num == self.get_active_number() and is_group != self.is_active_a_friend(): # add message to list if not is_group: self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type) @@ -426,6 +426,7 @@ class Profile(basecontact.BaseContact, Singleton): self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type, True, self._tox.group_peer_get_name(num, peer_id)) self._messages.scrollToBottom() + active = True if is_group: friend_or_gc = self.get_gc_by_number(num) friend_or_gc.append_message(GroupChatTextMessage(self._tox.group_peer_get_name(num, peer_id), @@ -434,7 +435,8 @@ class Profile(basecontact.BaseContact, Singleton): else: friend_or_gc = self.get_friend_by_number(num) friend_or_gc.append_message(TextMessage(message, MESSAGE_OWNER['FRIEND'], time.time(), message_type)) - friend_or_gc.inc_messages() + if not active: + friend_or_gc.inc_messages() if not friend_or_gc.visibility: self.update_filtration() @@ -723,7 +725,7 @@ class Profile(basecontact.BaseContact, Singleton): if not is_gc: self._tox.friend_delete(friend.number) else: - self._tox.group_leave(num, message.encode('utf-8') if message is not None else None) + self._tox.group_leave(friend.number, message.encode('utf-8') if message is not None else None) del self._friends_and_gc[num] self._screen.friends_list.takeItem(num) if num == self._active_friend_or_gc: # active friend or gc was deleted diff --git a/toxygen/tox.py b/toxygen/tox.py index a80900b..6cfca5a 100644 --- a/toxygen/tox.py +++ b/toxygen/tox.py @@ -1609,7 +1609,6 @@ class Tox: f.restype = c_bool result = f(self._tox_pointer, groupnumber, message, len(message) if message is not None else 0, byref(error)) - print('In group leave. Result:', result, 'Error:', error.value) return result # ----------------------------------------------------------------------------------------------------------------- From 2fc90880b88923ec4aabc56aef47a29fb5d8c072 Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Fri, 27 Jan 2017 21:09:15 +0300 Subject: [PATCH 09/10] api update --- toxygen/profile.py | 2 +- toxygen/tox.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/toxygen/profile.py b/toxygen/profile.py index 2cb8e29..fc54a31 100644 --- a/toxygen/profile.py +++ b/toxygen/profile.py @@ -1308,7 +1308,7 @@ class Profile(basecontact.BaseContact, Singleton): fr_req = QtGui.QApplication.translate('MainWindow', 'Group chat invite', None, QtGui.QApplication.UnicodeUTF8) reply = QtGui.QMessageBox.question(None, fr_req, info, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: # accepted - num = self._tox.group_invite_accept(data) + num = self._tox.group_invite_accept(data, friend_num) data = self._tox.get_savedata() ProfileHelper.get_instance().save_profile(data) print('In gc invite', num) diff --git a/toxygen/tox.py b/toxygen/tox.py index 6cfca5a..2e88366 100644 --- a/toxygen/tox.py +++ b/toxygen/tox.py @@ -2154,7 +2154,7 @@ class Tox: result = Tox.libtoxcore.tox_group_invite_friend(self._tox_pointer, groupnumber, friend_number, byref(error)) return result - def group_invite_accept(self, invite_data, password=None): + def group_invite_accept(self, invite_data, friend_number, password=None): """ Accept an invite to a group chat that the client previously received from a friend. The invite is only valid while the inviter is present in the group. @@ -2167,7 +2167,7 @@ class Tox: error = c_int() f = Tox.libtoxcore.tox_group_invite_accept f.restype = c_uint32 - result = f(self._tox_pointer, invite_data, len(invite_data), password, + result = f(self._tox_pointer, friend_number, invite_data, len(invite_data), password, len(password) if password is not None else 0, byref(error)) print('Invite accept. Result:', result, 'Error:', error.value) return result From 098f295cb0306647635af5cdaa4e9889f4802bd3 Mon Sep 17 00:00:00 2001 From: Ingvar Date: Mon, 8 Jan 2018 22:40:52 +0300 Subject: [PATCH 10/10] Fix group join by chat id --- toxygen/tox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toxygen/tox.py b/toxygen/tox.py index 2e88366..a783e5a 100644 --- a/toxygen/tox.py +++ b/toxygen/tox.py @@ -1568,7 +1568,7 @@ class Tox: """ error = c_int() - result = Tox.libtoxcore.tox_group_join(self._tox_pointer, chat_id, + result = Tox.libtoxcore.tox_group_join(self._tox_pointer, string_to_bin(chat_id), password, len(password) if password is not None else 0, byref(error))