diff --git a/toxygen/contacts/contact_menu.py b/toxygen/contacts/contact_menu.py index e10f07d..63d0d36 100644 --- a/toxygen/contacts/contact_menu.py +++ b/toxygen/contacts/contact_menu.py @@ -181,9 +181,12 @@ class GroupMenuGenerator(BaseContactMenuGenerator): menu = (builder .with_action(util_ui.tr('Set alias'), lambda: main_screen.set_alias(number)) .with_submenu(copy_menu_builder) + .with_optional_action(util_ui.tr('Manage group'), + lambda: groups_service.show_group_management_screen(self._contact), + self._contact.is_self_founder()) .with_optional_action(util_ui.tr('Set topic'), lambda: groups_service.set_group_topic(self._contact), - self._contact.is_moderator_or_founder()) + self._contact.is_self_moderator_or_founder()) .with_action(util_ui.tr('Reconnect to group'), lambda: groups_service.reconnect_to_group(self._contact.number)) .with_optional_action(util_ui.tr('Disconnect from group'), diff --git a/toxygen/contacts/group_chat.py b/toxygen/contacts/group_chat.py index 38ab686..b38e538 100644 --- a/toxygen/contacts/group_chat.py +++ b/toxygen/contacts/group_chat.py @@ -12,6 +12,8 @@ class GroupChat(contact.Contact, ToxSave): super().__init__(profile_manager, message_getter, number, name, status_message, widget, tox_id) ToxSave.__init__(self, tox) self._is_private = is_private + self._password = None + self._peers_limit = 512 self._peers = [] self._add_self_to_gc() @@ -32,7 +34,26 @@ class GroupChat(contact.Contact, ToxSave): def get_is_private(self): return self._is_private - is_private = property(get_is_private) + def set_is_private(self, is_private): + self._is_private = is_private + + is_private = property(get_is_private, set_is_private) + + def get_password(self): + return self._password + + def set_password(self, password): + self._password = password + + password = property(get_password, set_password) + + def get_peers_limit(self): + return self._peers_limit + + def set_peers_limit(self, peers_limit): + self._peers_limit = peers_limit + + peers_limit = property(get_peers_limit, set_peers_limit) # ----------------------------------------------------------------------------------------------------------------- # Peers methods @@ -47,9 +68,12 @@ class GroupChat(contact.Contact, ToxSave): def get_self_role(self): return self._peers[0].role - def is_moderator_or_founder(self): + def is_self_moderator_or_founder(self): return self.get_self_role() <= constants.TOX_GROUP_ROLE['MODERATOR'] + def is_self_founder(self): + return self.get_self_role() == constants.TOX_GROUP_ROLE['FOUNDER'] + def add_peer(self, peer_id, is_current_user=False): peer = GroupChatPeer(peer_id, self._tox.group_peer_get_name(self._number, peer_id), diff --git a/toxygen/groups/groups_service.py b/toxygen/groups/groups_service.py index 1016bd7..4cf1368 100644 --- a/toxygen/groups/groups_service.py +++ b/toxygen/groups/groups_service.py @@ -15,7 +15,7 @@ class GroupsService(tox_save.ToxSave): self._peers_list_widget = main_screen.peers_list self._widgets_factory_provider = widgets_factory_provider self._group_invites = [] - self._peer_screen = None + self._peer_screen = self._management_screen = None def set_tox(self, tox): super().set_tox(tox) @@ -70,14 +70,14 @@ class GroupsService(tox_save.ToxSave): friend = self._get_friend_by_number(friend_number) invite = GroupInvite(friend.tox_id, group_name, invite_data) self._group_invites.append(invite) - self._main_screen.update_gc_invites_button_state() + self._update_invites_button_state() 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) - self._main_screen.update_gc_invites_button_state() + self._update_invites_button_state() def decline_group_invite(self, invite): self._delete_group_invite(invite) @@ -102,7 +102,7 @@ class GroupsService(tox_save.ToxSave): group.status_message = self._tox.group_get_topic(group.number) def set_group_topic(self, group): - if not group.is_moderator_or_founder(): + if not group.is_self_moderator_or_founder(): return text = util_ui.tr('New topic for group "{}":'.format(group.name)) title = util_ui.tr('Set group topic') @@ -112,6 +112,30 @@ class GroupsService(tox_save.ToxSave): self._tox.group_set_topic(group.number, topic) group.status_message = topic + def show_group_management_screen(self, group): + widgets_factory = self._get_widgets_factory() + self._management_screen = widgets_factory.create_group_management_screen(group) + self._management_screen.show() + + def set_group_password(self, group, password): + if group.password == password: + return + self._tox.group_founder_set_password(group.number, password) + group.password = password + + def set_group_peers_limit(self, group, peers_limit): + if group.peers_limit == peers_limit: + return + self._tox.group_founder_set_peer_limit(group.number, peers_limit) + group.peers_limit = peers_limit + + def set_group_privacy_state(self, group, privacy_state): + is_private = privacy_state == constants.TOX_GROUP_PRIVACY_STATE['PRIVATE'] + if group.is_private == is_private: + return + self._tox.group_founder_set_privacy_state(group.number, privacy_state) + group.is_private = is_private + # ----------------------------------------------------------------------------------------------------------------- # Peers list # ----------------------------------------------------------------------------------------------------------------- @@ -123,7 +147,7 @@ class GroupsService(tox_save.ToxSave): PeersListGenerator().generate(group.peers, self, self._peers_list_widget, group.tox_id) def peer_selected(self, chat_id, peer_id): - widgets_factory = self._widgets_factory_provider.get_item() + widgets_factory = self._get_widgets_factory() group = self._get_group_by_public_key(chat_id) self_peer = group.get_self_peer() if self_peer.id != peer_id: @@ -186,3 +210,9 @@ class GroupsService(tox_save.ToxSave): 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) + + def _update_invites_button_state(self): + self._main_screen.update_gc_invites_button_state() + + def _get_widgets_factory(self): + return self._widgets_factory_provider.get_item() diff --git a/toxygen/middleware/callbacks.py b/toxygen/middleware/callbacks.py index 36bb960..77a029d 100644 --- a/toxygen/middleware/callbacks.py +++ b/toxygen/middleware/callbacks.py @@ -506,6 +506,34 @@ def group_moderation(groups_service, contacts_provider, contacts_manager, messen return wrapped + +def group_password(contacts_provider): + + def wrapped(tox_link, group_number, password, length, user_data): + password = str(password[:length], 'utf-8') + group = contacts_provider.get_group_by_number(group_number) + group.password = password + + return wrapped + + +def group_peer_limit(contacts_provider): + + def wrapped(tox_link, group_number, peer_limit, user_data): + group = contacts_provider.get_group_by_number(group_number) + group.peer_limit = peer_limit + + return wrapped + + +def group_privacy_state(contacts_provider): + + def wrapped(tox_link, group_number, privacy_state, user_data): + group = contacts_provider.get_group_by_number(group_number) + group.is_private = privacy_state == TOX_GROUP_PRIVACY_STATE['PRIVATE'] + + return wrapped + # ----------------------------------------------------------------------------------------------------------------- # Callbacks - initialization # ----------------------------------------------------------------------------------------------------------------- @@ -573,3 +601,6 @@ def init_callbacks(tox, profile, settings, plugin_loader, contacts_manager, tox.callback_group_peer_status(group_peer_status(contacts_provider, groups_service), 0) tox.callback_group_topic(group_topic(contacts_provider), 0) tox.callback_group_moderation(group_moderation(groups_service, contacts_provider, contacts_manager, messenger), 0) + tox.callback_group_password(group_password(contacts_provider), 0) + tox.callback_group_peer_limit(group_peer_limit(contacts_provider), 0) + tox.callback_group_privacy_state(group_privacy_state(contacts_provider), 0) diff --git a/toxygen/ui/group_management_screen.py b/toxygen/ui/group_management_screen.py new file mode 100644 index 0000000..bbc2629 --- /dev/null +++ b/toxygen/ui/group_management_screen.py @@ -0,0 +1,46 @@ +from ui.widgets import CenteredWidget +from PyQt5 import uic +import utils.util as util +import utils.ui as util_ui + + +class GroupManagementScreen(CenteredWidget): + + def __init__(self, groups_service, group): + super().__init__() + self._groups_service = groups_service + self._group = group + + uic.loadUi(util.get_views_path('group_management_screen'), self) + self._update_ui() + + def _update_ui(self): + self._retranslate_ui() + + self.passwordLineEdit.setText(self._group.password) + self.privacyStateComboBox.setCurrentIndex(1 if self._group.is_private else 0) + self.peersLimitSpinBox.setValue(self._group.peers_limit) + + self.savePushButton.clicked.connect(self._save) + + def _retranslate_ui(self): + self.setWindowTitle(util_ui.tr('Group "{}"').format(self._group.name)) + self.passwordLabel.setText(util_ui.tr('Password')) + self.peerLimitLabel.setText(util_ui.tr('Peer limit:')) + self.privacyStateLabel.setText(util_ui.tr('Privacy state')) + self.savePushButton.setText(util_ui.tr('Save')) + + self.privacyStateComboBox.clear() + self.privacyStateComboBox.addItem(util_ui.tr('Public')) + self.privacyStateComboBox.addItem(util_ui.tr('Private')) + + def _save(self): + password = self.passwordLineEdit.text() + privacy_state = self.privacyStateComboBox.currentIndex() + peers_limit = self.peersLimitSpinBox.value() + + self._groups_service.set_group_password(self._group, password) + self._groups_service.set_group_privacy_state(self._group, privacy_state) + self._groups_service.set_group_peers_limit(self._group, peers_limit) + + self.close() diff --git a/toxygen/ui/views/group_management_screen.ui b/toxygen/ui/views/group_management_screen.ui new file mode 100644 index 0000000..859754b --- /dev/null +++ b/toxygen/ui/views/group_management_screen.ui @@ -0,0 +1,110 @@ + + + Form + + + + 0 + 0 + 658 + 238 + + + + Form + + + + + 180 + 20 + 450 + 41 + + + + + + + 20 + 30 + 145 + 20 + + + + TextLabel + + + + + + 20 + 80 + 145 + 20 + + + + TextLabel + + + + + + 180 + 70 + 450 + 40 + + + + 2 + + + 9999 + + + 512 + + + + + + 20 + 130 + 145 + 20 + + + + TextLabel + + + + + + 180 + 120 + 450 + 40 + + + + + + + 20 + 180 + 611 + 41 + + + + PushButton + + + + + + diff --git a/toxygen/ui/views/interface_settings_screen.ui b/toxygen/ui/views/interface_settings_screen.ui new file mode 100644 index 0000000..fb0bcf1 --- /dev/null +++ b/toxygen/ui/views/interface_settings_screen.ui @@ -0,0 +1,253 @@ + + + Form + + + + 0 + 0 + 552 + 847 + + + + Form + + + + + + Qt::ScrollBarAsNeeded + + + true + + + + + 0 + 0 + 532 + 827 + + + + + + 30 + 140 + 67 + 17 + + + + TextLabel + + + + + + 20 + 180 + 471 + 31 + + + + + + + 20 + 60 + 471 + 31 + + + + + + + 30 + 20 + 67 + 17 + + + + TextLabel + + + + + + 30 + 220 + 461 + 23 + + + + CheckBox + + + + + + 30 + 280 + 461 + 221 + + + + GroupBox + + + + + 30 + 40 + 92 + 23 + + + + CheckBox + + + + + + 30 + 80 + 411 + 17 + + + + TextLabel + + + + + + 30 + 120 + 411 + 31 + + + + + + + + 30 + 250 + 461 + 23 + + + + CheckBox + + + + + + 30 + 750 + 471 + 40 + + + + PushButton + + + + + + 30 + 690 + 471 + 40 + + + + PushButton + + + + + + 30 + 520 + 461 + 23 + + + + CheckBox + + + + + + 30 + 550 + 471 + 131 + + + + GroupBox + + + + + 30 + 30 + 421 + 23 + + + + RadioButton + + + + + + 30 + 60 + 431 + 23 + + + + RadioButton + + + + + + 30 + 90 + 421 + 23 + + + + RadioButton + + + + + + + + + + + diff --git a/toxygen/ui/widgets_factory.py b/toxygen/ui/widgets_factory.py index 75b83b4..e394684 100644 --- a/toxygen/ui/widgets_factory.py +++ b/toxygen/ui/widgets_factory.py @@ -4,6 +4,7 @@ from ui.groups_widgets import * from ui.peer_screen import * from ui.self_peer_screen import * from ui.group_invites_widgets import * +from ui.group_management_screen import * class WidgetsFactory: @@ -82,3 +83,6 @@ class WidgetsFactory: def create_group_invites_window(self): return GroupInvitesScreen(self._groups_service, self._profile, self._contacts_provider) + + def create_group_management_screen(self, group): + return GroupManagementScreen(self._groups_service, group)