|  |  |  | // | 
					
						
							|  |  |  | //  Copyright (c) 2018 Open Whisper Systems. All rights reserved. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #import "TSGroupModel.h" | 
					
						
							|  |  |  | #import <SessionMessagingKit/SessionMessagingKit-Swift.h> | 
					
						
							|  |  |  | #import <SignalCoreKit/NSString+OWS.h> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NS_ASSUME_NONNULL_BEGIN | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const int32_t kGroupIdLength = 16; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @interface TSGroupModel () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @property (nullable, nonatomic) NSString *groupName; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark - | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @implementation TSGroupModel | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (nullable NSString *)groupName | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return _groupName.filterStringForDisplay; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if TARGET_OS_IOS | 
					
						
							|  |  |  | - (instancetype)initWithTitle:(nullable NSString *)title | 
					
						
							|  |  |  |                     memberIds:(NSArray<NSString *> *)memberIds | 
					
						
							|  |  |  |                         image:(nullable UIImage *)image | 
					
						
							|  |  |  |                       groupId:(NSData *)groupId | 
					
						
							|  |  |  |                     groupType:(GroupType)groupType | 
					
						
							|  |  |  |                      adminIds:(NSArray<NSString *> *)adminIds | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _groupName              = title; | 
					
						
							|  |  |  |     _groupMemberIds         = [memberIds copy]; | 
					
						
							|  |  |  |     _groupImage             = image; | 
					
						
							|  |  |  |     _groupType              = groupType; | 
					
						
							|  |  |  |     _groupId                = groupId; | 
					
						
							|  |  |  |     _groupAdminIds          = [adminIds copy]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return self; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (nullable instancetype)initWithCoder:(NSCoder *)coder | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     self = [super initWithCoder:coder]; | 
					
						
							|  |  |  |     if (!self) { | 
					
						
							|  |  |  |         return self; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Occasionally seeing this as nil in legacy data, | 
					
						
							|  |  |  |     // which causes crashes. | 
					
						
							|  |  |  |     if (_groupMemberIds == nil) { | 
					
						
							|  |  |  |         _groupMemberIds = [NSArray new]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (_groupAdminIds == nil) { | 
					
						
							|  |  |  |         _groupAdminIds = [NSArray new]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return self; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (BOOL)isEqual:(id)other { | 
					
						
							|  |  |  |     if (other == self) { | 
					
						
							|  |  |  |         return YES; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!other || ![other isKindOfClass:[self class]]) { | 
					
						
							|  |  |  |         return NO; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return [self isEqualToGroupModel:other]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (BOOL)isEqualToGroupModel:(TSGroupModel *)other { | 
					
						
							|  |  |  |     if (self == other) | 
					
						
							|  |  |  |         return YES; | 
					
						
							|  |  |  |     if (![_groupId isEqualToData:other.groupId]) { | 
					
						
							|  |  |  |         return NO; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (![_groupName isEqual:other.groupName]) { | 
					
						
							|  |  |  |         return NO; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!(_groupImage != nil && other.groupImage != nil && | 
					
						
							|  |  |  |           [UIImagePNGRepresentation(_groupImage) isEqualToData:UIImagePNGRepresentation(other.groupImage)])) { | 
					
						
							|  |  |  |         return NO; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (_groupType != other.groupType) { | 
					
						
							|  |  |  |         return NO; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     NSMutableArray *compareMyGroupMemberIds = [NSMutableArray arrayWithArray:_groupMemberIds]; | 
					
						
							|  |  |  |     [compareMyGroupMemberIds removeObjectsInArray:other.groupMemberIds]; | 
					
						
							|  |  |  |     if ([compareMyGroupMemberIds count] > 0) { | 
					
						
							|  |  |  |         return NO; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return YES; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSString *)getInfoStringAboutUpdateTo:(TSGroupModel *)newModel { | 
					
						
							|  |  |  |     // This is only invoked for group * changes *, i.e. not when a group is created. | 
					
						
							|  |  |  |     NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey]; | 
					
						
							|  |  |  |     NSString *updatedGroupInfoString = @""; | 
					
						
							|  |  |  |     if (self == newModel) { | 
					
						
							|  |  |  |         return NSLocalizedString(@"GROUP_UPDATED", @""); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Name change | 
					
						
							|  |  |  |     if (![_groupName isEqual:newModel.groupName]) { | 
					
						
							|  |  |  |         updatedGroupInfoString = [updatedGroupInfoString stringByAppendingString:[NSString stringWithFormat:NSLocalizedString(@"GROUP_TITLE_CHANGED", @""), newModel.groupName]]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Added & removed members | 
					
						
							|  |  |  |     NSSet *oldMembers = [NSSet setWithArray:_groupMemberIds]; | 
					
						
							|  |  |  |     NSSet *newMembers = [NSSet setWithArray:newModel.groupMemberIds]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSMutableSet *addedMembers = newMembers.mutableCopy; | 
					
						
							|  |  |  |     [addedMembers minusSet:oldMembers]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSMutableSet *removedMembers = oldMembers.mutableCopy; | 
					
						
							|  |  |  |     [removedMembers minusSet:newMembers]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSMutableSet *removedMembersMinusSelf = removedMembers.mutableCopy; | 
					
						
							|  |  |  |     [removedMembersMinusSelf minusSet:[NSSet setWithObject:userPublicKey]]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (removedMembersMinusSelf.count > 0) { | 
					
						
							|  |  |  |         NSArray *removedMemberNames = [removedMembers.allObjects map:^NSString *(NSString *publicKey) { | 
					
						
							|  |  |  |             SNContact *contact = [LKStorage.shared getContactWithSessionID:publicKey]; | 
					
						
							|  |  |  |             return [contact displayNameFor:SNContactContextRegular] ?: publicKey; | 
					
						
							|  |  |  |         }]; | 
					
						
							|  |  |  |         NSString *format = removedMembers.count > 1 ? NSLocalizedString(@"GROUP_MEMBERS_REMOVED", @"") : NSLocalizedString(@"GROUP_MEMBER_REMOVED", @""); | 
					
						
							|  |  |  |         updatedGroupInfoString = [updatedGroupInfoString | 
					
						
							|  |  |  |                                   stringByAppendingString:[NSString | 
					
						
							|  |  |  |                                                            stringWithFormat: format, | 
					
						
							|  |  |  |                                                            [removedMemberNames componentsJoinedByString:@", "]]]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (addedMembers.count > 0) { | 
					
						
							|  |  |  |         NSArray *addedMemberNames = [[addedMembers allObjects] map:^NSString*(NSString* publicKey) { | 
					
						
							|  |  |  |             SNContact *contact = [LKStorage.shared getContactWithSessionID:publicKey]; | 
					
						
							|  |  |  |             return [contact displayNameFor:SNContactContextRegular] ?: publicKey; | 
					
						
							|  |  |  |         }]; | 
					
						
							|  |  |  |         updatedGroupInfoString = [updatedGroupInfoString | 
					
						
							|  |  |  |                                   stringByAppendingString:[NSString | 
					
						
							|  |  |  |                                                            stringWithFormat:NSLocalizedString(@"GROUP_MEMBER_JOINED", @""), | 
					
						
							|  |  |  |                                                            [addedMemberNames componentsJoinedByString:@", "]]]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ([removedMembers containsObject:userPublicKey]) { | 
					
						
							|  |  |  |         updatedGroupInfoString = [updatedGroupInfoString stringByAppendingString:NSLocalizedString(@"YOU_WERE_REMOVED", @"")]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Return | 
					
						
							|  |  |  |     if ([updatedGroupInfoString length] == 0) { | 
					
						
							|  |  |  |         updatedGroupInfoString = NSLocalizedString(@"GROUP_UPDATED", @""); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return updatedGroupInfoString; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NS_ASSUME_NONNULL_END |