mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-21 17:12:45 +02:00
Merge MatrixKit develop with commit hash: b85b736313bec0592bd1cabc68035d97f5331137
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <AddressBook/AddressBook.h>
|
||||
|
||||
#import "MXKCellData.h"
|
||||
|
||||
#import "MXKEmail.h"
|
||||
#import "MXKPhoneNumber.h"
|
||||
|
||||
/**
|
||||
Posted when the contact thumbnail is updated.
|
||||
The notification object is a contact Id.
|
||||
*/
|
||||
extern NSString *const kMXKContactThumbnailUpdateNotification;
|
||||
|
||||
extern NSString *const kMXKContactLocalContactPrefixId;
|
||||
extern NSString *const kMXKContactMatrixContactPrefixId;
|
||||
extern NSString *const kMXKContactDefaultContactPrefixId;
|
||||
|
||||
@interface MXKContact : MXKCellData <NSCoding>
|
||||
|
||||
/**
|
||||
The unique identifier
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString * contactID;
|
||||
|
||||
/**
|
||||
The display name
|
||||
*/
|
||||
@property (nonatomic, readwrite) NSString *displayName;
|
||||
|
||||
/**
|
||||
The sorting display name built by trimming the symbols [_!~`@#$%^&*-+();:={}[],.<>?\/"'] from the display name.
|
||||
*/
|
||||
@property (nonatomic) NSString* sortingDisplayName;
|
||||
|
||||
/**
|
||||
The contact thumbnail. Default size: 256 X 256 pixels
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) UIImage *thumbnail;
|
||||
|
||||
/**
|
||||
YES if the contact does not exist in the contacts book
|
||||
the contact has been created from a MXUser or MXRoomThirdPartyInvite
|
||||
*/
|
||||
@property (nonatomic) BOOL isMatrixContact;
|
||||
|
||||
/**
|
||||
YES if the contact is coming from MXRoomThirdPartyInvite event (NO by default).
|
||||
*/
|
||||
@property (nonatomic) BOOL isThirdPartyInvite;
|
||||
|
||||
/**
|
||||
The array of MXKPhoneNumber
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray *phoneNumbers;
|
||||
|
||||
/**
|
||||
The array of MXKEmail
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray *emailAddresses;
|
||||
|
||||
/**
|
||||
The array of matrix identifiers
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray* matrixIdentifiers;
|
||||
|
||||
/**
|
||||
The matrix avatar url used (if any) to build the current thumbnail, nil by default.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString* matrixAvatarURL;
|
||||
|
||||
/**
|
||||
Reset the current thumbnail if it is retrieved from a matrix url. May be used in case of the matrix avatar url change.
|
||||
A new thumbnail will be automatically restored from the contact data.
|
||||
*/
|
||||
- (void)resetMatrixThumbnail;
|
||||
|
||||
/**
|
||||
The contact ID from native phonebook record
|
||||
*/
|
||||
+ (NSString*)contactID:(ABRecordRef)record;
|
||||
|
||||
/**
|
||||
Create a local contact from a device contact
|
||||
|
||||
@param record device contact id
|
||||
@return MXKContact instance
|
||||
*/
|
||||
- (id)initLocalContactWithABRecord:(ABRecordRef)record;
|
||||
|
||||
/**
|
||||
Create a matrix contact with the dedicated info
|
||||
|
||||
@param displayName the contact display name
|
||||
@param matrixID the contact matrix id
|
||||
@return MXKContact instance
|
||||
*/
|
||||
- (id)initMatrixContactWithDisplayName:(NSString*)displayName andMatrixID:(NSString*)matrixID;
|
||||
|
||||
/**
|
||||
Create a matrix contact with the dedicated info
|
||||
|
||||
@param displayName the contact display name
|
||||
@param matrixID the contact matrix id
|
||||
@param matrixAvatarURL the matrix avatar url
|
||||
@return MXKContact instance
|
||||
*/
|
||||
- (id)initMatrixContactWithDisplayName:(NSString*)displayName matrixID:(NSString*)matrixID andMatrixAvatarURL:(NSString*)matrixAvatarURL;
|
||||
|
||||
/**
|
||||
Create a contact with the dedicated info
|
||||
|
||||
@param displayName the contact display name
|
||||
@param emails an array of emails
|
||||
@param phones an array of phone numbers
|
||||
@param thumbnail the contact thumbnail
|
||||
@return MXKContact instance
|
||||
*/
|
||||
- (id)initContactWithDisplayName:(NSString*)displayName
|
||||
emails:(NSArray<MXKEmail*> *)emails
|
||||
phoneNumbers:(NSArray<MXKPhoneNumber*> *)phones
|
||||
andThumbnail:(UIImage *)thumbnail;
|
||||
|
||||
/**
|
||||
The contact thumbnail with a prefered size.
|
||||
|
||||
If the thumbnail is already loaded, this method returns this one by ignoring prefered size.
|
||||
The prefered size is used only if a server request is required.
|
||||
|
||||
@return thumbnail with a prefered size
|
||||
*/
|
||||
- (UIImage*)thumbnailWithPreferedSize:(CGSize)size;
|
||||
|
||||
/**
|
||||
Tell whether a component of the contact's displayName, or one of his matrix id/email has the provided prefix.
|
||||
|
||||
@param prefix a non empty string.
|
||||
@return YES when at least one matrix id, email or a component of the display name has this prefix.
|
||||
*/
|
||||
- (BOOL)hasPrefix:(NSString*)prefix;
|
||||
|
||||
/**
|
||||
Check if the patterns can match with this contact
|
||||
*/
|
||||
- (BOOL)matchedWithPatterns:(NSArray*)patterns;
|
||||
|
||||
/**
|
||||
The default ISO 3166-1 country code used to internationalize the contact phone numbers.
|
||||
*/
|
||||
@property (nonatomic) NSString *defaultCountryCode;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "MXKContact.h"
|
||||
|
||||
#import "MXKEmail.h"
|
||||
#import "MXKPhoneNumber.h"
|
||||
|
||||
NSString *const kMXKContactThumbnailUpdateNotification = @"kMXKContactThumbnailUpdateNotification";
|
||||
|
||||
NSString *const kMXKContactLocalContactPrefixId = @"Local_";
|
||||
NSString *const kMXKContactMatrixContactPrefixId = @"Matrix_";
|
||||
NSString *const kMXKContactDefaultContactPrefixId = @"Default_";
|
||||
|
||||
@interface MXKContact()
|
||||
{
|
||||
UIImage* contactThumbnail;
|
||||
UIImage* matrixThumbnail;
|
||||
|
||||
// The matrix id of the contact (used when the contact is not defined in the contacts book)
|
||||
MXKContactField *matrixIdField;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation MXKContact
|
||||
@synthesize isMatrixContact, isThirdPartyInvite;
|
||||
|
||||
+ (NSString*)contactID:(ABRecordRef)record
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@%d", kMXKContactLocalContactPrefixId, ABRecordGetRecordID(record)];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
matrixIdField = nil;
|
||||
isMatrixContact = NO;
|
||||
_matrixAvatarURL = nil;
|
||||
|
||||
isThirdPartyInvite = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initLocalContactWithABRecord:(ABRecordRef)record
|
||||
{
|
||||
self = [self init];
|
||||
if (self)
|
||||
{
|
||||
// compute a contact ID
|
||||
_contactID = [MXKContact contactID:record];
|
||||
|
||||
// use the contact book display name
|
||||
_displayName = (__bridge NSString*) ABRecordCopyCompositeName(record);
|
||||
|
||||
// avoid nil display name
|
||||
// the display name is used to sort contacts
|
||||
if (!_displayName)
|
||||
{
|
||||
_displayName = @"";
|
||||
}
|
||||
|
||||
// extract the phone numbers and their related label
|
||||
ABMultiValueRef multi = ABRecordCopyValue(record, kABPersonPhoneProperty);
|
||||
CFIndex nCount = ABMultiValueGetCount(multi);
|
||||
NSMutableArray* pns = [[NSMutableArray alloc] initWithCapacity:nCount];
|
||||
|
||||
for (int i = 0; i < nCount; i++)
|
||||
{
|
||||
CFTypeRef phoneRef = ABMultiValueCopyValueAtIndex(multi, i);
|
||||
NSString *phoneVal = (__bridge NSString*)phoneRef;
|
||||
|
||||
// sanity check
|
||||
if (0 != [phoneVal length])
|
||||
{
|
||||
CFStringRef lblRef = ABMultiValueCopyLabelAtIndex(multi, i);
|
||||
CFStringRef localizedLblRef = nil;
|
||||
NSString *lbl = @"";
|
||||
|
||||
if (lblRef != nil)
|
||||
{
|
||||
localizedLblRef = ABAddressBookCopyLocalizedLabel(lblRef);
|
||||
if (localizedLblRef)
|
||||
{
|
||||
lbl = (__bridge NSString*)localizedLblRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
lbl = (__bridge NSString*)lblRef;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
localizedLblRef = ABAddressBookCopyLocalizedLabel(kABOtherLabel);
|
||||
if (localizedLblRef)
|
||||
{
|
||||
lbl = (__bridge NSString*)localizedLblRef;
|
||||
}
|
||||
}
|
||||
|
||||
[pns addObject:[[MXKPhoneNumber alloc] initWithTextNumber:phoneVal type:lbl contactID:_contactID matrixID:nil]];
|
||||
|
||||
if (lblRef)
|
||||
{
|
||||
CFRelease(lblRef);
|
||||
}
|
||||
if (localizedLblRef)
|
||||
{
|
||||
CFRelease(localizedLblRef);
|
||||
}
|
||||
}
|
||||
|
||||
// release meory
|
||||
if (phoneRef)
|
||||
{
|
||||
CFRelease(phoneRef);
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(multi);
|
||||
_phoneNumbers = pns;
|
||||
|
||||
// extract the emails
|
||||
multi = ABRecordCopyValue(record, kABPersonEmailProperty);
|
||||
nCount = ABMultiValueGetCount(multi);
|
||||
|
||||
NSMutableArray *emails = [[NSMutableArray alloc] initWithCapacity:nCount];
|
||||
|
||||
for (int i = 0; i < nCount; i++)
|
||||
{
|
||||
CFTypeRef emailValRef = ABMultiValueCopyValueAtIndex(multi, i);
|
||||
NSString *emailVal = (__bridge NSString*)emailValRef;
|
||||
|
||||
// sanity check
|
||||
if ((nil != emailVal) && (0 != [emailVal length]))
|
||||
{
|
||||
CFStringRef lblRef = ABMultiValueCopyLabelAtIndex(multi, i);
|
||||
CFStringRef localizedLblRef = nil;
|
||||
NSString *lbl = @"";
|
||||
|
||||
if (lblRef != nil)
|
||||
{
|
||||
localizedLblRef = ABAddressBookCopyLocalizedLabel(lblRef);
|
||||
|
||||
if (localizedLblRef)
|
||||
{
|
||||
lbl = (__bridge NSString*)localizedLblRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
lbl = (__bridge NSString*)lblRef;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
localizedLblRef = ABAddressBookCopyLocalizedLabel(kABOtherLabel);
|
||||
if (localizedLblRef)
|
||||
{
|
||||
lbl = (__bridge NSString*)localizedLblRef;
|
||||
}
|
||||
}
|
||||
|
||||
[emails addObject: [[MXKEmail alloc] initWithEmailAddress:emailVal type:lbl contactID:_contactID matrixID:nil]];
|
||||
|
||||
if (lblRef)
|
||||
{
|
||||
CFRelease(lblRef);
|
||||
}
|
||||
|
||||
if (localizedLblRef)
|
||||
{
|
||||
CFRelease(localizedLblRef);
|
||||
}
|
||||
}
|
||||
|
||||
if (emailValRef)
|
||||
{
|
||||
CFRelease(emailValRef);
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(multi);
|
||||
|
||||
_emailAddresses = emails;
|
||||
|
||||
// thumbnail/picture
|
||||
// check whether the contact has a picture
|
||||
if (ABPersonHasImageData(record))
|
||||
{
|
||||
CFDataRef dataRef;
|
||||
|
||||
dataRef = ABPersonCopyImageDataWithFormat(record, kABPersonImageFormatThumbnail);
|
||||
if (dataRef)
|
||||
{
|
||||
contactThumbnail = [UIImage imageWithData:(__bridge NSData*)dataRef];
|
||||
CFRelease(dataRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initMatrixContactWithDisplayName:(NSString*)displayName andMatrixID:(NSString*)matrixID
|
||||
{
|
||||
self = [self init];
|
||||
if (self)
|
||||
{
|
||||
_contactID = [NSString stringWithFormat:@"%@%@", kMXKContactMatrixContactPrefixId, [[NSUUID UUID] UUIDString]];
|
||||
|
||||
// Sanity check
|
||||
if (matrixID.length)
|
||||
{
|
||||
// used when the contact is not defined in the contacts book
|
||||
matrixIdField = [[MXKContactField alloc] initWithContactID:_contactID matrixID:matrixID];
|
||||
isMatrixContact = YES;
|
||||
}
|
||||
|
||||
// _displayName must not be nil
|
||||
// it is used to sort the contacts
|
||||
if (displayName)
|
||||
{
|
||||
_displayName = displayName;
|
||||
}
|
||||
else
|
||||
{
|
||||
_displayName = @"";
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initMatrixContactWithDisplayName:(NSString*)displayName matrixID:(NSString*)matrixID andMatrixAvatarURL:(NSString*)matrixAvatarURL
|
||||
{
|
||||
self = [self initMatrixContactWithDisplayName:displayName andMatrixID:matrixID];
|
||||
if (self)
|
||||
{
|
||||
matrixIdField.matrixAvatarURL = matrixAvatarURL;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initContactWithDisplayName:(NSString*)displayName
|
||||
emails:(NSArray<MXKEmail*> *)emails
|
||||
phoneNumbers:(NSArray<MXKPhoneNumber*> *)phones
|
||||
andThumbnail:(UIImage *)thumbnail
|
||||
{
|
||||
self = [self init];
|
||||
if (self)
|
||||
{
|
||||
_contactID = [NSString stringWithFormat:@"%@%@", kMXKContactDefaultContactPrefixId, [[NSUUID UUID] UUIDString]];
|
||||
|
||||
// _displayName must not be nil
|
||||
// it is used to sort the contacts
|
||||
if (displayName)
|
||||
{
|
||||
_displayName = displayName;
|
||||
}
|
||||
else
|
||||
{
|
||||
_displayName = @"";
|
||||
}
|
||||
|
||||
_emailAddresses = emails;
|
||||
_phoneNumbers = phones;
|
||||
|
||||
contactThumbnail = thumbnail;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSString*)sortingDisplayName
|
||||
{
|
||||
if (!_sortingDisplayName)
|
||||
{
|
||||
// Sanity check - display name should not be nil here
|
||||
if (self.displayName)
|
||||
{
|
||||
NSCharacterSet *specialCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"_!~`@#$%^&*-+();:={}[],.<>?\\/\"\'"];
|
||||
|
||||
_sortingDisplayName = [self.displayName stringByTrimmingCharactersInSet:specialCharacterSet];
|
||||
}
|
||||
else
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
}
|
||||
|
||||
return _sortingDisplayName;
|
||||
}
|
||||
|
||||
- (BOOL)hasPrefix:(NSString*)prefix
|
||||
{
|
||||
prefix = [prefix lowercaseString];
|
||||
|
||||
// Check first display name
|
||||
if (_displayName.length)
|
||||
{
|
||||
NSString *lowercaseString = [_displayName lowercaseString];
|
||||
if ([lowercaseString hasPrefix:prefix])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSArray *components = [lowercaseString componentsSeparatedByString:@" "];
|
||||
for (NSString *component in components)
|
||||
{
|
||||
NSString *theComponent = [component stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
if ([theComponent hasPrefix:prefix])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check matrix identifiers
|
||||
NSArray *identifiers = self.matrixIdentifiers;
|
||||
NSString *idPrefix = prefix;
|
||||
if (![prefix hasPrefix:@"@"])
|
||||
{
|
||||
idPrefix = [NSString stringWithFormat:@"@%@", prefix];
|
||||
}
|
||||
|
||||
for (NSString* mxId in identifiers)
|
||||
{
|
||||
if ([[mxId lowercaseString] hasPrefix:idPrefix])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// Check email
|
||||
for (MXKEmail* email in _emailAddresses)
|
||||
{
|
||||
if ([email.emailAddress hasPrefix:prefix])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// Check phones
|
||||
for (MXKPhoneNumber* phone in _phoneNumbers)
|
||||
{
|
||||
if ([phone hasPrefix:prefix])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)matchedWithPatterns:(NSArray*)patterns
|
||||
{
|
||||
BOOL matched = NO;
|
||||
|
||||
if (patterns.count > 0)
|
||||
{
|
||||
matched = YES;
|
||||
|
||||
// test first display name
|
||||
for (NSString* pattern in patterns)
|
||||
{
|
||||
if ([_displayName rangeOfString:pattern options:NSCaseInsensitiveSearch].location == NSNotFound)
|
||||
{
|
||||
matched = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NSArray *identifiers = self.matrixIdentifiers;
|
||||
if (!matched && identifiers.count > 0)
|
||||
{
|
||||
for (NSString* mxId in identifiers)
|
||||
{
|
||||
// Consider only the first part of the matrix id (ignore homeserver name)
|
||||
NSRange range = [mxId rangeOfString:@":"];
|
||||
if (range.location != NSNotFound)
|
||||
{
|
||||
NSString *mxIdName = [mxId substringToIndex:range.location];
|
||||
for (NSString* pattern in patterns)
|
||||
{
|
||||
if ([mxIdName rangeOfString:pattern options:NSCaseInsensitiveSearch].location != NSNotFound)
|
||||
{
|
||||
matched = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!matched && _phoneNumbers.count > 0)
|
||||
{
|
||||
for (MXKPhoneNumber* phonenumber in _phoneNumbers)
|
||||
{
|
||||
if ([phonenumber matchedWithPatterns:patterns])
|
||||
{
|
||||
matched = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!matched && _emailAddresses.count > 0)
|
||||
{
|
||||
for (MXKEmail* email in _emailAddresses)
|
||||
{
|
||||
if ([email matchedWithPatterns:patterns])
|
||||
{
|
||||
matched = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if there is no pattern to search, it should always matched
|
||||
matched = YES;
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
- (void)setDefaultCountryCode:(NSString *)defaultCountryCode
|
||||
{
|
||||
for (MXKPhoneNumber* phonenumber in _phoneNumbers)
|
||||
{
|
||||
phonenumber.defaultCountryCode = defaultCountryCode;
|
||||
}
|
||||
|
||||
_defaultCountryCode = defaultCountryCode;
|
||||
}
|
||||
|
||||
#pragma mark - getter/setter
|
||||
|
||||
- (NSArray*)matrixIdentifiers
|
||||
{
|
||||
NSMutableArray* identifiers = [[NSMutableArray alloc] init];
|
||||
|
||||
if (matrixIdField)
|
||||
{
|
||||
[identifiers addObject:matrixIdField.matrixID];
|
||||
}
|
||||
|
||||
for (MXKEmail* email in _emailAddresses)
|
||||
{
|
||||
if (email.matrixID && ([identifiers indexOfObject:email.matrixID] == NSNotFound))
|
||||
{
|
||||
[identifiers addObject:email.matrixID];
|
||||
}
|
||||
}
|
||||
|
||||
for (MXKPhoneNumber* pn in _phoneNumbers)
|
||||
{
|
||||
if (pn.matrixID && ([identifiers indexOfObject:pn.matrixID] == NSNotFound))
|
||||
{
|
||||
[identifiers addObject:pn.matrixID];
|
||||
}
|
||||
}
|
||||
|
||||
return identifiers;
|
||||
}
|
||||
|
||||
- (void)setDisplayName:(NSString *)displayName
|
||||
{
|
||||
// a display name must not be emptied
|
||||
// it is used to sort the contacts
|
||||
if (displayName.length == 0)
|
||||
{
|
||||
_displayName = _contactID;
|
||||
}
|
||||
else
|
||||
{
|
||||
_displayName = displayName;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resetMatrixThumbnail
|
||||
{
|
||||
matrixThumbnail = nil;
|
||||
_matrixAvatarURL = nil;
|
||||
|
||||
// Reset the avatar in the contact fields too.
|
||||
[matrixIdField resetMatrixAvatar];
|
||||
|
||||
for (MXKEmail* email in _emailAddresses)
|
||||
{
|
||||
[email resetMatrixAvatar];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage*)thumbnailWithPreferedSize:(CGSize)size
|
||||
{
|
||||
// Consider first the local thumbnail if any.
|
||||
if (contactThumbnail)
|
||||
{
|
||||
return contactThumbnail;
|
||||
}
|
||||
|
||||
// Check whether a matrix thumbnail is already found.
|
||||
if (matrixThumbnail)
|
||||
{
|
||||
return matrixThumbnail;
|
||||
}
|
||||
|
||||
// Look for a thumbnail from the matrix identifiers
|
||||
MXKContactField* firstField = matrixIdField;
|
||||
if (firstField)
|
||||
{
|
||||
if (firstField.avatarImage)
|
||||
{
|
||||
matrixThumbnail = firstField.avatarImage;
|
||||
_matrixAvatarURL = firstField.matrixAvatarURL;
|
||||
return matrixThumbnail;
|
||||
}
|
||||
}
|
||||
|
||||
// try to replace the thumbnail by the matrix one
|
||||
if (_emailAddresses.count > 0)
|
||||
{
|
||||
// list the linked email
|
||||
// search if one email field has a dedicated thumbnail
|
||||
for (MXKEmail* email in _emailAddresses)
|
||||
{
|
||||
if (email.avatarImage)
|
||||
{
|
||||
matrixThumbnail = email.avatarImage;
|
||||
_matrixAvatarURL = email.matrixAvatarURL;
|
||||
return matrixThumbnail;
|
||||
}
|
||||
else if (!firstField && email.matrixID)
|
||||
{
|
||||
firstField = email;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_phoneNumbers.count > 0)
|
||||
{
|
||||
// list the linked phones
|
||||
// search if one phone field has a dedicated thumbnail
|
||||
for (MXKPhoneNumber* phoneNb in _phoneNumbers)
|
||||
{
|
||||
if (phoneNb.avatarImage)
|
||||
{
|
||||
matrixThumbnail = phoneNb.avatarImage;
|
||||
_matrixAvatarURL = phoneNb.matrixAvatarURL;
|
||||
return matrixThumbnail;
|
||||
}
|
||||
else if (!firstField && phoneNb.matrixID)
|
||||
{
|
||||
firstField = phoneNb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no thumbnail has been found
|
||||
// try to load the first field one
|
||||
if (firstField)
|
||||
{
|
||||
// should be retrieved by the cell info
|
||||
[firstField loadAvatarWithSize:size];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UIImage*)thumbnail
|
||||
{
|
||||
return [self thumbnailWithPreferedSize:CGSizeMake(256, 256)];
|
||||
}
|
||||
|
||||
#pragma mark NSCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
_contactID = [coder decodeObjectForKey:@"contactID"];
|
||||
_displayName = [coder decodeObjectForKey:@"displayName"];
|
||||
|
||||
matrixIdField = [coder decodeObjectForKey:@"matrixIdField"];
|
||||
|
||||
_phoneNumbers = [coder decodeObjectForKey:@"phoneNumbers"];
|
||||
_emailAddresses = [coder decodeObjectForKey:@"emailAddresses"];
|
||||
|
||||
NSData *data = [coder decodeObjectForKey:@"contactThumbnail"];
|
||||
if (!data)
|
||||
{
|
||||
// Check the legacy storage.
|
||||
data = [coder decodeObjectForKey:@"contactBookThumbnail"];
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
contactThumbnail = [UIImage imageWithData:data];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
|
||||
[coder encodeObject:_contactID forKey:@"contactID"];
|
||||
[coder encodeObject:_displayName forKey:@"displayName"];
|
||||
|
||||
if (matrixIdField)
|
||||
{
|
||||
[coder encodeObject:matrixIdField forKey:@"matrixIdField"];
|
||||
}
|
||||
|
||||
if (_phoneNumbers.count)
|
||||
{
|
||||
[coder encodeObject:_phoneNumbers forKey:@"phoneNumbers"];
|
||||
}
|
||||
|
||||
if (_emailAddresses.count)
|
||||
{
|
||||
[coder encodeObject:_emailAddresses forKey:@"emailAddresses"];
|
||||
}
|
||||
|
||||
if (contactThumbnail)
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
NSData *data = UIImageJPEGRepresentation(contactThumbnail, 0.8);
|
||||
[coder encodeObject:data forKey:@"contactThumbnail"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface MXKContactField : NSObject<NSCoding>
|
||||
|
||||
/**
|
||||
The identifier of the contact to whom the data belongs to.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *contactID;
|
||||
/**
|
||||
The linked matrix identifier if any
|
||||
*/
|
||||
@property (nonatomic, readwrite) NSString *matrixID;
|
||||
/**
|
||||
The matrix avatar url (Matrix Content URI), nil by default.
|
||||
*/
|
||||
@property (nonatomic) NSString* matrixAvatarURL;
|
||||
/**
|
||||
The current avatar downloaded by using the avatar url if any
|
||||
*/
|
||||
@property (nonatomic, readonly) UIImage *avatarImage;
|
||||
|
||||
- (id)initWithContactID:(NSString*)contactID matrixID:(NSString*)matrixID;
|
||||
|
||||
- (void)loadAvatarWithSize:(CGSize)avatarSize;
|
||||
|
||||
/**
|
||||
Reset the current avatar. May be used in case of the matrix avatar url change.
|
||||
A new avatar will be automatically restored from the matrix data.
|
||||
*/
|
||||
- (void)resetMatrixAvatar;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "MXKContactField.h"
|
||||
|
||||
@import MatrixSDK.MXMediaManager;
|
||||
|
||||
#import "MXKContactManager.h"
|
||||
|
||||
@interface MXKContactField()
|
||||
{
|
||||
// Tell whether we already check the contact avatar definition.
|
||||
BOOL shouldCheckAvatarURL;
|
||||
// The media manager of the session used to retrieve the contect avatar url
|
||||
// This manager is used to download this avatar if need
|
||||
MXMediaManager *mediaManager;
|
||||
// The current download id
|
||||
NSString *downloadId;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation MXKContactField
|
||||
|
||||
- (void)initFields
|
||||
{
|
||||
// init members
|
||||
_contactID = nil;
|
||||
_matrixID = nil;
|
||||
|
||||
[self resetMatrixAvatar];
|
||||
}
|
||||
|
||||
- (id)initWithContactID:(NSString*)contactID matrixID:(NSString*)matrixID
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self initFields];
|
||||
_contactID = contactID;
|
||||
_matrixID = matrixID;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)resetMatrixAvatar
|
||||
{
|
||||
_avatarImage = nil;
|
||||
_matrixAvatarURL = nil;
|
||||
shouldCheckAvatarURL = YES;
|
||||
mediaManager = nil;
|
||||
downloadId = nil;
|
||||
}
|
||||
|
||||
- (void)loadAvatarWithSize:(CGSize)avatarSize
|
||||
{
|
||||
// Check whether the avatar image is already set
|
||||
if (_avatarImage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (_matrixID)
|
||||
{
|
||||
if (shouldCheckAvatarURL)
|
||||
{
|
||||
// Consider here all sessions reported into contact manager
|
||||
NSArray* mxSessions = [MXKContactManager sharedManager].mxSessions;
|
||||
|
||||
if (mxSessions.count)
|
||||
{
|
||||
// Check whether a matrix user is already known
|
||||
MXUser* user;
|
||||
MXSession *mxSession;
|
||||
|
||||
for (mxSession in mxSessions)
|
||||
{
|
||||
user = [mxSession userWithUserId:_matrixID];
|
||||
if (user)
|
||||
{
|
||||
_matrixAvatarURL = user.avatarUrl;
|
||||
if (_matrixAvatarURL)
|
||||
{
|
||||
shouldCheckAvatarURL = NO;
|
||||
mediaManager = mxSession.mediaManager;
|
||||
[self downloadAvatarImage:avatarSize];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger a server request if this url has not been found.
|
||||
if (shouldCheckAvatarURL)
|
||||
{
|
||||
MXWeakify(self);
|
||||
[mxSession.matrixRestClient avatarUrlForUser:_matrixID
|
||||
success:^(NSString *mxAvatarUrl) {
|
||||
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
self.matrixAvatarURL = mxAvatarUrl;
|
||||
self->shouldCheckAvatarURL = NO;
|
||||
self->mediaManager = mxSession.mediaManager;
|
||||
[self downloadAvatarImage:avatarSize];
|
||||
|
||||
} failure:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_matrixAvatarURL)
|
||||
{
|
||||
[self downloadAvatarImage:avatarSize];
|
||||
}
|
||||
// Do nothing if the avatar url has been checked, and it is null.
|
||||
}
|
||||
}
|
||||
|
||||
- (void)downloadAvatarImage:(CGSize)avatarSize
|
||||
{
|
||||
// the avatar image is already done
|
||||
if (_avatarImage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_matrixAvatarURL)
|
||||
{
|
||||
NSString *cacheFilePath = [MXMediaManager thumbnailCachePathForMatrixContentURI:_matrixAvatarURL
|
||||
andType:nil
|
||||
inFolder:kMXMediaManagerAvatarThumbnailFolder
|
||||
toFitViewSize:avatarSize
|
||||
withMethod:MXThumbnailingMethodCrop];
|
||||
_avatarImage = [MXMediaManager loadPictureFromFilePath:cacheFilePath];
|
||||
|
||||
// the image is already in the cache
|
||||
if (_avatarImage)
|
||||
{
|
||||
MXWeakify(self);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKContactThumbnailUpdateNotification object:self.contactID userInfo:nil];
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString *downloadId = [MXMediaManager thumbnailDownloadIdForMatrixContentURI:_matrixAvatarURL inFolder:kMXMediaManagerAvatarThumbnailFolder toFitViewSize:avatarSize withMethod:MXThumbnailingMethodCrop];
|
||||
MXMediaLoader* loader = [MXMediaManager existingDownloaderWithIdentifier:downloadId];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXMediaLoaderStateDidChangeNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMediaDownloadEnd:) name:kMXMediaLoaderStateDidChangeNotification object:loader];
|
||||
if (!loader && mediaManager)
|
||||
{
|
||||
[mediaManager downloadThumbnailFromMatrixContentURI:_matrixAvatarURL
|
||||
withType:nil
|
||||
inFolder:kMXMediaManagerAvatarThumbnailFolder
|
||||
toFitViewSize:avatarSize
|
||||
withMethod:MXThumbnailingMethodCrop
|
||||
success:nil
|
||||
failure:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onMediaDownloadEnd:(NSNotification *)notif
|
||||
{
|
||||
MXMediaLoader *loader = (MXMediaLoader*)notif.object;
|
||||
if ([loader.downloadId isEqualToString:downloadId])
|
||||
{
|
||||
// update the image
|
||||
switch (loader.state) {
|
||||
case MXMediaLoaderStateDownloadCompleted:
|
||||
{
|
||||
UIImage *image = [MXMediaManager loadPictureFromFilePath:loader.downloadOutputFilePath];
|
||||
if (image)
|
||||
{
|
||||
_avatarImage = image;
|
||||
|
||||
MXWeakify(self);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKContactThumbnailUpdateNotification object:self.contactID userInfo:nil];
|
||||
});
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXMediaLoaderStateDidChangeNotification object:nil];
|
||||
downloadId = nil;
|
||||
break;
|
||||
}
|
||||
case MXMediaLoaderStateDownloadFailed:
|
||||
case MXMediaLoaderStateCancelled:
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXMediaLoaderStateDidChangeNotification object:nil];
|
||||
downloadId = nil;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark NSCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
[self initFields];
|
||||
_contactID = [coder decodeObjectForKey:@"contactID"];
|
||||
_matrixID = [coder decodeObjectForKey:@"matrixID"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[coder encodeObject:_contactID forKey:@"contactID"];
|
||||
[coder encodeObject:_matrixID forKey:@"matrixID"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Contacts/Contacts.h>
|
||||
|
||||
#import <MatrixSDK/MatrixSDK.h>
|
||||
|
||||
#import "MXKSectionedContacts.h"
|
||||
#import "MXKContact.h"
|
||||
|
||||
/**
|
||||
Posted when the matrix contact list is loaded or updated.
|
||||
The notification object is:
|
||||
- a contact Id when a matrix contact has been added/updated/removed.
|
||||
or
|
||||
- nil when all matrix contacts are concerned.
|
||||
*/
|
||||
extern NSString * _Nonnull const kMXKContactManagerDidUpdateMatrixContactsNotification;
|
||||
|
||||
/**
|
||||
Posted when the local contact list is loaded and updated.
|
||||
The notification object is:
|
||||
- a contact Id when a local contact has been added/updated/removed.
|
||||
or
|
||||
- nil when all local contacts are concerned.
|
||||
*/
|
||||
extern NSString * _Nonnull const kMXKContactManagerDidUpdateLocalContactsNotification;
|
||||
|
||||
/**
|
||||
Posted when local contact matrix ids is updated.
|
||||
The notification object is:
|
||||
- a contact Id when a local contact has been added/updated/removed.
|
||||
or
|
||||
- nil when all local contacts are concerned.
|
||||
*/
|
||||
extern NSString * _Nonnull const kMXKContactManagerDidUpdateLocalContactMatrixIDsNotification;
|
||||
|
||||
/**
|
||||
Posted when the presence of a matrix user linked at least to one contact has changed.
|
||||
The notification object is the matrix Id. The `userInfo` dictionary contains an `MXPresenceString` object under the `kMXKContactManagerMatrixPresenceKey` key, representing the matrix user presence.
|
||||
*/
|
||||
extern NSString * _Nonnull const kMXKContactManagerMatrixUserPresenceChangeNotification;
|
||||
extern NSString * _Nonnull const kMXKContactManagerMatrixPresenceKey;
|
||||
|
||||
/**
|
||||
Posted when all phonenumbers of local contacts have been internationalized.
|
||||
The notification object is nil.
|
||||
*/
|
||||
extern NSString * _Nonnull const kMXKContactManagerDidInternationalizeNotification;
|
||||
|
||||
/**
|
||||
Used to identify the type of data when requesting MXKeyProvider
|
||||
*/
|
||||
extern NSString * _Nonnull const MXKContactManagerDataType;
|
||||
|
||||
/**
|
||||
Define the contact creation for the room members
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, MXKContactManagerMXRoomSource) {
|
||||
MXKContactManagerMXRoomSourceNone = 0, // the MXMember does not create any new contact.
|
||||
MXKContactManagerMXRoomSourceDirectChats = 1, // the direct chat users have their own contact even if they are not defined in the device contacts book
|
||||
MXKContactManagerMXRoomSourceAll = 2, // all the room members have their own contact even if they are not defined in the device contacts book
|
||||
};
|
||||
|
||||
/**
|
||||
This manager handles 2 kinds of contact list:
|
||||
- The local contacts retrieved from the device phonebook.
|
||||
- The matrix contacts retrieved from the matrix one-to-one rooms.
|
||||
|
||||
Note: The local contacts handling depends on the 'syncLocalContacts' and 'phonebookCountryCode' properties
|
||||
of the shared application settings object '[MXKAppSettings standardAppSettings]'.
|
||||
*/
|
||||
@interface MXKContactManager : NSObject
|
||||
|
||||
/**
|
||||
The shared instance of contact manager.
|
||||
*/
|
||||
+ (MXKContactManager* _Nonnull)sharedManager;
|
||||
|
||||
/**
|
||||
Block called (if any) to discover the Matrix users bound to a set of third-party identifiers (email addresses, phone numbers).
|
||||
If this property is unset, the contact manager will consider the potential identity server URL (see the `identityServer` property)
|
||||
to build its own Restclient and trigger `lookup3PIDs` requests.
|
||||
|
||||
@param threepids the list of 3rd party ids: [[<(MX3PIDMedium)media1>, <(NSString*)address1>], [<(MX3PIDMedium)media2>, <(NSString*)address2>], ...].
|
||||
@param success a block object called when the operation succeeds. It provides the array of the discovered users:
|
||||
[[<(MX3PIDMedium)media>, <(NSString*)address>, <(NSString*)userId>], ...].
|
||||
@param failure a block object called when the operation fails.
|
||||
*/
|
||||
typedef void(^MXKContactManagerDiscoverUsersBoundTo3PIDs)(NSArray<NSArray<NSString *> *> * _Nonnull threepids,
|
||||
void (^ _Nonnull success)(NSArray<NSArray<NSString *> *> *_Nonnull),
|
||||
void (^ _Nonnull failure)(NSError *_Nonnull));
|
||||
@property (nonatomic, nullable) MXKContactManagerDiscoverUsersBoundTo3PIDs discoverUsersBoundTo3PIDsBlock;
|
||||
|
||||
/**
|
||||
Define if the room member must have their dedicated contact even if they are not define in the device contacts book.
|
||||
The default value is MXKContactManagerMXRoomSourceDirectChats;
|
||||
*/
|
||||
@property (nonatomic) MXKContactManagerMXRoomSource contactManagerMXRoomSource;
|
||||
|
||||
/**
|
||||
Associated matrix sessions (empty by default).
|
||||
*/
|
||||
@property (nonatomic, readonly, nonnull) NSArray *mxSessions;
|
||||
|
||||
/**
|
||||
The current list of the contacts extracted from matrix data. Depends on 'contactManagerMXRoomSource'.
|
||||
*/
|
||||
@property (nonatomic, readonly, nullable) NSArray *matrixContacts;
|
||||
|
||||
/**
|
||||
The current list of the local contacts (nil by default until the contacts are loaded).
|
||||
*/
|
||||
@property (nonatomic, readonly, nullable) NSArray *localContacts;
|
||||
|
||||
/**
|
||||
The current list of the local contacts who have contact methods which can be used to invite them or to discover matrix users.
|
||||
*/
|
||||
@property (nonatomic, readonly, nullable) NSArray *localContactsWithMethods;
|
||||
|
||||
/**
|
||||
The contacts list obtained by splitting each local contact by contact method.
|
||||
This list is alphabetically sorted.
|
||||
Each contact has one and only one contact method.
|
||||
*/
|
||||
//- (void)localContactsSplitByContactMethod:(void (^)(NSArray<MXKContact*> *localContactsSplitByContactMethod))onComplete;
|
||||
|
||||
@property (nonatomic, readonly, nullable) NSArray *localContactsSplitByContactMethod;
|
||||
|
||||
/**
|
||||
The current list of the contacts for whom a direct chat exists.
|
||||
*/
|
||||
@property (nonatomic, readonly, nonnull) NSArray *directMatrixContacts;
|
||||
|
||||
/// Flag to allow local contacts access or not. Default value is YES.
|
||||
@property (nonatomic, assign) BOOL allowLocalContactsAccess;
|
||||
|
||||
/**
|
||||
Add/remove matrix session. The matrix contact list is automatically updated (see kMXKContactManagerDidUpdateMatrixContactsNotification event).
|
||||
*/
|
||||
- (void)addMatrixSession:(MXSession* _Nonnull)mxSession;
|
||||
- (void)removeMatrixSession:(MXSession* _Nonnull)mxSession;
|
||||
|
||||
/**
|
||||
Takes into account the state of the identity service's terms, local contacts access authorization along with
|
||||
whether the user has left the app for the Settings app to update the contacts access, and enables/disables
|
||||
the `syncLocalContacts` property of `MXKAppSettings` when necessary.
|
||||
@param mxSession The session who's identity service shall be used.
|
||||
*/
|
||||
- (void)validateSyncLocalContactsStateForSession:(MXSession *)mxSession;
|
||||
|
||||
/**
|
||||
Load and/or refresh the local contacts. Observe kMXKContactManagerDidUpdateLocalContactsNotification to know when local contacts are available.
|
||||
*/
|
||||
- (void)refreshLocalContacts;
|
||||
|
||||
/**
|
||||
Delete contacts info
|
||||
*/
|
||||
- (void)reset;
|
||||
|
||||
/**
|
||||
Get contact by its identifier.
|
||||
|
||||
@param contactID the contact identifier.
|
||||
@return the contact defined with the provided id.
|
||||
*/
|
||||
- (MXKContact* _Nullable)contactWithContactID:(NSString* _Nonnull)contactID;
|
||||
|
||||
/**
|
||||
Refresh matrix IDs for a specific local contact. See kMXKContactManagerDidUpdateLocalContactMatrixIDsNotification
|
||||
posted when update is done.
|
||||
|
||||
@param contact the local contact to refresh.
|
||||
*/
|
||||
- (void)updateMatrixIDsForLocalContact:(MXKContact* _Nonnull)contact;
|
||||
|
||||
/**
|
||||
Refresh matrix IDs for all local contacts. See kMXKContactManagerDidUpdateLocalContactMatrixIDsNotification
|
||||
posted when update for all local contacts is done.
|
||||
*/
|
||||
- (void)updateMatrixIDsForAllLocalContacts;
|
||||
|
||||
/**
|
||||
The contacts list obtained by splitting each local contact by contact method.
|
||||
This list is alphabetically sorted.
|
||||
Each contact has one and only one contact method.
|
||||
*/
|
||||
//- (void)localContactsSplitByContactMethod:(void (^)(NSArray<MXKContact*> *localContactsSplitByContactMethod))onComplete;
|
||||
|
||||
/**
|
||||
Sort a contacts array in sectioned arrays to be displayable in a UITableview
|
||||
*/
|
||||
- (MXKSectionedContacts* _Nullable)getSectionedContacts:(NSArray* _Nonnull)contactList;
|
||||
|
||||
/**
|
||||
Sort alphabetically an array of contacts.
|
||||
|
||||
@param contactsArray the array of contacts to sort.
|
||||
*/
|
||||
- (void)sortAlphabeticallyContacts:(NSMutableArray<MXKContact*> * _Nonnull)contactsArray;
|
||||
|
||||
/**
|
||||
Sort an array of contacts by last active, with "active now" first.
|
||||
...and then alphabetically.
|
||||
|
||||
@param contactsArray the array of contacts to sort.
|
||||
*/
|
||||
- (void)sortContactsByLastActiveInformation:(NSMutableArray<MXKContact*> * _Nonnull)contactsArray;
|
||||
|
||||
/**
|
||||
Refresh the international phonenumber of the local contacts (See kMXKContactManagerDidInternationalizeNotification).
|
||||
|
||||
@param countryCode the country code.
|
||||
*/
|
||||
- (void)internationalizePhoneNumbers:(NSString* _Nonnull)countryCode;
|
||||
|
||||
/**
|
||||
Request user permission for syncing local contacts.
|
||||
|
||||
@param viewController the view controller to attach the dialog to the user.
|
||||
@param handler the block called with the result of requesting access
|
||||
*/
|
||||
+ (void)requestUserConfirmationForLocalContactsSyncInViewController:(UIViewController* _Nonnull)viewController
|
||||
completionHandler:(void (^_Nonnull)(BOOL granted))handler;
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "MXKContactField.h"
|
||||
|
||||
@interface MXKEmail : MXKContactField
|
||||
|
||||
// email info (the address is stored in lowercase)
|
||||
@property (nonatomic, readonly) NSString *type;
|
||||
@property (nonatomic, readonly) NSString *emailAddress;
|
||||
|
||||
- (id)initWithEmailAddress:(NSString*)anEmailAddress type:(NSString*)aType contactID:(NSString*)aContactID matrixID:(NSString*)matrixID;
|
||||
|
||||
- (BOOL)matchedWithPatterns:(NSArray*)patterns;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "MXKEmail.h"
|
||||
|
||||
@implementation MXKEmail
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_emailAddress = nil;
|
||||
_type = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithEmailAddress:(NSString*)anEmailAddress type:(NSString*)aType contactID:(NSString*)aContactID matrixID:(NSString*)matrixID
|
||||
{
|
||||
self = [super initWithContactID:aContactID matrixID:matrixID];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_emailAddress = [anEmailAddress lowercaseString];
|
||||
_type = aType;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)matchedWithPatterns:(NSArray*)patterns
|
||||
{
|
||||
// no number -> cannot match
|
||||
if (_emailAddress.length == 0)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
if (patterns.count > 0)
|
||||
{
|
||||
for(NSString *pattern in patterns)
|
||||
{
|
||||
if ([_emailAddress rangeOfString:pattern options:NSCaseInsensitiveSearch].location == NSNotFound)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
#pragma mark NSCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_type = [coder decodeObjectForKey:@"type"];
|
||||
_emailAddress = [[coder decodeObjectForKey:@"emailAddress"] lowercaseString];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[super encodeWithCoder:coder];
|
||||
|
||||
[coder encodeObject:_type forKey:@"type"];
|
||||
[coder encodeObject:_emailAddress forKey:@"emailAddress"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "MXKContactField.h"
|
||||
|
||||
@class NBPhoneNumber;
|
||||
|
||||
@interface MXKPhoneNumber : MXKContactField
|
||||
|
||||
/**
|
||||
The phone number information
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *type;
|
||||
@property (nonatomic, readonly) NSString *textNumber;
|
||||
@property (nonatomic, readonly) NSString *cleanedPhonenumber;
|
||||
|
||||
/**
|
||||
When the number is considered to be a possible number. We expose here
|
||||
the corresponding NBPhoneNumber instance. Use the NBPhoneNumberUtil interface
|
||||
to format this phone number, or check whether the number is actually a
|
||||
valid number.
|
||||
*/
|
||||
@property (nonatomic, readonly) NBPhoneNumber* nbPhoneNumber;
|
||||
|
||||
/**
|
||||
The default ISO 3166-1 country code used to parse the text number,
|
||||
and create the nbPhoneNumber instance.
|
||||
*/
|
||||
@property (nonatomic) NSString *defaultCountryCode;
|
||||
|
||||
/**
|
||||
The Mobile Station International Subscriber Directory Number.
|
||||
Available when the nbPhoneNumber is not nil.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *msisdn;
|
||||
|
||||
/**
|
||||
Create a new MXKPhoneNumber instance
|
||||
|
||||
@param textNumber the phone number
|
||||
@param type the phone number type
|
||||
@param contactID The identifier of the contact to whom the data belongs to.
|
||||
@param matrixID The linked matrix identifier if any.
|
||||
*/
|
||||
- (id)initWithTextNumber:(NSString*)textNumber type:(NSString*)type contactID:(NSString*)contactID matrixID:(NSString*)matrixID;
|
||||
|
||||
/**
|
||||
Return YES when all the provided patterns are found in the phone number or its msisdn.
|
||||
|
||||
@param patterns an array of patterns (The potential "+" (or "00") prefix is ignored during the msisdn handling).
|
||||
*/
|
||||
- (BOOL)matchedWithPatterns:(NSArray*)patterns;
|
||||
|
||||
/**
|
||||
Tell whether the phone number or its msisdn has the provided prefix.
|
||||
|
||||
@param prefix a non empty string (The potential "+" (or "00") prefix is ignored during the msisdn handling).
|
||||
@return YES when the phone number or its msisdn has the provided prefix.
|
||||
*/
|
||||
- (BOOL)hasPrefix:(NSString*)prefix;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "MXKPhoneNumber.h"
|
||||
|
||||
@import libPhoneNumber_iOS;
|
||||
|
||||
@implementation MXKPhoneNumber
|
||||
|
||||
@synthesize msisdn;
|
||||
|
||||
- (id)initWithTextNumber:(NSString*)textNumber type:(NSString*)type contactID:(NSString*)contactID matrixID:(NSString*)matrixID
|
||||
{
|
||||
self = [super initWithContactID:contactID matrixID:matrixID];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_type = type ? type : @"";
|
||||
_textNumber = textNumber ? textNumber : @"" ;
|
||||
_cleanedPhonenumber = [MXKPhoneNumber cleanPhonenumber:_textNumber];
|
||||
_defaultCountryCode = nil;
|
||||
msisdn = nil;
|
||||
|
||||
_nbPhoneNumber = [[NBPhoneNumberUtil sharedInstance] parse:_cleanedPhonenumber defaultRegion:nil error:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// remove the unuseful characters in a phonenumber
|
||||
+ (NSString*)cleanPhonenumber:(NSString*)phoneNumber
|
||||
{
|
||||
// sanity check
|
||||
if (nil == phoneNumber)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// empty string
|
||||
if (0 == [phoneNumber length])
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
static NSCharacterSet *invertedPhoneCharSet = nil;
|
||||
|
||||
if (!invertedPhoneCharSet)
|
||||
{
|
||||
invertedPhoneCharSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789+*#,()"] invertedSet];
|
||||
}
|
||||
|
||||
return [[phoneNumber componentsSeparatedByCharactersInSet:invertedPhoneCharSet] componentsJoinedByString:@""];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)matchedWithPatterns:(NSArray*)patterns
|
||||
{
|
||||
// no number -> cannot match
|
||||
if (_textNumber.length == 0)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (patterns.count > 0)
|
||||
{
|
||||
for (NSString *pattern in patterns)
|
||||
{
|
||||
if ([_textNumber rangeOfString:pattern].location == NSNotFound)
|
||||
{
|
||||
NSString *cleanPattern = [[pattern componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:@""];
|
||||
|
||||
if ([_cleanedPhonenumber rangeOfString:cleanPattern].location == NSNotFound)
|
||||
{
|
||||
NSString *msisdnPattern;
|
||||
|
||||
if ([cleanPattern hasPrefix:@"+"])
|
||||
{
|
||||
msisdnPattern = [cleanPattern substringFromIndex:1];
|
||||
}
|
||||
else if ([cleanPattern hasPrefix:@"00"])
|
||||
{
|
||||
msisdnPattern = [cleanPattern substringFromIndex:2];
|
||||
}
|
||||
else
|
||||
{
|
||||
msisdnPattern = cleanPattern;
|
||||
}
|
||||
|
||||
// Check the msisdn
|
||||
if (!self.msisdn || !msisdnPattern.length || [self.msisdn rangeOfString:msisdnPattern].location == NSNotFound)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)hasPrefix:(NSString*)prefix
|
||||
{
|
||||
// no number -> cannot match
|
||||
if (_textNumber.length == 0)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ([_textNumber hasPrefix:prefix])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Remove whitespace before checking the cleaned phone number
|
||||
prefix = [[prefix componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:@""];
|
||||
|
||||
if ([_cleanedPhonenumber hasPrefix:prefix])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (self.msisdn)
|
||||
{
|
||||
if ([prefix hasPrefix:@"+"])
|
||||
{
|
||||
prefix = [prefix substringFromIndex:1];
|
||||
}
|
||||
else if ([prefix hasPrefix:@"00"])
|
||||
{
|
||||
prefix = [prefix substringFromIndex:2];
|
||||
}
|
||||
|
||||
return [self.msisdn hasPrefix:prefix];
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)setDefaultCountryCode:(NSString *)defaultCountryCode
|
||||
{
|
||||
if (![defaultCountryCode isEqualToString:_defaultCountryCode])
|
||||
{
|
||||
_nbPhoneNumber = [[NBPhoneNumberUtil sharedInstance] parse:_cleanedPhonenumber defaultRegion:defaultCountryCode error:nil];
|
||||
|
||||
_defaultCountryCode = defaultCountryCode;
|
||||
msisdn = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString*)msisdn
|
||||
{
|
||||
if (!msisdn && _nbPhoneNumber)
|
||||
{
|
||||
NSString *e164 = [[NBPhoneNumberUtil sharedInstance] format:_nbPhoneNumber numberFormat:NBEPhoneNumberFormatE164 error:nil];
|
||||
if ([e164 hasPrefix:@"+"])
|
||||
{
|
||||
msisdn = [e164 substringFromIndex:1];
|
||||
}
|
||||
else if ([e164 hasPrefix:@"00"])
|
||||
{
|
||||
msisdn = [e164 substringFromIndex:2];
|
||||
}
|
||||
}
|
||||
return msisdn;
|
||||
}
|
||||
|
||||
#pragma mark NSCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_type = [coder decodeObjectForKey:@"type"];
|
||||
_textNumber = [coder decodeObjectForKey:@"textNumber"];
|
||||
_cleanedPhonenumber = [coder decodeObjectForKey:@"cleanedPhonenumber"];
|
||||
_defaultCountryCode = [coder decodeObjectForKey:@"countryCode"];
|
||||
|
||||
_nbPhoneNumber = [[NBPhoneNumberUtil sharedInstance] parse:_cleanedPhonenumber defaultRegion:_defaultCountryCode error:nil];
|
||||
msisdn = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[super encodeWithCoder:coder];
|
||||
|
||||
[coder encodeObject:_type forKey:@"type"];
|
||||
[coder encodeObject:_textNumber forKey:@"textNumber"];
|
||||
[coder encodeObject:_cleanedPhonenumber forKey:@"cleanedPhonenumber"];
|
||||
[coder encodeObject:_defaultCountryCode forKey:@"countryCode"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "MXKContact.h"
|
||||
|
||||
@interface MXKSectionedContacts : NSObject {
|
||||
int contactsCount;
|
||||
NSArray<NSString*> *sectionTitles;
|
||||
NSArray<NSArray<MXKContact*>*> *sectionedContacts;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) int contactsCount;
|
||||
@property (nonatomic, readonly) NSArray<NSString*> *sectionTitles;
|
||||
@property (nonatomic, readonly) NSArray<NSArray<MXKContact*>*> *sectionedContacts;
|
||||
|
||||
- (instancetype)initWithContacts:(NSArray<NSArray<MXKContact*>*> *)inSectionedContacts andTitles:(NSArray<NSString*> *)titles andCount:(int)count;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "MXKSectionedContacts.h"
|
||||
|
||||
@implementation MXKSectionedContacts
|
||||
|
||||
@synthesize contactsCount, sectionTitles, sectionedContacts;
|
||||
|
||||
-(id)initWithContacts:(NSArray<NSArray<MXKContact*> *> *)inSectionedContacts andTitles:(NSArray<NSString *> *)titles andCount:(int)count {
|
||||
if (self = [super init]) {
|
||||
contactsCount = count;
|
||||
sectionedContacts = inSectionedContacts;
|
||||
sectionTitles = titles;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user