Signal-iOS/SignalServiceKit/src/Messages/OWSGroupCallMessage.m
2021-01-14 22:25:45 -03:00

290 lines
12 KiB
Objective-C

//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
#import "OWSGroupCallMessage.h"
#import "TSGroupThread.h"
#import <SignalCoreKit/NSDate+OWS.h>
#import <SignalServiceKit/FunctionalUtil.h>
#import <SignalServiceKit/SignalServiceKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSGroupCallMessage ()
@property (nonatomic, getter=wasRead) BOOL read;
@property (nonatomic, nullable, readonly) NSString *eraId;
@property (nonatomic, nullable) NSArray<NSString *> *joinedMemberUuids;
@property (nonatomic, nullable) NSString *creatorUuid;
@property (nonatomic) BOOL hasEnded;
@end
#pragma mark -
@implementation OWSGroupCallMessage
- (instancetype)initWithEraId:(NSString *)eraId
joinedMemberUuids:(NSArray<NSUUID *> *)joinedMemberUuids
creatorUuid:(nullable NSUUID *)creatorUuid
thread:(TSGroupThread *)thread
sentAtTimestamp:(uint64_t)sentAtTimestamp
{
self = [super initInteractionWithTimestamp:sentAtTimestamp thread:thread];
if (!self) {
return self;
}
_eraId = eraId;
_joinedMemberUuids = [joinedMemberUuids map:^(NSUUID *uuid) { return uuid.UUIDString; }];
_creatorUuid = creatorUuid.UUIDString;
return self;
}
// --- CODE GENERATION MARKER
// This snippet is generated by /Scripts/sds_codegen/sds_generate.py. Do not manually edit it, instead run
// `sds_codegen.sh`.
// clang-format off
- (instancetype)initWithGrdbId:(int64_t)grdbId
uniqueId:(NSString *)uniqueId
receivedAtTimestamp:(uint64_t)receivedAtTimestamp
sortId:(uint64_t)sortId
timestamp:(uint64_t)timestamp
uniqueThreadId:(NSString *)uniqueThreadId
creatorUuid:(nullable NSString *)creatorUuid
eraId:(nullable NSString *)eraId
hasEnded:(BOOL)hasEnded
joinedMemberUuids:(nullable NSArray<NSString *> *)joinedMemberUuids
read:(BOOL)read
{
self = [super initWithGrdbId:grdbId
uniqueId:uniqueId
receivedAtTimestamp:receivedAtTimestamp
sortId:sortId
timestamp:timestamp
uniqueThreadId:uniqueThreadId];
if (!self) {
return self;
}
_creatorUuid = creatorUuid;
_eraId = eraId;
_hasEnded = hasEnded;
_joinedMemberUuids = joinedMemberUuids;
_read = read;
return self;
}
// clang-format on
// --- CODE GENERATION MARKER
- (nullable instancetype)initWithCoder:(NSCoder *)coder
{
return [super initWithCoder:coder];
}
- (NSArray<SignalServiceAddress *> *)joinedMemberAddresses
{
return [self.joinedMemberUuids
map:^(NSString *uuidString) { return [[SignalServiceAddress alloc] initWithUuidString:uuidString]; }];
}
- (nullable SignalServiceAddress *)creatorAddress
{
if (self.creatorUuid) {
return [[SignalServiceAddress alloc] initWithUuidString:self.creatorUuid];
} else {
return nil;
}
}
- (OWSInteractionType)interactionType
{
return OWSInteractionType_Call;
}
#pragma mark - OWSReadTracking
- (uint64_t)expireStartedAt
{
return 0;
}
- (BOOL)shouldAffectUnreadCounts
{
return YES;
}
- (void)markAsReadAtTimestamp:(uint64_t)readTimestamp
thread:(TSThread *)thread
circumstance:(OWSReadCircumstance)circumstance
transaction:(SDSAnyWriteTransaction *)transaction
{
OWSAssertDebug(transaction);
if (self.read) {
return;
}
OWSLogDebug(@"marking as read uniqueId: %@ which has timestamp: %llu", self.uniqueId, self.timestamp);
[self anyUpdateGroupCallMessageWithTransaction:transaction
block:^(OWSGroupCallMessage *groupCallMessage) {
groupCallMessage.read = YES;
}];
// Ignore `circumstance` - we never send read receipts for calls.
}
#pragma mark - Methods
- (id<ContactsManagerProtocol>)contactsManager
{
return SSKEnvironment.shared.contactsManager;
}
- (NSString *)previewTextWithTransaction:(SDSAnyReadTransaction *)transaction
{
if (self.hasEnded) {
return NSLocalizedString(
@"GROUP_CALL_ENDED_MESSAGE", @"Text in conversation view for a group call that has since ended");
} else if (self.creatorAddress.isLocalAddress) {
return NSLocalizedString(@"GROUP_CALL_STARTED_BY_YOU", @"Text explaining that you started a group call.");
} else if (self.creatorAddress) {
NSString *creatorDisplayName = [self participantNameForAddress:self.creatorAddress transaction:transaction];
NSString *formatString = NSLocalizedString(@"GROUP_CALL_STARTED_MESSAGE_FORMAT",
@"Text explaining that someone started a group call. Embeds {{call creator display name}}");
return [NSString stringWithFormat:formatString, creatorDisplayName];
} else {
return NSLocalizedString(@"GROUP_CALL_SOMEONE_STARTED_MESSAGE",
@"Text in conversation view for a group call that someone started. We don't know who");
}
}
- (NSString *)systemTextWithTransaction:(SDSAnyReadTransaction *)transaction
{
NSString *moreThanThreeFormat = NSLocalizedString(@"GROUP_CALL_MANY_PEOPLE_HERE_FORMAT",
@"Text explaining that there are more than three people in the group call. Embeds {{ %1$@ participant1, %2$@ "
@"participant2, %3$@ participantCount-2 }}");
NSString *threeFormat = NSLocalizedString(@"GROUP_CALL_THREE_PEOPLE_HERE_FORMAT",
@"Text explaining that there are three people in the group call. Embeds {{ %1$@ participant1, %2$@ "
@"participant2 }}");
NSString *twoFormat = NSLocalizedString(@"GROUP_CALL_TWO_PEOPLE_HERE_FORMAT",
@"Text explaining that there are two people in the group call. Embeds {{ %1$@ participant1, %2$@ participant2 "
@"}}");
NSString *onlyCreatorFormat = NSLocalizedString(@"GROUP_CALL_STARTED_MESSAGE_FORMAT",
@"Text explaining that someone started a group call. Embeds {{call creator display name}}");
NSString *youCreatedString
= NSLocalizedString(@"GROUP_CALL_STARTED_BY_YOU", @"Text explaining that you started a group call.");
NSString *onlyYouString
= NSLocalizedString(@"GROUP_CALL_YOU_ARE_HERE", @"Text explaining that you are in the group call.");
NSString *onlyOneFormat = NSLocalizedString(@"GROUP_CALL_ONE_PERSON_HERE_FORMAT",
@"Text explaining that there is one person in the group call. Embeds {member name}");
NSString *endedString = NSLocalizedString(
@"GROUP_CALL_ENDED_MESSAGE", @"Text in conversation view for a group call that has since ended");
NSString *someoneString = NSLocalizedString(@"GROUP_CALL_SOMEONE_STARTED_MESSAGE",
@"Text in conversation view for a group call that someone started. We don't know who");
// Sort the addresses to prioritize the local user and originator, then the rest of the participants alphabetically
NSArray<SignalServiceAddress *> *sortedAddresses = [self.joinedMemberAddresses
sortedArrayUsingComparator:^NSComparisonResult(SignalServiceAddress *obj1, SignalServiceAddress *obj2) {
if ([obj1 isEqualToAddress:obj2]) {
return NSOrderedSame;
} else if (obj1.isLocalAddress || obj2.isLocalAddress) {
return obj1.isLocalAddress ? NSOrderedAscending : NSOrderedDescending;
} else if ([obj1 isEqualToAddress:self.creatorAddress] || [obj2 isEqualToAddress:self.creatorAddress]) {
return [obj1 isEqualToAddress:self.creatorAddress] ? NSOrderedAscending : NSOrderedDescending;
} else {
NSString *compareString1 = [self.contactsManager comparableNameForAddress:obj1 transaction:transaction];
NSString *compareString2 = [self.contactsManager comparableNameForAddress:obj2 transaction:transaction];
return [compareString1 compare:compareString2];
}
}];
if (self.hasEnded) {
return endedString;
} else if (sortedAddresses.count >= 4) {
NSString *firstName = [self participantNameForAddress:sortedAddresses[0] transaction:transaction];
NSString *secondName = [self participantNameForAddress:sortedAddresses[1] transaction:transaction];
NSString *remainingCount = [OWSFormat formatInt:(sortedAddresses.count - 2)];
return [NSString stringWithFormat:moreThanThreeFormat, firstName, secondName, remainingCount];
} else if (sortedAddresses.count == 3) {
NSString *firstName = [self participantNameForAddress:sortedAddresses[0] transaction:transaction];
NSString *secondName = [self participantNameForAddress:sortedAddresses[1] transaction:transaction];
return [NSString stringWithFormat:threeFormat, firstName, secondName];
} else if (sortedAddresses.count == 2) {
NSString *firstName = [self participantNameForAddress:sortedAddresses[0] transaction:transaction];
NSString *secondName = [self participantNameForAddress:sortedAddresses[1] transaction:transaction];
return [NSString stringWithFormat:twoFormat, firstName, secondName];
} else if (sortedAddresses.count == 1 && [sortedAddresses[0] isEqualToAddress:self.creatorAddress]) {
if (sortedAddresses[0].isLocalAddress) {
return youCreatedString;
} else {
NSString *name = [self participantNameForAddress:sortedAddresses[0] transaction:transaction];
return [NSString stringWithFormat:onlyCreatorFormat, name];
}
} else if (sortedAddresses.count == 1 && sortedAddresses[0].isLocalAddress) {
return onlyYouString;
} else if (sortedAddresses.count == 1) {
NSString *name = [self participantNameForAddress:sortedAddresses[0] transaction:transaction];
return [NSString stringWithFormat:onlyOneFormat, name];
} else {
return someoneString;
}
}
- (void)updateWithHasEnded:(BOOL)hasEnded transaction:(SDSAnyWriteTransaction *)transaction
{
[self anyUpdateGroupCallMessageWithTransaction:transaction
block:^(OWSGroupCallMessage *message) {
message.hasEnded = hasEnded;
message.joinedMemberUuids = @[];
}];
}
- (void)updateWithJoinedMemberUuids:(NSArray<NSUUID *> *)joinedMemberUuids
creatorUuid:(NSUUID *)uuid
transaction:(SDSAnyWriteTransaction *)transaction
{
[self anyUpdateGroupCallMessageWithTransaction:transaction
block:^(OWSGroupCallMessage *message) {
message.hasEnded = joinedMemberUuids.count == 0;
message.creatorUuid = uuid.UUIDString;
message.joinedMemberUuids = [joinedMemberUuids
map:^(NSUUID *uuid) { return uuid.UUIDString; }];
}];
}
#pragma mark - Private
- (NSString *)participantNameForAddress:(SignalServiceAddress *)address transaction:(SDSAnyReadTransaction *)transaction
{
if (address.isLocalAddress) {
return NSLocalizedString(@"GROUP_CALL_YOU", "Text describing the local user as a participant in a group call.");
} else {
return [self.contactsManager displayNameForAddress:address transaction:transaction];
}
}
@end
NS_ASSUME_NONNULL_END