diff --git a/Signal/src/ViewControllers/ThreadSettings/ConversationSettingsViewController+Contents.swift b/Signal/src/ViewControllers/ThreadSettings/ConversationSettingsViewController+Contents.swift index 64a7b29fdf..e2abab8dc5 100644 --- a/Signal/src/ViewControllers/ThreadSettings/ConversationSettingsViewController+Contents.swift +++ b/Signal/src/ViewControllers/ThreadSettings/ConversationSettingsViewController+Contents.swift @@ -611,20 +611,17 @@ extension ConversationSettingsViewController { self?.showMemberRequestsAndInvitesView() })) - if canEditConversationAccess { - let itemTitle = NSLocalizedString( + section.add(OWSTableItem.disclosureItem( + icon: .settingsPrivacy, + name: NSLocalizedString( "CONVERSATION_SETTINGS_PERMISSIONS", comment: "Label for 'permissions' action in conversation settings view." - ) - section.add(OWSTableItem.disclosureItem( - icon: .settingsPrivacy, - name: itemTitle, - accessibilityIdentifier: "conversation_settings_permissions", - actionBlock: { [weak self] in - self?.showPermissionsSettingsView() - } - )) - } + ), + accessibilityIdentifier: "conversation_settings_permissions", + actionBlock: { [weak self] in + self?.showPermissionsSettingsView() + } + )) contents.addSection(section) } diff --git a/Signal/src/ViewControllers/ThreadSettings/ConversationSettingsViewController.swift b/Signal/src/ViewControllers/ThreadSettings/ConversationSettingsViewController.swift index 5741d9e35b..7410f86dbf 100644 --- a/Signal/src/ViewControllers/ThreadSettings/ConversationSettingsViewController.swift +++ b/Signal/src/ViewControllers/ThreadSettings/ConversationSettingsViewController.swift @@ -104,32 +104,32 @@ class ConversationSettingsViewController: OWSTableViewController2 { // MARK: - Accessors var isBlockedByMigration: Bool { - return groupViewHelper.isBlockedByMigration + groupViewHelper.isBlockedByMigration } var canEditConversationAttributes: Bool { - return groupViewHelper.canEditConversationAttributes + groupViewHelper.canEditConversationAttributes } var canEditConversationMembership: Bool { - return groupViewHelper.canEditConversationMembership + groupViewHelper.canEditConversationMembership } // Can local user edit group access. - var canEditConversationAccess: Bool { - return groupViewHelper.canEditConversationAccess + var canEditPermissions: Bool { + groupViewHelper.canEditPermissions } var isLocalUserFullMember: Bool { - return groupViewHelper.isLocalUserFullMember + groupViewHelper.isLocalUserFullMember } var isLocalUserFullOrInvitedMember: Bool { - return groupViewHelper.isLocalUserFullOrInvitedMember + groupViewHelper.isLocalUserFullOrInvitedMember } var isGroupThread: Bool { - return thread.isGroupThread + thread.isGroupThread } // MARK: - View Lifecycle diff --git a/Signal/src/ViewControllers/ThreadSettings/GroupPermissionsSettingsViewController.swift b/Signal/src/ViewControllers/ThreadSettings/GroupPermissionsSettingsViewController.swift index 8818bdb578..bc4f62717a 100644 --- a/Signal/src/ViewControllers/ThreadSettings/GroupPermissionsSettingsViewController.swift +++ b/Signal/src/ViewControllers/ThreadSettings/GroupPermissionsSettingsViewController.swift @@ -52,6 +52,10 @@ class GroupPermissionsSettingsViewController: OWSTableViewController2 { self.groupViewHelper.delegate = self + // We only show the "announcement-only" UI if all members of the + // group support this capability. If some members don't, fetch their + // profiles; perhaps they have the capability and we just don't know + // it yet. switch announcementOnlyMode { case .enabled: break @@ -108,9 +112,13 @@ class GroupPermissionsSettingsViewController: OWSTableViewController2 { } private var hasUnsavedChanges: Bool { - currentAccessMembers != accessMembers || + guard groupViewHelper.canEditPermissions else { + return false + } + + return (currentAccessMembers != accessMembers || currentAccessAttributes != accessAttributes || - currentIsAnnouncementsOnly != isAnnouncementsOnly + currentIsAnnouncementsOnly != isAnnouncementsOnly) } // Don't allow interactive dismiss when there are unsaved changes. @@ -144,10 +152,6 @@ class GroupPermissionsSettingsViewController: OWSTableViewController2 { let contents = OWSTableContents() defer { self.contents = contents } - guard groupViewHelper.canEditConversationAccess else { - return owsFailDebug("!canEditConversationAccess") - } - let accessMembersSection = OWSTableSection() accessMembersSection.headerTitle = NSLocalizedString( "CONVERSATION_SETTINGS_EDIT_MEMBERSHIP_ACCESS", @@ -164,10 +168,7 @@ class GroupPermissionsSettingsViewController: OWSTableViewController2 { comment: "Label for button that sets 'group attributes access' to 'members-only'." ), actionBlock: { [weak self] in - guard let self = self else { return } - self.accessMembers = .member - self.updateTableContents() - self.updateNavigation() + self?.tryToSetAccessMembers(.member) }, accessoryType: accessMembers == .member ? .checkmark : .none )) @@ -177,10 +178,7 @@ class GroupPermissionsSettingsViewController: OWSTableViewController2 { comment: "Label for button that sets 'group attributes access' to 'administrators-only'." ), actionBlock: { [weak self] in - guard let self = self else { return } - self.accessMembers = .administrator - self.updateTableContents() - self.updateNavigation() + self?.tryToSetAccessMembers(.administrator) }, accessoryType: accessMembers == .administrator ? .checkmark : .none )) @@ -203,10 +201,7 @@ class GroupPermissionsSettingsViewController: OWSTableViewController2 { comment: "Label for button that sets 'group attributes access' to 'members-only'." ), actionBlock: { [weak self] in - guard let self = self else { return } - self.accessAttributes = .member - self.updateTableContents() - self.updateNavigation() + self?.tryToSetAccessAttributes(.member) }, accessoryType: accessAttributes == .member ? .checkmark : .none )) @@ -216,17 +211,18 @@ class GroupPermissionsSettingsViewController: OWSTableViewController2 { comment: "Label for button that sets 'group attributes access' to 'administrators-only'." ), actionBlock: { [weak self] in - guard let self = self else { return } - self.accessAttributes = .administrator - self.updateTableContents() - self.updateNavigation() + self?.tryToSetAccessAttributes(.administrator) }, accessoryType: accessAttributes == .administrator ? .checkmark : .none )) contents.addSection(accessAttributesSection) - let canShowAnnouncementOnlyMode = announcementOnlyMode == .enabled + // Always show the announcements-only UI if that option is + // already enabled. If not, only show that UI if all group + // members support that capability. + let canShowAnnouncementOnlyMode = (announcementOnlyMode == .enabled || + isAnnouncementsOnly) if RemoteConfig.announcementOnlyGroups, canShowAnnouncementOnlyMode { let isAnnouncementsOnly = self.isAnnouncementsOnly @@ -247,10 +243,7 @@ class GroupPermissionsSettingsViewController: OWSTableViewController2 { comment: "Label for button that sets 'send messages permission' for a group to 'all members'." ), actionBlock: { [weak self] in - guard let self = self else { return } - self.isAnnouncementsOnly = false - self.updateTableContents() - self.updateNavigation() + self?.tryToSetIsAnnouncementsOnly(false) }, accessoryType: !isAnnouncementsOnly ? .checkmark : .none )) @@ -260,10 +253,7 @@ class GroupPermissionsSettingsViewController: OWSTableViewController2 { comment: "Label for button that sets 'send messages permission' for a group to 'administrators only'." ), actionBlock: { [weak self] in - guard let self = self else { return } - self.isAnnouncementsOnly = true - self.updateTableContents() - self.updateNavigation() + self?.tryToSetIsAnnouncementsOnly(true) }, accessoryType: isAnnouncementsOnly ? .checkmark : .none )) @@ -272,6 +262,43 @@ class GroupPermissionsSettingsViewController: OWSTableViewController2 { } } + private func tryToSetAccessMembers(_ value: GroupV2Access) { + guard groupViewHelper.canEditPermissions else { + showAdminOnlyWarningAlert() + return + } + self.accessMembers = value + self.updateTableContents() + self.updateNavigation() + } + + private func tryToSetAccessAttributes(_ value: GroupV2Access) { + guard groupViewHelper.canEditPermissions else { + showAdminOnlyWarningAlert() + return + } + self.accessAttributes = value + self.updateTableContents() + self.updateNavigation() + } + + private func tryToSetIsAnnouncementsOnly(_ value: Bool) { + guard groupViewHelper.canEditPermissions else { + showAdminOnlyWarningAlert() + return + } + isAnnouncementsOnly = value + updateTableContents() + updateNavigation() + } + + private func showAdminOnlyWarningAlert() { + let message = NSLocalizedString("GROUP_ADMIN_ONLY_WARNING", + comment: "Message indicating that a feature can only be used by group admins.") + presentToast(text: message) + updateTableContents() + } + private func reloadThreadAndUpdateContent() { let didUpdate = self.databaseStorage.read { transaction -> Bool in guard let newThread = TSThread.anyFetch( diff --git a/Signal/src/ViewControllers/ThreadSettings/GroupViewHelper.swift b/Signal/src/ViewControllers/ThreadSettings/GroupViewHelper.swift index c2e5edc485..60ffe2d03b 100644 --- a/Signal/src/ViewControllers/ThreadSettings/GroupViewHelper.swift +++ b/Signal/src/ViewControllers/ThreadSettings/GroupViewHelper.swift @@ -106,8 +106,8 @@ class GroupViewHelper: NSObject { } } - // Can local user edit group access. - var canEditConversationAccess: Bool { + // Can local user edit group access and message send permission. + var canEditPermissions: Bool { guard let groupThread = thread as? TSGroupThread else { return false }