Disable PNs for muted closed groups

This commit is contained in:
Niels Andriesse 2021-07-13 16:09:28 +10:00
parent 06a3eaad2d
commit aae11b1c28
5 changed files with 267 additions and 459 deletions

View File

@ -280,377 +280,284 @@ CGFloat kIconViewLength = 24;
__weak OWSConversationSettingsViewController *weakSelf = self; __weak OWSConversationSettingsViewController *weakSelf = self;
// Main section. OWSTableSection *section = [OWSTableSection new];
OWSTableSection *mainSection = [OWSTableSection new]; section.customHeaderView = [self mainSectionHeader];
section.customHeaderHeight = @(UITableViewAutomaticDimension);
mainSection.customHeaderView = [self mainSectionHeader];
mainSection.customHeaderHeight = @(UITableViewAutomaticDimension);
// Copy Session ID
if ([self.thread isKindOfClass:TSContactThread.class]) { if ([self.thread isKindOfClass:TSContactThread.class]) {
[mainSection addItem:[OWSTableItem [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
itemWithCustomCellBlock:^{ return [weakSelf
return [weakSelf disclosureCellWithName:NSLocalizedString(@"vc_conversation_settings_copy_session_id_button_title", "")
disclosureCellWithName:NSLocalizedString(@"vc_conversation_settings_copy_session_id_button_title", "") iconName:@"ic_copy"
iconName:@"ic_copy" accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(OWSConversationSettingsViewController, @"copy_session_id")];
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME( }
OWSConversationSettingsViewController, @"copy_session_id")]; actionBlock:^{
} [weakSelf copySessionID];
actionBlock:^{ }]];
[weakSelf copySessionID];
}]];
} }
[mainSection addItem:[OWSTableItem // All media
itemWithCustomCellBlock:^{ [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
return [weakSelf return [weakSelf
disclosureCellWithName:MediaStrings.allMedia disclosureCellWithName:MediaStrings.allMedia
iconName:@"actionsheet_camera_roll_black" iconName:@"actionsheet_camera_roll_black"
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME( accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(OWSConversationSettingsViewController, @"all_media")];
OWSConversationSettingsViewController, @"all_media")]; } actionBlock:^{
} [weakSelf showMediaGallery];
actionBlock:^{ }]];
[weakSelf showMediaGallery];
}]];
// Invite button
if (self.isOpenGroup) { if (self.isOpenGroup) {
[mainSection addItem:[OWSTableItem [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
itemWithCustomCellBlock:^{ return [weakSelf
return [weakSelf disclosureCellWithName:NSLocalizedString(@"vc_conversation_settings_invite_button_title", "")
disclosureCellWithName:NSLocalizedString(@"vc_conversation_settings_invite_button_title", "") iconName:@"ic_plus_24"
iconName:@"ic_plus_24" accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(OWSConversationSettingsViewController, @"invite")];
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME( } actionBlock:^{
OWSConversationSettingsViewController, @"invite")]; [weakSelf inviteUsersToOpenGroup];
} }]];
actionBlock:^{
[weakSelf inviteUsersToOpenGroup];
}]];
} }
[mainSection addItem:[OWSTableItem // Search
itemWithCustomCellBlock:^{ [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
NSString *title = NSLocalizedString(@"CONVERSATION_SETTINGS_SEARCH", NSString *title = NSLocalizedString(@"CONVERSATION_SETTINGS_SEARCH",
@"Table cell label in conversation settings which returns the user to the " @"Table cell label in conversation settings which returns the user to the "
@"conversation with 'search mode' activated"); @"conversation with 'search mode' activated");
return [weakSelf return [weakSelf
disclosureCellWithName:title disclosureCellWithName:title
iconName:@"conversation_settings_search" iconName:@"conversation_settings_search"
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME( accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(OWSConversationSettingsViewController, @"search")];
OWSConversationSettingsViewController, @"search")]; } actionBlock:^{
} [weakSelf tappedConversationSearch];
actionBlock:^{ }]];
[weakSelf tappedConversationSearch];
}]];
// Disappearing messages
if (![self isOpenGroup]) { if (![self isOpenGroup]) {
[mainSection addItem:[OWSTableItem [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
itemWithCustomCellBlock:^{ UITableViewCell *cell = [OWSTableItem newCell];
UITableViewCell *cell = [OWSTableItem newCell]; OWSConversationSettingsViewController *strongSelf = weakSelf;
OWSConversationSettingsViewController *strongSelf = weakSelf; OWSCAssertDebug(strongSelf);
OWSCAssertDebug(strongSelf); cell.preservesSuperviewLayoutMargins = YES;
cell.preservesSuperviewLayoutMargins = YES; cell.contentView.preservesSuperviewLayoutMargins = YES;
cell.contentView.preservesSuperviewLayoutMargins = YES; cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
NSString *iconName NSString *iconName
= (strongSelf.disappearingMessagesConfiguration.isEnabled ? @"ic_timer" = (strongSelf.disappearingMessagesConfiguration.isEnabled ? @"ic_timer" : @"ic_timer_disabled");
: @"ic_timer_disabled"); UIImageView *iconView = [strongSelf viewForIconWithName:iconName];
UIImageView *iconView = [strongSelf viewForIconWithName:iconName];
UILabel *rowLabel = [UILabel new]; UILabel *rowLabel = [UILabel new];
rowLabel.text = NSLocalizedString( rowLabel.text = NSLocalizedString(
@"DISAPPEARING_MESSAGES", @"table cell label in conversation settings"); @"DISAPPEARING_MESSAGES", @"table cell label in conversation settings");
rowLabel.textColor = LKColors.text; rowLabel.textColor = LKColors.text;
rowLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize]; rowLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize];
rowLabel.lineBreakMode = NSLineBreakByTruncatingTail; rowLabel.lineBreakMode = NSLineBreakByTruncatingTail;
UISwitch *switchView = [UISwitch new]; UISwitch *switchView = [UISwitch new];
switchView.on = strongSelf.disappearingMessagesConfiguration.isEnabled; switchView.on = strongSelf.disappearingMessagesConfiguration.isEnabled;
[switchView addTarget:strongSelf [switchView addTarget:strongSelf action:@selector(disappearingMessagesSwitchValueDidChange:)
action:@selector(disappearingMessagesSwitchValueDidChange:) forControlEvents:UIControlEventValueChanged];
forControlEvents:UIControlEventValueChanged];
UIStackView *topRow = UIStackView *topRow =
[[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel, switchView ]]; [[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel, switchView ]];
topRow.spacing = strongSelf.iconSpacing; topRow.spacing = strongSelf.iconSpacing;
topRow.alignment = UIStackViewAlignmentCenter; topRow.alignment = UIStackViewAlignmentCenter;
[cell.contentView addSubview:topRow]; [cell.contentView addSubview:topRow];
[topRow autoPinEdgesToSuperviewMarginsExcludingEdge:ALEdgeBottom]; [topRow autoPinEdgesToSuperviewMarginsExcludingEdge:ALEdgeBottom];
UILabel *subtitleLabel = [UILabel new]; UILabel *subtitleLabel = [UILabel new];
NSString *displayName; NSString *displayName;
if (self.thread.isGroupThread) { if (self.thread.isGroupThread) {
displayName = @"the group"; displayName = @"the group";
} else { } else {
TSContactThread *thread = (TSContactThread *)self.thread; TSContactThread *thread = (TSContactThread *)self.thread;
displayName = [[LKStorage.shared getContactWithSessionID:thread.contactSessionID] displayNameFor:SNContactContextRegular] ?: @"anonymous"; displayName = [[LKStorage.shared getContactWithSessionID:thread.contactSessionID] displayNameFor:SNContactContextRegular] ?: @"anonymous";
} }
subtitleLabel.text = [NSString stringWithFormat:NSLocalizedString(@"When enabled, messages between you and %@ will disappear after they have been seen.", ""), displayName]; subtitleLabel.text = [NSString stringWithFormat:NSLocalizedString(@"When enabled, messages between you and %@ will disappear after they have been seen.", ""), displayName];
subtitleLabel.textColor = LKColors.text; subtitleLabel.textColor = LKColors.text;
subtitleLabel.font = [UIFont systemFontOfSize:LKValues.smallFontSize]; subtitleLabel.font = [UIFont systemFontOfSize:LKValues.smallFontSize];
subtitleLabel.numberOfLines = 0; subtitleLabel.numberOfLines = 0;
subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping; subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping;
[cell.contentView addSubview:subtitleLabel]; [cell.contentView addSubview:subtitleLabel];
[subtitleLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:topRow withOffset:8]; [subtitleLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:topRow withOffset:8];
[subtitleLabel autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:rowLabel]; [subtitleLabel autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:rowLabel];
[subtitleLabel autoPinTrailingToSuperviewMargin]; [subtitleLabel autoPinTrailingToSuperviewMargin];
[subtitleLabel autoPinBottomToSuperviewMargin]; [subtitleLabel autoPinBottomToSuperviewMargin];
cell.userInteractionEnabled = !strongSelf.hasLeftGroup; cell.userInteractionEnabled = !strongSelf.hasLeftGroup;
cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME( cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME(OWSConversationSettingsViewController, @"disappearing_messages");
OWSConversationSettingsViewController, @"disappearing_messages");
return cell; return cell;
} } customRowHeight:UITableViewAutomaticDimension actionBlock:nil]];
customRowHeight:UITableViewAutomaticDimension
actionBlock:nil]];
if (self.disappearingMessagesConfiguration.isEnabled) { if (self.disappearingMessagesConfiguration.isEnabled) {
[mainSection [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
addItem:[OWSTableItem UITableViewCell *cell = [OWSTableItem newCell];
itemWithCustomCellBlock:^{ OWSConversationSettingsViewController *strongSelf = weakSelf;
UITableViewCell *cell = [OWSTableItem newCell]; OWSCAssertDebug(strongSelf);
OWSConversationSettingsViewController *strongSelf = weakSelf; cell.preservesSuperviewLayoutMargins = YES;
OWSCAssertDebug(strongSelf); cell.contentView.preservesSuperviewLayoutMargins = YES;
cell.preservesSuperviewLayoutMargins = YES; cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.contentView.preservesSuperviewLayoutMargins = YES;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UIImageView *iconView = [strongSelf viewForIconWithName:@"ic_timer"]; UIImageView *iconView = [strongSelf viewForIconWithName:@"ic_timer"];
UILabel *rowLabel = strongSelf.disappearingMessagesDurationLabel; UILabel *rowLabel = strongSelf.disappearingMessagesDurationLabel;
[strongSelf updateDisappearingMessagesDurationLabel]; [strongSelf updateDisappearingMessagesDurationLabel];
rowLabel.textColor = LKColors.text; rowLabel.textColor = LKColors.text;
rowLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize]; rowLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize];
// don't truncate useful duration info which is in the tail // don't truncate useful duration info which is in the tail
rowLabel.lineBreakMode = NSLineBreakByTruncatingHead; rowLabel.lineBreakMode = NSLineBreakByTruncatingHead;
UIStackView *topRow = UIStackView *topRow =
[[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel ]]; [[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel ]];
topRow.spacing = strongSelf.iconSpacing; topRow.spacing = strongSelf.iconSpacing;
topRow.alignment = UIStackViewAlignmentCenter; topRow.alignment = UIStackViewAlignmentCenter;
[cell.contentView addSubview:topRow]; [cell.contentView addSubview:topRow];
[topRow autoPinEdgesToSuperviewMarginsExcludingEdge:ALEdgeBottom]; [topRow autoPinEdgesToSuperviewMarginsExcludingEdge:ALEdgeBottom];
UISlider *slider = [UISlider new]; UISlider *slider = [UISlider new];
slider.maximumValue = (float)(strongSelf.disappearingMessagesDurations.count - 1); slider.maximumValue = (float)(strongSelf.disappearingMessagesDurations.count - 1);
slider.minimumValue = 0; slider.minimumValue = 0;
slider.tintColor = LKColors.accent; slider.tintColor = LKColors.accent;
slider.continuous = NO; slider.continuous = NO;
slider.value = strongSelf.disappearingMessagesConfiguration.durationIndex; slider.value = strongSelf.disappearingMessagesConfiguration.durationIndex;
[slider addTarget:strongSelf [slider addTarget:strongSelf action:@selector(durationSliderDidChange:)
action:@selector(durationSliderDidChange:) forControlEvents:UIControlEventValueChanged];
forControlEvents:UIControlEventValueChanged]; [cell.contentView addSubview:slider];
[cell.contentView addSubview:slider]; [slider autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:topRow withOffset:6];
[slider autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:topRow withOffset:6]; [slider autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:rowLabel];
[slider autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:rowLabel]; [slider autoPinTrailingToSuperviewMargin];
[slider autoPinTrailingToSuperviewMargin]; [slider autoPinBottomToSuperviewMargin];
[slider autoPinBottomToSuperviewMargin];
cell.userInteractionEnabled = !strongSelf.hasLeftGroup; cell.userInteractionEnabled = !strongSelf.hasLeftGroup;
cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME( cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME(
OWSConversationSettingsViewController, @"disappearing_messages_duration"); OWSConversationSettingsViewController, @"disappearing_messages_duration");
return cell; return cell;
} } customRowHeight:UITableViewAutomaticDimension actionBlock:nil]];
customRowHeight:UITableViewAutomaticDimension
actionBlock:nil]];
} }
} }
[contents addSection:mainSection]; [contents addSection:section];
// Group settings section.
// Closed group settings
__block BOOL isUserMember = NO; __block BOOL isUserMember = NO;
if (self.isGroupThread) { if (self.isGroupThread) {
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey]; NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
isUserMember = [(TSGroupThread *)self.thread isUserMemberInGroup:userPublicKey]; isUserMember = [(TSGroupThread *)self.thread isUserMemberInGroup:userPublicKey];
} }
if (self.isGroupThread && self.isClosedGroup && isUserMember) { if (self.isGroupThread && self.isClosedGroup && isUserMember) {
if (((TSGroupThread *)self.thread).isClosedGroup) { [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
[mainSection addItem:[OWSTableItem UITableViewCell *cell =
itemWithCustomCellBlock:^{ [weakSelf disclosureCellWithName:NSLocalizedString(@"EDIT_GROUP_ACTION", @"table cell label in conversation settings")
UITableViewCell *cell = iconName:@"table_ic_group_edit"
[weakSelf disclosureCellWithName:NSLocalizedString(@"EDIT_GROUP_ACTION", accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(OWSConversationSettingsViewController, @"edit_group")];
@"table cell label in conversation settings") cell.userInteractionEnabled = !weakSelf.hasLeftGroup;
iconName:@"table_ic_group_edit" return cell;
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME( } actionBlock:^{
OWSConversationSettingsViewController, @"edit_group")]; [weakSelf editGroup];
cell.userInteractionEnabled = !weakSelf.hasLeftGroup; }]];
return cell; [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
} UITableViewCell *cell =
actionBlock:^{ [weakSelf disclosureCellWithName:NSLocalizedString(@"LEAVE_GROUP_ACTION", @"table cell label in conversation settings")
[weakSelf editGroup]; iconName:@"table_ic_group_leave"
}] accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(OWSConversationSettingsViewController, @"leave_group")];
]; cell.userInteractionEnabled = !weakSelf.hasLeftGroup;
}
[mainSection addItem:[OWSTableItem
itemWithCustomCellBlock:^{
UITableViewCell *cell =
[weakSelf disclosureCellWithName:NSLocalizedString(@"LEAVE_GROUP_ACTION",
@"table cell label in conversation settings")
iconName:@"table_ic_group_leave"
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(
OWSConversationSettingsViewController, @"leave_group")];
cell.userInteractionEnabled = !weakSelf.hasLeftGroup;
return cell; return cell;
} } actionBlock:^{
actionBlock:^{ [weakSelf didTapLeaveGroup];
[weakSelf didTapLeaveGroup]; }]];
}]
];
} }
// Mute thread section.
if (!isNoteToSelf) { if (!isNoteToSelf) {
[mainSection // Notification sound
addItem:[OWSTableItem [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
itemWithCustomCellBlock:^{ UITableViewCell *cell =
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil]; [OWSTableItem configureCell:cell];
[OWSTableItem configureCell:cell]; OWSConversationSettingsViewController *strongSelf = weakSelf;
OWSConversationSettingsViewController *strongSelf = weakSelf; OWSCAssertDebug(strongSelf);
OWSCAssertDebug(strongSelf); cell.preservesSuperviewLayoutMargins = YES;
cell.preservesSuperviewLayoutMargins = YES; cell.contentView.preservesSuperviewLayoutMargins = YES;
cell.contentView.preservesSuperviewLayoutMargins = YES;
UIImageView *iconView = [strongSelf viewForIconWithName:@"table_ic_notification_sound"]; UIImageView *iconView = [strongSelf viewForIconWithName:@"table_ic_notification_sound"];
UILabel *rowLabel = [UILabel new]; UILabel *rowLabel = [UILabel new];
rowLabel.text = NSLocalizedString(@"SETTINGS_ITEM_NOTIFICATION_SOUND", rowLabel.text = NSLocalizedString(@"SETTINGS_ITEM_NOTIFICATION_SOUND",
@"Label for settings view that allows user to change the notification sound."); @"Label for settings view that allows user to change the notification sound.");
rowLabel.textColor = LKColors.text; rowLabel.textColor = LKColors.text;
rowLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize]; rowLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize];
rowLabel.lineBreakMode = NSLineBreakByTruncatingTail; rowLabel.lineBreakMode = NSLineBreakByTruncatingTail;
UIStackView *contentRow = UIStackView *contentRow =
[[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel ]]; [[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel ]];
contentRow.spacing = strongSelf.iconSpacing; contentRow.spacing = strongSelf.iconSpacing;
contentRow.alignment = UIStackViewAlignmentCenter; contentRow.alignment = UIStackViewAlignmentCenter;
[cell.contentView addSubview:contentRow]; [cell.contentView addSubview:contentRow];
[contentRow autoPinEdgesToSuperviewMargins]; [contentRow autoPinEdgesToSuperviewMargins];
OWSSound sound = [OWSSounds notificationSoundForThread:strongSelf.thread]; OWSSound sound = [OWSSounds notificationSoundForThread:strongSelf.thread];
cell.detailTextLabel.text = [OWSSounds displayNameForSound:sound]; cell.detailTextLabel.text = [OWSSounds displayNameForSound:sound];
cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME( cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME(
OWSConversationSettingsViewController, @"notifications"); OWSConversationSettingsViewController, @"notifications");
return cell; return cell;
} }
customRowHeight:UITableViewAutomaticDimension customRowHeight:UITableViewAutomaticDimension
actionBlock:^{ actionBlock:^{
OWSSoundSettingsViewController *vc = [OWSSoundSettingsViewController new]; OWSSoundSettingsViewController *vc = [OWSSoundSettingsViewController new];
vc.thread = weakSelf.thread; vc.thread = weakSelf.thread;
[weakSelf.navigationController pushViewController:vc animated:YES]; [weakSelf.navigationController pushViewController:vc animated:YES];
}]]; }]];
[mainSection
addItem: // Mute thread
[OWSTableItem [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
itemWithCustomCellBlock:^{ OWSConversationSettingsViewController *strongSelf = weakSelf;
UITableViewCell *cell = if (!strongSelf) { return [UITableViewCell new]; }
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
[OWSTableItem configureCell:cell];
OWSConversationSettingsViewController *strongSelf = weakSelf;
OWSCAssertDebug(strongSelf);
cell.preservesSuperviewLayoutMargins = YES;
cell.contentView.preservesSuperviewLayoutMargins = YES;
UIImageView *iconView = [strongSelf viewForIconWithName:@"Mute"]; NSString *cellTitle = NSLocalizedString(@"CONVERSATION_SETTINGS_MUTE_LABEL", @"label for 'mute thread' cell in conversation settings");
UITableViewCell *cell = [strongSelf disclosureCellWithName:cellTitle iconName:@"Mute"
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(OWSConversationSettingsViewController, @"mute")];
UILabel *rowLabel = [UILabel new]; cell.selectionStyle = UITableViewCellSelectionStyleNone;
rowLabel.text = NSLocalizedString(@"CONVERSATION_SETTINGS_MUTE_LABEL",
@"label for 'mute thread' cell in conversation settings");
rowLabel.textColor = LKColors.text;
rowLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize];
rowLabel.lineBreakMode = NSLineBreakByTruncatingTail;
NSString *muteStatus = NSLocalizedString(@"CONVERSATION_SETTINGS_MUTE_NOT_MUTED", UISwitch *muteConversationSwitch = [UISwitch new];
@"Indicates that the current thread is not muted."); NSDate *mutedUntilDate = strongSelf.thread.mutedUntilDate;
NSDate *mutedUntilDate = strongSelf.thread.mutedUntilDate; NSDate *now = [NSDate date];
NSDate *now = [NSDate date]; muteConversationSwitch.on = (mutedUntilDate != nil && [mutedUntilDate timeIntervalSinceDate:now] > 0);
if (mutedUntilDate != nil && [mutedUntilDate timeIntervalSinceDate:now] > 0) { [muteConversationSwitch addTarget:strongSelf action:@selector(handleMuteSwitchToggled:)
NSCalendar *calendar = [NSCalendar currentCalendar]; forControlEvents:UIControlEventValueChanged];
NSCalendarUnit calendarUnits = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay; cell.accessoryView = muteConversationSwitch;
NSDateComponents *muteUntilComponents =
[calendar components:calendarUnits fromDate:mutedUntilDate];
NSDateComponents *nowComponents = [calendar components:calendarUnits fromDate:now];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
if (nowComponents.year != muteUntilComponents.year
|| nowComponents.month != muteUntilComponents.month
|| nowComponents.day != muteUntilComponents.day) {
[dateFormatter setDateStyle:NSDateFormatterShortStyle]; return cell;
[dateFormatter setTimeStyle:NSDateFormatterShortStyle]; } actionBlock:nil]];
} else {
[dateFormatter setDateStyle:NSDateFormatterNoStyle];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
}
muteStatus = [NSString
stringWithFormat:NSLocalizedString(@"CONVERSATION_SETTINGS_MUTED_UNTIL_FORMAT",
@"Indicates that this thread is muted until a given date or time. "
@"Embeds {{The date or time which the thread is muted until}}."),
[dateFormatter stringFromDate:mutedUntilDate]];
}
UIStackView *contentRow =
[[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel ]];
contentRow.spacing = strongSelf.iconSpacing;
contentRow.alignment = UIStackViewAlignmentCenter;
[cell.contentView addSubview:contentRow];
[contentRow autoPinEdgesToSuperviewMargins];
cell.detailTextLabel.text = muteStatus;
cell.accessibilityIdentifier
= ACCESSIBILITY_IDENTIFIER_WITH_NAME(OWSConversationSettingsViewController, @"mute");
return cell;
}
customRowHeight:UITableViewAutomaticDimension
actionBlock:^{
[weakSelf showMuteUnmuteActionSheet];
}]];
} }
// Block Conversation section.
// Block contact
if (!isNoteToSelf && [self.thread isKindOfClass:TSContactThread.class]) { if (!isNoteToSelf && [self.thread isKindOfClass:TSContactThread.class]) {
[mainSection addItem:[OWSTableItem [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
itemWithCustomCellBlock:^{ OWSConversationSettingsViewController *strongSelf = weakSelf;
OWSConversationSettingsViewController *strongSelf = weakSelf; if (!strongSelf) { return [UITableViewCell new]; }
if (!strongSelf) {
return [UITableViewCell new];
}
NSString *cellTitle = NSLocalizedString(@"CONVERSATION_SETTINGS_BLOCK_THIS_USER", NSString *cellTitle = NSLocalizedString(@"CONVERSATION_SETTINGS_BLOCK_THIS_USER", @"table cell label in conversation settings");
@"table cell label in conversation settings"); UITableViewCell *cell = [strongSelf disclosureCellWithName:cellTitle iconName:@"table_ic_block"
UITableViewCell *cell = [strongSelf accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(OWSConversationSettingsViewController, @"block")];
disclosureCellWithName:cellTitle
iconName:@"table_ic_block"
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(
OWSConversationSettingsViewController, @"block")];
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
UISwitch *blockConversationSwitch = [UISwitch new]; UISwitch *blockConversationSwitch = [UISwitch new];
blockConversationSwitch.on = blockConversationSwitch.on = [strongSelf.blockingManager isThreadBlocked:strongSelf.thread];
[strongSelf.blockingManager isThreadBlocked:strongSelf.thread]; [blockConversationSwitch addTarget:strongSelf action:@selector(blockConversationSwitchDidChange:)
[blockConversationSwitch addTarget:strongSelf forControlEvents:UIControlEventValueChanged];
action:@selector(blockConversationSwitchDidChange:) cell.accessoryView = blockConversationSwitch;
forControlEvents:UIControlEventValueChanged];
cell.accessoryView = blockConversationSwitch;
return cell; return cell;
} } actionBlock:nil]];
actionBlock:nil]];
} }
self.contents = contents; self.contents = contents;
@ -892,6 +799,31 @@ CGFloat kIconViewLength = 24;
[self updateTableContents]; [self updateTableContents];
} }
- (void)handleMuteSwitchToggled:(id)sender
{
UISwitch *uiSwitch = (UISwitch *)sender;
if (uiSwitch.isOn) {
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self.thread updateWithMutedUntilDate:[NSDate distantFuture] transaction:transaction];
}];
} else {
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self.thread updateWithMutedUntilDate:nil transaction:transaction];
}];
}
if (self.isClosedGroup) {
NSString *groupPublicKey = [LKGroupUtilities getDecodedGroupID:((TSGroupThread *)self.thread).groupModel.groupId];
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
if (uiSwitch.isOn) {
[[LKPushNotificationAPI performOperation:ClosedGroupOperationUnsubscribe
forClosedGroupWithPublicKey:groupPublicKey userPublicKey:userPublicKey] retainUntilComplete];
} else {
[[LKPushNotificationAPI performOperation:ClosedGroupOperationSubscribe
forClosedGroupWithPublicKey:groupPublicKey userPublicKey:userPublicKey] retainUntilComplete];
}
}
}
- (void)blockConversationSwitchDidChange:(id)sender - (void)blockConversationSwitchDidChange:(id)sender
{ {
if (![sender isKindOfClass:[UISwitch class]]) { if (![sender isKindOfClass:[UISwitch class]]) {
@ -967,137 +899,6 @@ CGFloat kIconViewLength = 24;
[self.disappearingMessagesDurationLabel.superview setNeedsLayout]; [self.disappearingMessagesDurationLabel.superview setNeedsLayout];
} }
- (void)showMuteUnmuteActionSheet
{
// The "unmute" action sheet has no title or message; the
// action label speaks for itself.
NSString *title = nil;
NSString *message = nil;
if (!self.thread.isMuted) {
title = NSLocalizedString(
@"CONVERSATION_SETTINGS_MUTE_ACTION_SHEET_TITLE", @"Title of the 'mute this thread' action sheet.");
message = NSLocalizedString(
@"MUTE_BEHAVIOR_EXPLANATION", @"An explanation of the consequences of muting a thread.");
}
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleActionSheet];
__weak OWSConversationSettingsViewController *weakSelf = self;
if (self.thread.isMuted) {
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"CONVERSATION_SETTINGS_UNMUTE_ACTION",
@"Label for button to unmute a thread.")
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"unmute")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull ignore) {
[weakSelf setThreadMutedUntilDate:nil];
}];
[actionSheet addAction:action];
} else {
#ifdef DEBUG
[actionSheet
addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"CONVERSATION_SETTINGS_MUTE_ONE_MINUTE_ACTION",
@"Label for button to mute a thread for a minute.")
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"mute_1_minute")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull ignore) {
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:timeZone];
NSDateComponents *dateComponents = [NSDateComponents new];
[dateComponents setMinute:1];
NSDate *mutedUntilDate =
[calendar dateByAddingComponents:dateComponents
toDate:[NSDate date]
options:0];
[weakSelf setThreadMutedUntilDate:mutedUntilDate];
}]];
#endif
[actionSheet
addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"CONVERSATION_SETTINGS_MUTE_ONE_HOUR_ACTION",
@"Label for button to mute a thread for a hour.")
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"mute_1_hour")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull ignore) {
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:timeZone];
NSDateComponents *dateComponents = [NSDateComponents new];
[dateComponents setHour:1];
NSDate *mutedUntilDate =
[calendar dateByAddingComponents:dateComponents
toDate:[NSDate date]
options:0];
[weakSelf setThreadMutedUntilDate:mutedUntilDate];
}]];
[actionSheet
addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"CONVERSATION_SETTINGS_MUTE_ONE_DAY_ACTION",
@"Label for button to mute a thread for a day.")
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"mute_1_day")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull ignore) {
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:timeZone];
NSDateComponents *dateComponents = [NSDateComponents new];
[dateComponents setDay:1];
NSDate *mutedUntilDate =
[calendar dateByAddingComponents:dateComponents
toDate:[NSDate date]
options:0];
[weakSelf setThreadMutedUntilDate:mutedUntilDate];
}]];
[actionSheet
addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"CONVERSATION_SETTINGS_MUTE_ONE_WEEK_ACTION",
@"Label for button to mute a thread for a week.")
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"mute_1_week")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull ignore) {
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:timeZone];
NSDateComponents *dateComponents = [NSDateComponents new];
[dateComponents setDay:7];
NSDate *mutedUntilDate =
[calendar dateByAddingComponents:dateComponents
toDate:[NSDate date]
options:0];
[weakSelf setThreadMutedUntilDate:mutedUntilDate];
}]];
[actionSheet
addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"CONVERSATION_SETTINGS_MUTE_ONE_YEAR_ACTION",
@"Label for button to mute a thread for a year.")
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"mute_1_year")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull ignore) {
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:timeZone];
NSDateComponents *dateComponents = [NSDateComponents new];
[dateComponents setYear:1];
NSDate *mutedUntilDate =
[calendar dateByAddingComponents:dateComponents
toDate:[NSDate date]
options:0];
[weakSelf setThreadMutedUntilDate:mutedUntilDate];
}]];
}
[actionSheet addAction:[OWSAlerts cancelAction]];
[self presentAlert:actionSheet];
}
- (void)setThreadMutedUntilDate:(nullable NSDate *)value
{
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
[self.thread updateWithMutedUntilDate:value transaction:transaction];
}];
[self updateTableContents];
}
- (void)copySessionID - (void)copySessionID
{ {
UIPasteboard.generalPasteboard.string = ((TSContactThread *)self.thread).contactSessionID; UIPasteboard.generalPasteboard.string = ((TSContactThread *)self.thread).contactSessionID;

View File

@ -86,14 +86,10 @@ final class ConversationTitleView : UIView {
} }
private func getSubtitle() -> NSAttributedString? { private func getSubtitle() -> NSAttributedString? {
if let muteEndDate = thread.mutedUntilDate, thread.isMuted { if thread.isMuted {
let result = NSMutableAttributedString() let result = NSMutableAttributedString()
result.append(NSAttributedString(string: "\u{e067} ", attributes: [ .font : UIFont.ows_elegantIconsFont(10), .foregroundColor : Colors.text ])) result.append(NSAttributedString(string: "\u{e067} ", attributes: [ .font : UIFont.ows_elegantIconsFont(10), .foregroundColor : Colors.text ]))
let formatter = DateFormatter() result.append(NSAttributedString(string: "Muted"))
formatter.locale = Locale.current
formatter.timeStyle = .medium
formatter.dateStyle = .medium
result.append(NSAttributedString(string: "Muted until " + formatter.string(from: muteEndDate)))
return result return result
} else if let thread = self.thread as? TSGroupThread { } else if let thread = self.thread as? TSGroupThread {
var userCount: UInt64? var userCount: UInt64?
@ -118,7 +114,7 @@ final class ConversationTitleView : UIView {
} }
// MARK: Delegate // MARK: Delegate
protocol ConversationTitleViewDelegate : class { protocol ConversationTitleViewDelegate : AnyObject {
func handleTitleViewTapped() func handleTitleViewTapped()
} }

View File

@ -10,9 +10,15 @@ public final class PushNotificationAPI : NSObject {
private static let maxRetryCount: UInt = 4 private static let maxRetryCount: UInt = 4
private static let tokenExpirationInterval: TimeInterval = 12 * 60 * 60 private static let tokenExpirationInterval: TimeInterval = 12 * 60 * 60
public enum ClosedGroupOperation: String { @objc public enum ClosedGroupOperation : Int {
case subscribe = "subscribe_closed_group" case subscribe, unsubscribe
case unsubscribe = "unsubscribe_closed_group"
public var endpoint: String {
switch self {
case .subscribe: return "subscribe_closed_group"
case .unsubscribe: return "unsubscribe_closed_group"
}
}
} }
// MARK: Initialization // MARK: Initialization
@ -97,13 +103,13 @@ public final class PushNotificationAPI : NSObject {
let isUsingFullAPNs = UserDefaults.standard[.isUsingFullAPNs] let isUsingFullAPNs = UserDefaults.standard[.isUsingFullAPNs]
guard isUsingFullAPNs else { return Promise<Void> { $0.fulfill(()) } } guard isUsingFullAPNs else { return Promise<Void> { $0.fulfill(()) } }
let parameters = [ "closedGroupPublicKey" : closedGroupPublicKey, "pubKey" : publicKey ] let parameters = [ "closedGroupPublicKey" : closedGroupPublicKey, "pubKey" : publicKey ]
let url = URL(string: "\(server)/\(operation.rawValue)")! let url = URL(string: "\(server)/\(operation.endpoint)")!
let request = TSRequest(url: url, method: "POST", parameters: parameters) let request = TSRequest(url: url, method: "POST", parameters: parameters)
request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ] request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ]
let promise: Promise<Void> = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) { let promise: Promise<Void> = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) {
OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in
guard let json = response["body"] as? JSON else { guard let json = response["body"] as? JSON else {
return SNLog("Couldn't subscribe/unsubscribe closed group: \(closedGroupPublicKey).") return SNLog("Couldn't subscribe/unsubscribe for closed group: \(closedGroupPublicKey).")
} }
guard json["code"] as? Int != 0 else { guard json["code"] as? Int != 0 else {
return SNLog("Couldn't subscribe/unsubscribe for closed group: \(closedGroupPublicKey) due to error: \(json["message"] as? String ?? "nil").") return SNLog("Couldn't subscribe/unsubscribe for closed group: \(closedGroupPublicKey) due to error: \(json["message"] as? String ?? "nil").")
@ -111,8 +117,13 @@ public final class PushNotificationAPI : NSObject {
} }
} }
promise.catch2 { error in promise.catch2 { error in
SNLog("Couldn't subscribe/unsubscribe closed group: \(closedGroupPublicKey).") SNLog("Couldn't subscribe/unsubscribe for closed group: \(closedGroupPublicKey).")
} }
return promise return promise
} }
@objc(performOperation:forClosedGroupWithPublicKey:userPublicKey:)
public static func objc_performOperation(_ operation: ClosedGroupOperation, for closedGroupPublicKey: String, publicKey: String) -> AnyPromise {
return AnyPromise.from(performOperation(operation, for: closedGroupPublicKey, publicKey: publicKey))
}
} }

View File

@ -111,7 +111,7 @@ BOOL IsNoteToSelfEnabled(void);
#pragma mark Muting #pragma mark Muting
- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate transaction:(YapDatabaseReadWriteTransaction *)transaction; - (void)updateWithMutedUntilDate:(NSDate * _Nullable)mutedUntilDate transaction:(YapDatabaseReadWriteTransaction *)transaction;
@end @end

View File

@ -376,7 +376,7 @@ BOOL IsNoteToSelfEnabled(void)
return (mutedUntilDate != nil && [mutedUntilDate timeIntervalSinceDate:now] > 0); return (mutedUntilDate != nil && [mutedUntilDate timeIntervalSinceDate:now] > 0);
} }
- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate transaction:(YapDatabaseReadWriteTransaction *)transaction - (void)updateWithMutedUntilDate:(NSDate * _Nullable)mutedUntilDate transaction:(YapDatabaseReadWriteTransaction *)transaction
{ {
[self applyChangeToSelfAndLatestCopy:transaction [self applyChangeToSelfAndLatestCopy:transaction
changeBlock:^(TSThread *thread) { changeBlock:^(TSThread *thread) {