diff --git a/toxygen/app.py b/toxygen/app.py
index 77864e7..a7fbaff 100644
--- a/toxygen/app.py
+++ b/toxygen/app.py
@@ -366,10 +366,11 @@ class App:
widgets_factory = None
widgets_factory_provider = Provider(lambda: widgets_factory)
self._groups_service = GroupsService(self._tox, self._contacts_manager, self._contacts_provider, self._ms,
- widgets_factory_provider, self._profile)
+ widgets_factory_provider)
widgets_factory = WidgetsFactory(self._settings, self._profile, self._profile_manager, self._contacts_manager,
self._file_transfer_handler, self._smiley_loader, self._plugin_loader,
- self._toxes, self._version, self._groups_service, history)
+ self._toxes, self._version, self._groups_service, history,
+ self._contacts_provider)
self._tray = tray.init_tray(self._profile, self._settings, self._ms, self._toxes)
self._ms.set_dependencies(widgets_factory, self._tray, self._contacts_manager, self._messenger, self._profile,
self._plugin_loader, self._file_transfer_handler, history, self._calls_manager,
diff --git a/toxygen/groups/group_invite.py b/toxygen/groups/group_invite.py
new file mode 100644
index 0000000..a2eed47
--- /dev/null
+++ b/toxygen/groups/group_invite.py
@@ -0,0 +1,23 @@
+
+
+class GroupInvite:
+
+ def __init__(self, friend_public_key, chat_name, invite_data):
+ self._friend_public_key = friend_public_key
+ self._chat_name = chat_name
+ self._invite_data = invite_data[:]
+
+ def get_friend_public_key(self):
+ return self._friend_public_key
+
+ friend_public_key = property(get_friend_public_key)
+
+ def get_chat_name(self):
+ return self._chat_name
+
+ chat_name = property(get_chat_name)
+
+ def get_invite_data(self):
+ return self._invite_data[:]
+
+ invite_data = property(get_invite_data)
diff --git a/toxygen/groups/groups_service.py b/toxygen/groups/groups_service.py
index f9cdfc9..76ecdaf 100644
--- a/toxygen/groups/groups_service.py
+++ b/toxygen/groups/groups_service.py
@@ -1,18 +1,19 @@
import common.tox_save as tox_save
import utils.ui as util_ui
from groups.peers_list import PeersListGenerator
+from groups.group_invite import GroupInvite
import wrapper.toxcore_enums_and_consts as constants
class GroupsService(tox_save.ToxSave):
- def __init__(self, tox, contacts_manager, contacts_provider, main_screen, widgets_factory_provider, profile):
+ def __init__(self, tox, contacts_manager, contacts_provider, main_screen, widgets_factory_provider):
super().__init__(tox)
self._contacts_manager = contacts_manager
self._contacts_provider = contacts_provider
self._peers_list_widget = main_screen.peers_list
self._widgets_factory_provider = widgets_factory_provider
- self._profile = profile
+ self._group_invites = []
self._peer_screen = None
def set_tox(self, tox):
@@ -37,10 +38,6 @@ class GroupsService(tox_save.ToxSave):
group_number = self._tox.group_join(chat_id, password, nick, status)
self._add_new_group_by_number(group_number)
- def join_gc_via_invite(self, invite_data, friend_number, nick, status, password):
- group_number = self._tox.group_invite_accept(invite_data, friend_number, nick, status, password)
- self._add_new_group_by_number(group_number)
-
# -----------------------------------------------------------------------------------------------------------------
# Groups reconnect and leaving
# -----------------------------------------------------------------------------------------------------------------
@@ -71,9 +68,23 @@ class GroupsService(tox_save.ToxSave):
def process_group_invite(self, friend_number, group_name, invite_data):
friend = self._get_friend_by_number(friend_number)
- text = util_ui.tr('Friend {} invites you to group "{}". Accept?')
- if util_ui.question(text.format(friend.name, group_name), util_ui.tr('Group invite')):
- self.join_gc_via_invite(invite_data, friend_number, self._profile.name, self._profile.status or 0, None)
+ invite = GroupInvite(friend.tox_id, group_name, invite_data)
+ self._group_invites.append(invite)
+ # TODO: notification on main screen
+
+ def accept_group_invite(self, invite, name, status, password):
+ pk = invite.friend_public_key
+ friend = self._get_friend_by_public_key(pk)
+ self._join_gc_via_invite(invite.invite_data, friend.number, name, status, password)
+ self._delete_group_invite(invite)
+
+ def decline_group_invite(self, invite):
+ self._delete_group_invite(invite)
+
+ def get_group_invites(self):
+ return self._group_invites[:]
+
+ group_invites = property(get_group_invites)
# -----------------------------------------------------------------------------------------------------------------
# Group info methods
@@ -153,6 +164,17 @@ class GroupsService(tox_save.ToxSave):
def _get_friend_by_number(self, friend_number):
return self._contacts_provider.get_friend_by_number(friend_number)
+ def _get_friend_by_public_key(self, public_key):
+ return self._contacts_provider.get_friend_by_public_key(public_key)
+
def _clear_peers_list(self, group):
group.remove_all_peers_except_self()
self.generate_peers_list()
+
+ def _delete_group_invite(self, invite):
+ if invite in self._group_invites:
+ self._group_invites.remove(invite)
+
+ def _join_gc_via_invite(self, invite_data, friend_number, nick, status, password):
+ group_number = self._tox.group_invite_accept(invite_data, friend_number, nick, status, password)
+ self._add_new_group_by_number(group_number)
diff --git a/toxygen/middleware/callbacks.py b/toxygen/middleware/callbacks.py
index 3d40cc9..3f25e0c 100644
--- a/toxygen/middleware/callbacks.py
+++ b/toxygen/middleware/callbacks.py
@@ -438,7 +438,7 @@ def group_peer_name(contacts_provider, groups_service):
def wrapped(tox, group_number, peer_id, name, length, user_data):
group = contacts_provider.get_group_by_number(group_number)
peer = group.get_peer_by_id(peer_id)
- peer.name = str(name[:length])
+ peer.name = str(name[:length], 'utf-8')
invoke_in_main_thread(groups_service.generate_peers_list)
return wrapped
diff --git a/toxygen/ui/group_invites_widgets.py b/toxygen/ui/group_invites_widgets.py
new file mode 100644
index 0000000..77403d9
--- /dev/null
+++ b/toxygen/ui/group_invites_widgets.py
@@ -0,0 +1,120 @@
+from PyQt5 import uic, QtWidgets
+import utils.util as util
+from ui.widgets import *
+
+
+class GroupInviteItem(QtWidgets.QWidget):
+
+ def __init__(self, parent, chat_name, avatar, friend_name):
+ super().__init__(parent)
+ uic.loadUi(util.get_views_path('gc_invite_item'), self)
+
+ self.groupNameLabel.setText(chat_name)
+ self.friendNameLabel.setText(friend_name)
+ self.friendAvatarLabel.setPixmap(avatar)
+
+ def is_selected(self):
+ return self.selectCheckBox.isChecked()
+
+ def subscribe_checked_event(self, callback):
+ self.selectCheckBox.clicked.connect(callback)
+
+
+class GroupInvitesScreen(CenteredWidget):
+
+ def __init__(self, groups_service, profile, contacts_provider):
+ super().__init__()
+ self._groups_service = groups_service
+ self._profile = profile
+ self._contacts_provider = contacts_provider
+
+ uic.loadUi(util.get_views_path('group_invites_screen'), self)
+
+ self._update_ui()
+
+ def _update_ui(self):
+ self._retranslate_ui()
+
+ self._refresh_invites_list()
+
+ self.nickLineEdit.setText(self._profile.name)
+ self.statusComboBox.setCurrentIndex(self._profile.status or 0)
+
+ self.nickLineEdit.textChanged.connect(self._nick_changed)
+ self.acceptPushButton.clicked.connect(self._accept_invites)
+ self.declinePushButton.clicked.connect(self._decline_invites)
+
+ self.invitesListWidget.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
+
+ self._update_buttons_state()
+
+ def _retranslate_ui(self):
+ self.setWindowTitle(util_ui.tr('Group chat invites'))
+ self.noInvitesLabel.setText(util_ui.tr('No group invites found'))
+ self.acceptPushButton.setText(util_ui.tr('Accept'))
+ self.declinePushButton.setText(util_ui.tr('Decline'))
+ self.statusComboBox.addItem(util_ui.tr('Online'))
+ self.statusComboBox.addItem(util_ui.tr('Away'))
+ self.statusComboBox.addItem(util_ui.tr('Busy'))
+ self.nickLineEdit.setPlaceholderText(util_ui.tr('Your nick in chat'))
+ self.passwordLineEdit.setPlaceholderText(util_ui.tr('Optional password'))
+
+ def _get_friend(self, public_key):
+ return self._contacts_provider.get_friend_by_public_key(public_key)
+
+ def _accept_invites(self):
+ nick = self.nickLineEdit.text()
+ password = self.passwordLineEdit.text()
+ status = self.statusComboBox.currentIndex()
+
+ selected_invites = self._get_selected_invites()
+ for invite in selected_invites:
+ self._groups_service.accept_group_invite(invite, nick, status, password)
+
+ self._refresh_invites_list()
+
+ def _decline_invites(self):
+ selected_invites = self._get_selected_invites()
+ for invite in selected_invites:
+ self._groups_service.decline_group_invite(invite)
+
+ self._refresh_invites_list()
+
+ def _get_selected_invites(self):
+ all_invites = self._groups_service.get_group_invites()
+ selected = []
+ items_count = len(all_invites)
+ for index in range(items_count):
+ list_item = self.invitesListWidget.item(index)
+ item_widget = self.invitesListWidget.itemWidget(list_item)
+ if item_widget.is_selected():
+ selected.append(all_invites[index])
+
+ return selected
+
+ def _refresh_invites_list(self):
+ self.invitesListWidget.clear()
+ invites = self._groups_service.get_group_invites()
+ for invite in invites:
+ self._create_invite_item(invite)
+
+ def _create_invite_item(self, invite):
+ friend = self._get_friend(invite.friend_public_key)
+ item = GroupInviteItem(self.invitesListWidget, invite.chat_name, friend.get_pixmap(), friend.name)
+ item.subscribe_checked_event(self._item_selected)
+ elem = QtWidgets.QListWidgetItem()
+ elem.setSizeHint(QtCore.QSize(item.width(), item.height()))
+ self.invitesListWidget.addItem(elem)
+ self.invitesListWidget.setItemWidget(elem, item)
+
+ def _item_selected(self):
+ self._update_buttons_state()
+
+ def _nick_changed(self):
+ self._update_buttons_state()
+
+ def _update_buttons_state(self):
+ nick = self.nickLineEdit.text()
+ selected_items = self._get_selected_invites()
+ self.acceptPushButton.setEnabled(bool(nick) and len(selected_items))
+ self.declinePushButton.setEnabled(len(selected_items) > 0)
diff --git a/toxygen/ui/main_screen.py b/toxygen/ui/main_screen.py
index 1bc3612..d02c689 100644
--- a/toxygen/ui/main_screen.py
+++ b/toxygen/ui/main_screen.py
@@ -88,12 +88,14 @@ class MainWindow(QtWidgets.QMainWindow):
self.lockApp = QtWidgets.QAction(window)
self.createGC = QtWidgets.QAction(window)
self.joinGC = QtWidgets.QAction(window)
+ self.gc_invites = QtWidgets.QAction(window)
self.menuProfile.addAction(self.actionAdd_friend)
self.menuProfile.addAction(self.actionSettings)
self.menuProfile.addAction(self.lockApp)
self.menuGC.addAction(self.createGC)
self.menuGC.addAction(self.joinGC)
+ self.menuGC.addAction(self.gc_invites)
self.menuSettings.addAction(self.actionPrivacy_settings)
self.menuSettings.addAction(self.actionInterface_settings)
self.menuSettings.addAction(self.actionNotifications)
@@ -128,6 +130,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.lockApp.triggered.connect(self.lock_app)
self.importPlugin.triggered.connect(self.import_plugin)
self.reloadPlugins.triggered.connect(self.reload_plugins)
+ self.gc_invites.triggered.connect(self._open_gc_invites_list)
def languageChange(self, *args, **kwargs):
self.retranslateUi()
@@ -149,6 +152,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.actionAdd_friend.setText(util_ui.tr("Add contact"))
self.createGC.setText(util_ui.tr("Create group chat"))
self.joinGC.setText(util_ui.tr("Join group chat"))
+ self.gc_invites.setText(util_ui.tr("Group invites"))
self.actionprofilesettings.setText(util_ui.tr("Profile"))
self.actionPrivacy_settings.setText(util_ui.tr("Privacy"))
self.actionInterface_settings.setText(util_ui.tr("Interface"))
@@ -733,3 +737,7 @@ class MainWindow(QtWidgets.QMainWindow):
if self._should_show_group_peers_list:
self._toggle_gc_peers_list()
self.resizeEvent()
+
+ def _open_gc_invites_list(self):
+ self._modal_window = self._widget_factory.create_group_invites_window()
+ self._modal_window.show()
diff --git a/toxygen/ui/views/gc_invite_item.ui b/toxygen/ui/views/gc_invite_item.ui
new file mode 100644
index 0000000..1048a55
--- /dev/null
+++ b/toxygen/ui/views/gc_invite_item.ui
@@ -0,0 +1,71 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 600
+ 150
+
+
+
+ Form
+
+
+
+
+ 250
+ 30
+ 300
+ 21
+
+
+
+ TextLabel
+
+
+
+
+
+ 250
+ 70
+ 300
+ 21
+
+
+
+ TextLabel
+
+
+
+
+
+ 140
+ 30
+ 60
+ 60
+
+
+
+ TextLabel
+
+
+
+
+
+ 40
+ 50
+ 16
+ 23
+
+
+
+
+
+
+
+
+
+
diff --git a/toxygen/ui/views/group_invites_screen.ui b/toxygen/ui/views/group_invites_screen.ui
new file mode 100644
index 0000000..183f801
--- /dev/null
+++ b/toxygen/ui/views/group_invites_screen.ui
@@ -0,0 +1,113 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 600
+ 500
+
+
+
+
+ 600
+ 500
+
+
+
+
+ 600
+ 500
+
+
+
+ Form
+
+
+
+
+ 0
+ 150
+ 600
+ 25
+
+
+
+ TextLabel
+
+
+ Qt::AlignCenter
+
+
+
+
+
+ 0
+ 0
+ 600
+ 341
+
+
+
+
+
+
+ 10
+ 360
+ 350
+ 35
+
+
+
+
+
+
+ 10
+ 410
+ 350
+ 35
+
+
+
+
+
+
+ 390
+ 390
+ 200
+ 35
+
+
+
+
+
+
+ 40
+ 460
+ 201
+ 31
+
+
+
+ PushButton
+
+
+
+
+
+ 360
+ 460
+ 201
+ 31
+
+
+
+ PushButton
+
+
+
+
+
+
diff --git a/toxygen/ui/views/self_peer_screen.ui b/toxygen/ui/views/self_peer_screen.ui
new file mode 100644
index 0000000..38e1f88
--- /dev/null
+++ b/toxygen/ui/views/self_peer_screen.ui
@@ -0,0 +1,119 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 600
+ 500
+
+
+
+
+ 600
+ 500
+
+
+
+
+ 600
+ 500
+
+
+
+ Form
+
+
+
+
+ 50
+ 120
+ 67
+ 20
+
+
+
+ TextLabel
+
+
+
+
+
+ 50
+ 250
+ 500
+ 50
+
+
+
+ PushButton
+
+
+
+
+
+ 140
+ 110
+ 400
+ 40
+
+
+
+
+
+
+ 50
+ 40
+ 67
+ 20
+
+
+
+ TextLabel
+
+
+
+
+
+ 50
+ 190
+ 67
+ 20
+
+
+
+ TextLabel
+
+
+
+
+
+ 140
+ 190
+ 411
+ 20
+
+
+
+ TextLabel
+
+
+
+
+
+ 50
+ 330
+ 500
+ 50
+
+
+
+ PushButton
+
+
+
+
+
+
diff --git a/toxygen/ui/widgets_factory.py b/toxygen/ui/widgets_factory.py
index 8f341df..75b83b4 100644
--- a/toxygen/ui/widgets_factory.py
+++ b/toxygen/ui/widgets_factory.py
@@ -3,12 +3,13 @@ from ui.menu import *
from ui.groups_widgets import *
from ui.peer_screen import *
from ui.self_peer_screen import *
+from ui.group_invites_widgets import *
class WidgetsFactory:
def __init__(self, settings, profile, profile_manager, contacts_manager, file_transfer_handler, smiley_loader,
- plugin_loader, toxes, version, groups_service, history):
+ plugin_loader, toxes, version, groups_service, history, contacts_provider):
self._settings = settings
self._profile = profile
self._profile_manager = profile_manager
@@ -20,6 +21,7 @@ class WidgetsFactory:
self._version = version
self._groups_service = groups_service
self._history = history
+ self._contacts_provider = contacts_provider
def create_screenshot_window(self, *args):
return ScreenShotWindow(self._file_transfer_handler, self._contacts_manager, *args)
@@ -77,3 +79,6 @@ class WidgetsFactory:
def create_self_peer_screen_window(self, group):
return SelfPeerScreen(self._contacts_manager, self._groups_service, group)
+
+ def create_group_invites_window(self):
+ return GroupInvitesScreen(self._groups_service, self._profile, self._contacts_provider)
diff --git a/toxygen/wrapper/tox.py b/toxygen/wrapper/tox.py
index cb2f25e..d705293 100644
--- a/toxygen/wrapper/tox.py
+++ b/toxygen/wrapper/tox.py
@@ -1651,6 +1651,7 @@ class Tox:
"""
error = c_int()
+ name = bytes(name, 'utf-8')
result = Tox.libtoxcore.tox_group_self_set_name(self._tox_pointer, group_number, name, len(name), byref(error))
return result