From c9f8958d5a3a74de70cc71f3d78e77f24d09057f Mon Sep 17 00:00:00 2001 From: ylecollen Date: Tue, 20 Jan 2015 13:33:01 +0100 Subject: [PATCH] Add a 4th sections : contacts The contacts are displayed in a list. There is no check if one of the field is a matrix identifier. --- matrixConsole.xcodeproj/project.pbxproj | 42 ++++ matrixConsole/API/ContactManager.h | 37 ++++ matrixConsole/API/ContactManager.m | 163 ++++++++++++++++ matrixConsole/AppDelegate.m | 7 + matrixConsole/Base.lproj/Main.storyboard | 81 +++++++- matrixConsole/Model/ConsoleContact.h | 36 ++++ matrixConsole/Model/ConsoleContact.m | 182 ++++++++++++++++++ matrixConsole/Model/ConsoleEmail.h | 25 +++ matrixConsole/Model/ConsoleEmail.m | 21 ++ matrixConsole/Model/ConsolePhoneNumber.h | 24 +++ matrixConsole/Model/ConsolePhoneNumber.m | 21 ++ matrixConsole/Model/SectionedContacts.h | 31 +++ matrixConsole/Model/SectionedContacts.m | 31 +++ matrixConsole/View/ContactTableCell.h | 24 +++ matrixConsole/View/ContactTableCell.m | 20 ++ .../ViewController/ContactsViewController.h | 26 +++ .../ViewController/ContactsViewController.m | 94 +++++++++ 17 files changed, 862 insertions(+), 3 deletions(-) create mode 100644 matrixConsole/API/ContactManager.h create mode 100644 matrixConsole/API/ContactManager.m create mode 100644 matrixConsole/Model/ConsoleContact.h create mode 100644 matrixConsole/Model/ConsoleContact.m create mode 100644 matrixConsole/Model/ConsoleEmail.h create mode 100644 matrixConsole/Model/ConsoleEmail.m create mode 100644 matrixConsole/Model/ConsolePhoneNumber.h create mode 100644 matrixConsole/Model/ConsolePhoneNumber.m create mode 100644 matrixConsole/Model/SectionedContacts.h create mode 100644 matrixConsole/Model/SectionedContacts.m create mode 100644 matrixConsole/View/ContactTableCell.h create mode 100644 matrixConsole/View/ContactTableCell.m create mode 100644 matrixConsole/ViewController/ContactsViewController.h create mode 100644 matrixConsole/ViewController/ContactsViewController.m diff --git a/matrixConsole.xcodeproj/project.pbxproj b/matrixConsole.xcodeproj/project.pbxproj index a6d3d8bab..b236a0ca7 100644 --- a/matrixConsole.xcodeproj/project.pbxproj +++ b/matrixConsole.xcodeproj/project.pbxproj @@ -9,6 +9,13 @@ /* Begin PBXBuildFile section */ 710210A41A67A4B600364868 /* ConsoleGrowingTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 710210A31A67A4B600364868 /* ConsoleGrowingTextView.m */; }; 71193D241A6D64F900E59A9E /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71193D231A6D64F900E59A9E /* AddressBook.framework */; }; + 71193D291A6E3DC000E59A9E /* ContactsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 71193D281A6E3DC000E59A9E /* ContactsViewController.m */; }; + 71193D2C1A6E433900E59A9E /* ContactTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 71193D2B1A6E433900E59A9E /* ContactTableCell.m */; }; + 71193D361A6E49F000E59A9E /* ConsoleContact.m in Sources */ = {isa = PBXBuildFile; fileRef = 71193D311A6E49F000E59A9E /* ConsoleContact.m */; }; + 71193D371A6E49F000E59A9E /* ConsoleEmail.m in Sources */ = {isa = PBXBuildFile; fileRef = 71193D331A6E49F000E59A9E /* ConsoleEmail.m */; }; + 71193D381A6E49F000E59A9E /* ConsolePhoneNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 71193D351A6E49F000E59A9E /* ConsolePhoneNumber.m */; }; + 71193D3B1A6E50EC00E59A9E /* ContactManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 71193D3A1A6E50EC00E59A9E /* ContactManager.m */; }; + 71193D3E1A6E61AD00E59A9E /* SectionedContacts.m in Sources */ = {isa = PBXBuildFile; fileRef = 71193D3D1A6E61AD00E59A9E /* SectionedContacts.m */; }; 71D2E4EC1A49814B000DE015 /* MemberActionsCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 71D2E4EB1A49814B000DE015 /* MemberActionsCell.m */; }; 71DB9DC11A495B6400504A09 /* MemberViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 71DB9DC01A495B6400504A09 /* MemberViewController.m */; }; 71E94A771A5C4020009F52E5 /* PieChartView.m in Sources */ = {isa = PBXBuildFile; fileRef = 71E94A761A5C4020009F52E5 /* PieChartView.m */; }; @@ -74,6 +81,20 @@ 710210A21A67A4B600364868 /* ConsoleGrowingTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConsoleGrowingTextView.h; sourceTree = ""; }; 710210A31A67A4B600364868 /* ConsoleGrowingTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConsoleGrowingTextView.m; sourceTree = ""; }; 71193D231A6D64F900E59A9E /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; + 71193D271A6E3DC000E59A9E /* ContactsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsViewController.h; sourceTree = ""; }; + 71193D281A6E3DC000E59A9E /* ContactsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactsViewController.m; sourceTree = ""; }; + 71193D2A1A6E433900E59A9E /* ContactTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactTableCell.h; sourceTree = ""; }; + 71193D2B1A6E433900E59A9E /* ContactTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactTableCell.m; sourceTree = ""; }; + 71193D301A6E49F000E59A9E /* ConsoleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConsoleContact.h; sourceTree = ""; }; + 71193D311A6E49F000E59A9E /* ConsoleContact.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConsoleContact.m; sourceTree = ""; }; + 71193D321A6E49F000E59A9E /* ConsoleEmail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConsoleEmail.h; sourceTree = ""; }; + 71193D331A6E49F000E59A9E /* ConsoleEmail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConsoleEmail.m; sourceTree = ""; }; + 71193D341A6E49F000E59A9E /* ConsolePhoneNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConsolePhoneNumber.h; sourceTree = ""; }; + 71193D351A6E49F000E59A9E /* ConsolePhoneNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConsolePhoneNumber.m; sourceTree = ""; }; + 71193D391A6E50EC00E59A9E /* ContactManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactManager.h; sourceTree = ""; }; + 71193D3A1A6E50EC00E59A9E /* ContactManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactManager.m; sourceTree = ""; }; + 71193D3C1A6E61AD00E59A9E /* SectionedContacts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SectionedContacts.h; sourceTree = ""; }; + 71193D3D1A6E61AD00E59A9E /* SectionedContacts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SectionedContacts.m; sourceTree = ""; }; 71D2E4EA1A49814B000DE015 /* MemberActionsCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemberActionsCell.h; sourceTree = ""; }; 71D2E4EB1A49814B000DE015 /* MemberActionsCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MemberActionsCell.m; sourceTree = ""; }; 71DB9DBF1A495B6400504A09 /* MemberViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemberViewController.h; sourceTree = ""; }; @@ -219,6 +240,8 @@ F021FBEC1A5EF57300EA3AE6 /* API */ = { isa = PBXGroup; children = ( + 71193D391A6E50EC00E59A9E /* ContactManager.h */, + 71193D3A1A6E50EC00E59A9E /* ContactManager.m */, F02900B91A63C71E00356F7D /* ConsoleTools.h */, F02900BA1A63C71E00356F7D /* ConsoleTools.m */, F021FBED1A5EF57300EA3AE6 /* MediaLoader.h */, @@ -232,6 +255,8 @@ F03EF5E919F171EB00A0EE52 /* ViewController */ = { isa = PBXGroup; children = ( + 71193D271A6E3DC000E59A9E /* ContactsViewController.h */, + 71193D281A6E3DC000E59A9E /* ContactsViewController.m */, F03EF5EA19F171EB00A0EE52 /* HomeViewController.h */, F03EF5EB19F171EB00A0EE52 /* HomeViewController.m */, F03EF5EC19F171EB00A0EE52 /* LoginViewController.h */, @@ -253,6 +278,8 @@ F03EF5FC19F1762000A0EE52 /* View */ = { isa = PBXGroup; children = ( + 71193D2A1A6E433900E59A9E /* ContactTableCell.h */, + 71193D2B1A6E433900E59A9E /* ContactTableCell.m */, F00B5DB71A1B9BCE00EA1C8D /* CustomImageView.h */, F00B5DB81A1B9BCE00EA1C8D /* CustomImageView.m */, 71D2E4EA1A49814B000DE015 /* MemberActionsCell.h */, @@ -276,14 +303,22 @@ F0465AF71A251F85003639F9 /* Model */ = { isa = PBXGroup; children = ( + 71193D301A6E49F000E59A9E /* ConsoleContact.h */, + 71193D311A6E49F000E59A9E /* ConsoleContact.m */, + 71193D321A6E49F000E59A9E /* ConsoleEmail.h */, + 71193D331A6E49F000E59A9E /* ConsoleEmail.m */, 710210A21A67A4B600364868 /* ConsoleGrowingTextView.h */, 710210A31A67A4B600364868 /* ConsoleGrowingTextView.m */, + 71193D341A6E49F000E59A9E /* ConsolePhoneNumber.h */, + 71193D351A6E49F000E59A9E /* ConsolePhoneNumber.m */, F0D942F41A31F3A300826CC1 /* RecentRoom.h */, F0D942F51A31F3A300826CC1 /* RecentRoom.m */, F0465AF81A251F85003639F9 /* RoomMessage.h */, F0465AF91A251F85003639F9 /* RoomMessage.m */, F01A0FF11A27314B009FAE2F /* RoomMessageComponent.h */, F01A0FF21A27314B009FAE2F /* RoomMessageComponent.m */, + 71193D3C1A6E61AD00E59A9E /* SectionedContacts.h */, + 71193D3D1A6E61AD00E59A9E /* SectionedContacts.m */, ); path = Model; sourceTree = ""; @@ -515,10 +550,13 @@ F07A80DB19DD9DE700B621A1 /* AppDelegate.m in Sources */, F03EF5FF19F1762000A0EE52 /* RoomMessageTableCell.m in Sources */, F07A80D819DD9DE700B621A1 /* main.m in Sources */, + 71193D371A6E49F000E59A9E /* ConsoleEmail.m in Sources */, F05B955F19DEED8A008761B0 /* MatrixHandler.m in Sources */, + 71193D3E1A6E61AD00E59A9E /* SectionedContacts.m in Sources */, F021FBEF1A5EF57300EA3AE6 /* MediaLoader.m in Sources */, F03EF5FB19F171EB00A0EE52 /* SettingsViewController.m in Sources */, F02900BB1A63C71E00356F7D /* ConsoleTools.m in Sources */, + 71193D361A6E49F000E59A9E /* ConsoleContact.m in Sources */, F01A0FF31A27314B009FAE2F /* RoomMessageComponent.m in Sources */, F03EF5FA19F171EB00A0EE52 /* RoomViewController.m in Sources */, F03EF5F819F171EB00A0EE52 /* MasterTabBarController.m in Sources */, @@ -531,8 +569,12 @@ F0465AFA1A251F85003639F9 /* RoomMessage.m in Sources */, F021FBF21A5F1F8E00EA3AE6 /* MediaManager.m in Sources */, F04EE51F1A3A01D500C64930 /* APNSHandler.m in Sources */, + 71193D291A6E3DC000E59A9E /* ContactsViewController.m in Sources */, F03C47111A02952800E445AB /* CustomAlert.m in Sources */, F0E84D401A1F9AEC005F2E42 /* RecentsTableViewCell.m in Sources */, + 71193D381A6E49F000E59A9E /* ConsolePhoneNumber.m in Sources */, + 71193D3B1A6E50EC00E59A9E /* ContactManager.m in Sources */, + 71193D2C1A6E433900E59A9E /* ContactTableCell.m in Sources */, F02D707619F1DC9E007B47D3 /* RoomMemberTableCell.m in Sources */, F00B5DB91A1B9BCE00EA1C8D /* CustomImageView.m in Sources */, F0D3C30C1A011EF10000D49E /* AppSettings.m in Sources */, diff --git a/matrixConsole/API/ContactManager.h b/matrixConsole/API/ContactManager.h new file mode 100644 index 000000000..13c3c5903 --- /dev/null +++ b/matrixConsole/API/ContactManager.h @@ -0,0 +1,37 @@ +/* + Copyright 2014 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 +#import "SectionedContacts.h" + +// warn when there is a contacts list refresh +extern NSString *const kContactManagerRefreshNotification; + +@interface ContactManager : NSObject { + dispatch_queue_t processingQueue; +} + ++ (id)sharedManager; + +@property (nonatomic, readonly) NSMutableArray *contacts; + +// refresh self.contacts +- (void)refresh; + +// sort the contacts in sectioned arrays to be displayable in a UITableview +- (SectionedContacts *)getSectionedContacts:(NSArray*)contactsList; + +@end diff --git a/matrixConsole/API/ContactManager.m b/matrixConsole/API/ContactManager.m new file mode 100644 index 000000000..b89574ae4 --- /dev/null +++ b/matrixConsole/API/ContactManager.m @@ -0,0 +1,163 @@ +/* + Copyright 2014 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 "ContactManager.h" + +#import "ConsoleContact.h" + +// warn when there is a contacts list refresh +NSString *const kContactManagerRefreshNotification = @"kContactManagerRefreshNotification"; + +@implementation ContactManager +@synthesize contacts; + +#pragma mark Singleton Methods +static ContactManager* sharedContactManager = nil; + ++ (id)sharedManager { + @synchronized(self) { + if(sharedContactManager == nil) + sharedContactManager = [[self alloc] init]; + } + return sharedContactManager; +} + +#pragma mark - + +-(ContactManager *)init { + if (self = [super init]) { + NSString *label = [NSString stringWithFormat:@"ConsoleMatrix.%@.Contacts", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]]; + + processingQueue = dispatch_queue_create([label UTF8String], NULL); + + // put an empty array instead of nil + contacts = [[NSMutableArray alloc] init]; + + // check if the application is allowed to list the contacts + ABAuthorizationStatus cbStatus = ABAddressBookGetAuthorizationStatus(); + + // did not yet request the access + if (cbStatus == kABAuthorizationStatusNotDetermined) { + // request address book access + ABAddressBookRef ab = ABAddressBookCreateWithOptions(nil, nil); + + if (ab) { + ABAddressBookRequestAccessWithCompletion(ab, ^(bool granted, CFErrorRef error) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self refresh]; + }); + + }); + + CFRelease(ab); + } + } else if (cbStatus == kABAuthorizationStatusAuthorized) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self refresh]; + }); + } + } + + return self; +} + +-(void)dealloc { +} + +- (void)refresh +{ + // did not yet request the access + if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) { + // wait that the user gives the Authorization + return; + } + + dispatch_async(processingQueue, ^{ + ABAddressBookRef ab = ABAddressBookCreateWithOptions(nil, nil); + ABRecordRef contactRecord; + int index; + + //CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent(); + CFMutableArrayRef people = (CFMutableArrayRef)ABAddressBookCopyArrayOfAllPeople(ab); + + NSMutableArray* contactsList = [[NSMutableArray alloc] init]; + + if (nil != people) { + int peopleCount = CFArrayGetCount(people); + + for (index = 0; index < peopleCount; index++) { + contactRecord = (ABRecordRef)CFArrayGetValueAtIndex(people, index); + [contactsList addObject:[[ConsoleContact alloc] initWithABRecord:contactRecord]]; + } + + CFRelease(people); + } + + if (ab) { + CFRelease(ab); + } + + contacts = contactsList; + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:kContactManagerRefreshNotification object:nil userInfo:nil]; + }); + }); +} + +- (SectionedContacts *)getSectionedContacts:(NSArray*)contactsList { + UILocalizedIndexedCollation *collation = [UILocalizedIndexedCollation currentCollation]; + + int indexOffset = 0; + + NSInteger index, sectionTitlesCount = [[collation sectionTitles] count]; + NSMutableArray *tmpSectionsArray = [[NSMutableArray alloc] initWithCapacity:(sectionTitlesCount)]; + + sectionTitlesCount += indexOffset; + + for (index = 0; index < sectionTitlesCount; index++) { + NSMutableArray *array = [[NSMutableArray alloc] init]; + [tmpSectionsArray addObject:array]; + } + + int contactsCount = 0; + + for (ConsoleContact *aContact in contactsList) + { + NSInteger section = [collation sectionForObject:aContact collationStringSelector:@selector(displayName)] + indexOffset; + + [[tmpSectionsArray objectAtIndex:section] addObject:aContact]; + ++contactsCount; + } + + NSMutableArray *tmpSectionedContactsTitle = [[NSMutableArray alloc] initWithCapacity:sectionTitlesCount]; + NSMutableArray *shortSectionsArray = [[NSMutableArray alloc] initWithCapacity:sectionTitlesCount]; + + for (index = indexOffset; index < sectionTitlesCount; index++) { + + NSMutableArray *usersArrayForSection = [tmpSectionsArray objectAtIndex:index]; + + if ([usersArrayForSection count] != 0) { + NSArray* sortedUsersArrayForSection = [collation sortedArrayFromArray:usersArrayForSection collationStringSelector:@selector(displayName)]; + [shortSectionsArray addObject:sortedUsersArrayForSection]; + [tmpSectionedContactsTitle addObject:[[[UILocalizedIndexedCollation currentCollation] sectionTitles] objectAtIndex:(index - indexOffset)]]; + } + } + + return [[SectionedContacts alloc] initWithContacts:shortSectionsArray andTitles:tmpSectionedContactsTitle andCount:contactsCount]; +} + +@end diff --git a/matrixConsole/AppDelegate.m b/matrixConsole/AppDelegate.m index 5632fca3d..20bacfb2f 100644 --- a/matrixConsole/AppDelegate.m +++ b/matrixConsole/AppDelegate.m @@ -21,6 +21,7 @@ #import "MatrixHandler.h" #import "MediaManager.h" #import "SettingsViewController.h" +#import "ContactManager.h" @interface AppDelegate () @@ -81,6 +82,9 @@ // When user is already logged, we launch the app on Recents [self.masterTabBarController setSelectedIndex:TABBAR_RECENTS_INDEX]; } + + // refresh the contacts list + [[ContactManager sharedManager] refresh]; } return YES; } @@ -112,6 +116,9 @@ // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. // Resume Matrix handler [[MatrixHandler sharedHandler] resume]; + + // refresh the contacts list + [[ContactManager sharedManager] refresh]; } - (void)applicationWillTerminate:(UIApplication *)application { diff --git a/matrixConsole/Base.lproj/Main.storyboard b/matrixConsole/Base.lproj/Main.storyboard index de5ff108e..2f7af98f7 100644 --- a/matrixConsole/Base.lproj/Main.storyboard +++ b/matrixConsole/Base.lproj/Main.storyboard @@ -995,9 +995,10 @@ + - + @@ -1232,7 +1233,7 @@ - + @@ -1249,7 +1250,7 @@ - + @@ -1355,6 +1356,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/matrixConsole/Model/ConsoleContact.h b/matrixConsole/Model/ConsoleContact.h new file mode 100644 index 000000000..c07ec4266 --- /dev/null +++ b/matrixConsole/Model/ConsoleContact.h @@ -0,0 +1,36 @@ +/* + Copyright 2014 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 +#import + +@interface ConsoleContact : NSObject + +// display name +@property (nonatomic, copy, readwrite) NSString *displayName; + +@property (nonatomic, copy, readwrite) UIImage *thumbnail; + +// array of ConsolePhoneNumber +@property (nonatomic, readwrite) NSArray *phoneNumbers; +// array of ConsoleEmail +@property (nonatomic, readwrite) NSArray *emailAddresses; +// array of strings +@property (nonatomic, readonly) NSArray* matrixIdentifiers; + +- (id) initWithABRecord:(ABRecordRef)record; + +@end \ No newline at end of file diff --git a/matrixConsole/Model/ConsoleContact.m b/matrixConsole/Model/ConsoleContact.m new file mode 100644 index 000000000..7916705ef --- /dev/null +++ b/matrixConsole/Model/ConsoleContact.m @@ -0,0 +1,182 @@ +/* + Copyright 2014 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 "ConsoleContact.h" + +#import "ConsoleEmail.h" +#import "ConsolePhoneNumber.h" + +@implementation ConsoleContact +@synthesize displayName, phoneNumbers, emailAddresses, thumbnail; + +- (id) initWithABRecord:(ABRecordRef)record { + + self = [super init]; + + if (self) { + + self.displayName = (__bridge NSString*) ABRecordCopyCompositeName(record); + + // avoid nil display name + // the display name is used to sort contacts + if (!self.displayName) { + self.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; + } + } + + ConsolePhoneNumber* pn = [[ConsolePhoneNumber alloc] init]; + pn.type = lbl; + pn.textNumber = phoneVal; + + [pns addObject:pn]; + + if (lblRef) { + CFRelease(lblRef); + } + if (localizedLblRef) { + CFRelease(localizedLblRef); + } + } + + // release meory + if (phoneRef) { + CFRelease(phoneRef); + } + } + + CFRelease(multi); + self.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; + } + } + + ConsoleEmail* email = [[ConsoleEmail alloc] init]; + email.type = lbl; + email.emailAddress = emailVal; + + [emails addObject: email]; + + if (lblRef) { + CFRelease(lblRef); + } + + if (localizedLblRef) { + CFRelease(localizedLblRef); + } + } + + if (emailValRef) { + CFRelease(emailValRef); + } + } + + CFRelease(multi); + + self.emailAddresses = emails; + + // thumbnail/picture + // check whether the contact has a picture + if (ABPersonHasImageData(record)) + { + CFDataRef dataRef; + + dataRef = ABPersonCopyImageDataWithFormat(record, kABPersonImageFormatThumbnail); + if (dataRef) + { + self.thumbnail = [UIImage imageWithData:(__bridge NSData*)dataRef]; + CFRelease(dataRef); + } + } + } + return self; +} + +- (NSArray*) matrixIdentifiers { + NSMutableArray* identifiers = [[NSMutableArray alloc] init]; + + for(ConsolePhoneNumber* pn in self.phoneNumbers) { + if (pn.isMatrixIdentifier) { + [identifiers addObject:pn.textNumber]; + } + } + + for(ConsoleEmail* email in self.emailAddresses) { + if (email.isMatrixIdentifier) { + [identifiers addObject:email.emailAddress]; + } + } + + return identifiers; +} + +@end diff --git a/matrixConsole/Model/ConsoleEmail.h b/matrixConsole/Model/ConsoleEmail.h new file mode 100644 index 000000000..493e594c0 --- /dev/null +++ b/matrixConsole/Model/ConsoleEmail.h @@ -0,0 +1,25 @@ +/* + Copyright 2014 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 + +@interface ConsoleEmail : NSObject + +@property (nonatomic, readwrite) NSString *type; +@property (nonatomic, readwrite) NSString *emailAddress; +@property (nonatomic, readwrite) BOOL isMatrixIdentifier; + +@end diff --git a/matrixConsole/Model/ConsoleEmail.m b/matrixConsole/Model/ConsoleEmail.m new file mode 100644 index 000000000..9848bb3b8 --- /dev/null +++ b/matrixConsole/Model/ConsoleEmail.m @@ -0,0 +1,21 @@ +/* + Copyright 2014 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 "ConsoleEmail.h" + +@implementation ConsoleEmail + +@synthesize type, emailAddress, isMatrixIdentifier; +@end diff --git a/matrixConsole/Model/ConsolePhoneNumber.h b/matrixConsole/Model/ConsolePhoneNumber.h new file mode 100644 index 000000000..ce9716fb7 --- /dev/null +++ b/matrixConsole/Model/ConsolePhoneNumber.h @@ -0,0 +1,24 @@ +/* + Copyright 2014 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 + +@interface ConsolePhoneNumber : NSObject + +@property (nonatomic, readwrite) NSString *type; +@property (nonatomic, readwrite) NSString *textNumber; +@property (nonatomic, readwrite) BOOL isMatrixIdentifier; + +@end \ No newline at end of file diff --git a/matrixConsole/Model/ConsolePhoneNumber.m b/matrixConsole/Model/ConsolePhoneNumber.m new file mode 100644 index 000000000..b322cf763 --- /dev/null +++ b/matrixConsole/Model/ConsolePhoneNumber.m @@ -0,0 +1,21 @@ +/* + Copyright 2014 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 "ConsolePhoneNumber.h" + +@implementation ConsolePhoneNumber +@synthesize type, textNumber, isMatrixIdentifier; +@end \ No newline at end of file diff --git a/matrixConsole/Model/SectionedContacts.h b/matrixConsole/Model/SectionedContacts.h new file mode 100644 index 000000000..2034c9df4 --- /dev/null +++ b/matrixConsole/Model/SectionedContacts.h @@ -0,0 +1,31 @@ +/* + Copyright 2014 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 + +@interface SectionedContacts : NSObject { + int contactsCount; + NSArray *sectionTitles; + NSArray *sectionedContacts; +} + +@property (nonatomic, readonly) int contactsCount; +@property (nonatomic, readonly) NSArray *sectionTitles; +@property (nonatomic, readonly) NSArray *sectionedContacts; + +-(id)initWithContacts:(NSArray *)_sectionedContacts andTitles:(NSArray *)titles andCount:(int)count; + +@end diff --git a/matrixConsole/Model/SectionedContacts.m b/matrixConsole/Model/SectionedContacts.m new file mode 100644 index 000000000..c5833b316 --- /dev/null +++ b/matrixConsole/Model/SectionedContacts.m @@ -0,0 +1,31 @@ +/* + Copyright 2014 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 "SectionedContacts.h" + +@implementation SectionedContacts + +@synthesize contactsCount, sectionTitles, sectionedContacts; + +-(id)initWithContacts:(NSArray *)_sectionedContacts andTitles:(NSArray *)titles andCount:(int)count { + if (self = [super init]) { + contactsCount = count; + sectionedContacts = _sectionedContacts; + sectionTitles = titles; + } + return self; +} + +@end diff --git a/matrixConsole/View/ContactTableCell.h b/matrixConsole/View/ContactTableCell.h new file mode 100644 index 000000000..87b204bba --- /dev/null +++ b/matrixConsole/View/ContactTableCell.h @@ -0,0 +1,24 @@ +/* + Copyright 2014 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 +#import "CustomImageView.h" + +@interface ContactTableCell : UITableViewCell +@property (strong, nonatomic) IBOutlet CustomImageView *thumbnail; +@property (strong, nonatomic) IBOutlet UILabel *contactDisplayName; +@end + diff --git a/matrixConsole/View/ContactTableCell.m b/matrixConsole/View/ContactTableCell.m new file mode 100644 index 000000000..b777dd710 --- /dev/null +++ b/matrixConsole/View/ContactTableCell.m @@ -0,0 +1,20 @@ +/* + Copyright 2014 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 "ContactTableCell.h" + +@implementation ContactTableCell +@end \ No newline at end of file diff --git a/matrixConsole/ViewController/ContactsViewController.h b/matrixConsole/ViewController/ContactsViewController.h new file mode 100644 index 000000000..8ed2e21b7 --- /dev/null +++ b/matrixConsole/ViewController/ContactsViewController.h @@ -0,0 +1,26 @@ +/* + Copyright 2014 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 + +#import "SectionedContacts.h" + +@interface ContactsViewController : UITableViewController { + SectionedContacts *sectionedContacts; +} + +@end + diff --git a/matrixConsole/ViewController/ContactsViewController.m b/matrixConsole/ViewController/ContactsViewController.m new file mode 100644 index 000000000..d4e3e2979 --- /dev/null +++ b/matrixConsole/ViewController/ContactsViewController.m @@ -0,0 +1,94 @@ +/* + Copyright 2014 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 "ContactsViewController.h" + +#import "ContactManager.h" +#import "ConsoleContact.h" + +#import "ContactTableCell.h" + +@implementation ContactsViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + sectionedContacts = nil; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onContactsRefresh:) name:kContactManagerRefreshNotification object:nil]; +} + +#pragma mark - UITableView delegate +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + if (!sectionedContacts) { + ContactManager* sharedManager = [ContactManager sharedManager]; + + sectionedContacts = [sharedManager getSectionedContacts:sharedManager.contacts]; + } + + return sectionedContacts.sectionedContacts.count; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [[sectionedContacts.sectionedContacts objectAtIndex:section] count]; +} + +- (NSString *)tableView:(UITableView *)aTableView titleForHeaderInSection:(NSInteger)section { + if (sectionedContacts.sectionTitles.count <= section) { + return nil; + } + else { + return (NSString*)[sectionedContacts.sectionTitles objectAtIndex:section]; + } +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + ContactTableCell* cell = [tableView dequeueReusableCellWithIdentifier:@"ContactCell" forIndexPath:indexPath]; + + ConsoleContact* contact = nil; + + if (indexPath.section < sectionedContacts.sectionedContacts.count) { + NSArray *thisSection = [sectionedContacts.sectionedContacts objectAtIndex:indexPath.section]; + + if (indexPath.row < thisSection.count) { + contact = [thisSection objectAtIndex:indexPath.row]; + } + } + + // set the thumbnail + if (contact.thumbnail) { + cell.thumbnail.image = contact.thumbnail; + } else { + cell.thumbnail.image = [UIImage imageNamed:@"default-profile"]; + } + + cell.thumbnail.layer.cornerRadius = cell.thumbnail.frame.size.width / 2; + cell.thumbnail.clipsToBounds = YES; + + // and the displayname + cell.contactDisplayName.text = contact.displayName; + + return cell; +} + +#pragma mark - Actions + +- (void)onContactsRefresh:(NSNotification *)notif { + sectionedContacts = nil; + [self.tableView reloadData]; +} + +@end