shlist

share and manage lists between multiple people
Log | Files | Refs

commit 4fa7f7baac7418a7850c3dd49186a15908103528
parent aa3d22bff3e0a42a3106288b8bba6f7375edf6e2
Author: Kyle Milz <kyle@Kyles-MacBook-Pro.local>
Date:   Sun, 13 Sep 2015 19:20:33 -0600

ios: make address book class a singleton

Diffstat:
Aios-ng/ContactsTableViewController.h | 6++++++
Aios-ng/ContactsTableViewController.m | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mios-ng/shlist.xcodeproj/project.pbxproj | 6++++++
Mios-ng/shlist/AddressBook.h | 19++++++++++++++++++-
Mios-ng/shlist/AddressBook.m | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mios-ng/shlist/Base.lproj/Main.storyboard | 142++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mios-ng/shlist/ListDetailTableViewController.m | 3++-
Mios-ng/shlist/SharedList.h | 6+++++-
Mios-ng/shlist/SharedListsTableViewController.m | 132+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mios-ng/shlist/ShlistServer.m | 57++++++++++++++++++++++++++++++++++++++++++++++-----------
10 files changed, 475 insertions(+), 132 deletions(-)

diff --git a/ios-ng/ContactsTableViewController.h b/ios-ng/ContactsTableViewController.h @@ -0,0 +1,5 @@ +#import <UIKit/UIKit.h> + +@interface ContactsTableViewController : UITableViewController + +@end +\ No newline at end of file diff --git a/ios-ng/ContactsTableViewController.m b/ios-ng/ContactsTableViewController.m @@ -0,0 +1,161 @@ +#import "ContactsTableViewController.h" +#import "AddressBook.h" + +@interface ContactsTableViewController () + +@property (strong, retain) AddressBook *address_book; +@property (strong, retain) NSMutableArray *cells; +@property (strong, retain) NSArray *section_to_letter; + +@end + +@implementation ContactsTableViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // Uncomment the following line to preserve selection between presentations. + // self.clearsSelectionOnViewWillAppear = NO; + + // get a copy of the address book singleton + _address_book = [AddressBook shared_address_book]; + + // we'll always have 26 or less letters in this dictionary + NSMutableDictionary *letter_to_contact_map = [NSMutableDictionary dictionaryWithCapacity:26]; + + for (Contact *contact in _address_book.contacts) { + NSString *letter; + if (contact.last_name) + letter = [[contact.last_name uppercaseString] substringToIndex:1]; + else if (contact.first_name) + letter = [[contact.first_name uppercaseString] substringToIndex:1]; + else + // not sure if this can happen or not + continue; + + if (letter_to_contact_map[letter] != nil) + [[letter_to_contact_map objectForKey:letter] addObject:contact]; + else { + NSMutableArray *tmp = [NSMutableArray arrayWithObject:contact]; + [letter_to_contact_map setObject:tmp forKey:letter]; + } + } + + // get an array of first letters sorted lexicographically + _section_to_letter = [[letter_to_contact_map allKeys] + sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + _cells = [[NSMutableArray alloc] init]; + + for (NSString *letter in _section_to_letter) + [_cells addObject:[letter_to_contact_map objectForKey:letter]]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return [_cells count]; +} + +- (NSInteger)tableView:(UITableView *)tableView + numberOfRowsInSection:(NSInteger)section +{ + return [[_cells objectAtIndex:section] count]; +} + + +- (UITableViewCell *)tableView:(UITableView *)tableView + cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + int section = [indexPath section]; + int row = [indexPath row]; + Contact *contact = [[_cells objectAtIndex:section] objectAtIndex:row]; + + UITableViewCell *cell; + if (contact.first_name && contact.last_name) + cell = [tableView dequeueReusableCellWithIdentifier:@"contact_cell_two_name" forIndexPath:indexPath]; + else + cell = [tableView dequeueReusableCellWithIdentifier:@"contact_cell_one_name" forIndexPath:indexPath]; + + if (contact.first_name && contact.last_name) { + UILabel *first = (UILabel *)[cell viewWithTag:1]; + UILabel *second_bold = (UILabel *)[cell viewWithTag:2]; + + first.text = contact.first_name; + second_bold.text = contact.last_name; + } + else if (contact.first_name) { + // no last name + UILabel *first = (UILabel *)[cell viewWithTag:1]; + first.text = contact.first_name; + } + else if (contact.last_name) { + // no first name + UILabel *first = (UILabel *)[cell viewWithTag:1]; + first.text = contact.last_name; + } + else { + UILabel *first = (UILabel *)[cell viewWithTag:1]; + // neither first nor last names exist + // show first phone number if we have no other info + first.text = [contact.phone_numbers objectAtIndex:0]; + } + + return cell; +} + +// row was selected, toggle the accessory checkmark and call network functions +- (void)tableView:(UITableView *)tableView + didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + int section = [indexPath section]; + int row = [indexPath row]; + + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + Contact *contact = [[_cells objectAtIndex:section] objectAtIndex:row]; + + if ([cell accessoryType] == UITableViewCellAccessoryNone) + [cell setAccessoryType:UITableViewCellAccessoryCheckmark]; + else + [cell setAccessoryType:UITableViewCellAccessoryNone]; + + NSLog(@"info: selected %@ %@ who has %i phone numbers", + contact.first_name, contact.last_name, [contact.phone_numbers count]); +} + +// programatically assign section headers, in this case they're letters +- (NSString *)tableView:(UITableView *)tableView + titleForHeaderInSection:(NSInteger)section +{ + return [_section_to_letter objectAtIndex:section]; +} + +// needed to make the section header font bigger +- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view + forSection:(NSInteger)section +{ + UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view; + + header.textLabel.font = [UIFont boldSystemFontOfSize:18]; +} + + +// these two delegates below put the "quick index" ribbon on the right side +- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView +{ + return [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles]; +} + +- (NSInteger)tableView:(UITableView *)tableView + sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index +{ + return [[UILocalizedIndexedCollation currentCollation] sectionForSectionIndexTitleAtIndex:index]; +} + +@end +\ No newline at end of file diff --git a/ios-ng/shlist.xcodeproj/project.pbxproj b/ios-ng/shlist.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 27C70F301B33F4FA00DADEB3 /* SharedListsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C70F2F1B33F4FA00DADEB3 /* SharedListsTableViewController.m */; }; 27C70F321B3650CB00DADEB3 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 27C70F311B3650CB00DADEB3 /* libsqlite3.dylib */; }; 27C70F351B36513200DADEB3 /* DBManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C70F341B36513200DADEB3 /* DBManager.m */; }; + 27D805731BA2649D00867494 /* ContactsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D805721BA2649D00867494 /* ContactsTableViewController.m */; }; 27DCC9DE1B8A98D400207340 /* dollar103-2.png in Resources */ = {isa = PBXBuildFile; fileRef = 27DCC9DD1B8A98D400207340 /* dollar103-2.png */; }; 27DCC9E81B9EB4E800207340 /* information15-3.png in Resources */ = {isa = PBXBuildFile; fileRef = 27DCC9E71B9EB4E800207340 /* information15-3.png */; }; 27DCC9EB1B9FF89E00207340 /* AddressBook.m in Sources */ = {isa = PBXBuildFile; fileRef = 27DCC9EA1B9FF89E00207340 /* AddressBook.m */; }; @@ -69,6 +70,8 @@ 27C70F311B3650CB00DADEB3 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; 27C70F331B36513200DADEB3 /* DBManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBManager.h; sourceTree = "<group>"; }; 27C70F341B36513200DADEB3 /* DBManager.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = DBManager.m; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; }; + 27D805711BA2649D00867494 /* ContactsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsTableViewController.h; sourceTree = SOURCE_ROOT; }; + 27D805721BA2649D00867494 /* ContactsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactsTableViewController.m; sourceTree = SOURCE_ROOT; }; 27DCC9DD1B8A98D400207340 /* dollar103-2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dollar103-2.png"; path = "../../../Downloads/dollar103-2.png"; sourceTree = "<group>"; }; 27DCC9E71B9EB4E800207340 /* information15-3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "information15-3.png"; path = "../../../Downloads/information15-3.png"; sourceTree = "<group>"; }; 27DCC9E91B9FF89E00207340 /* AddressBook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddressBook.h; sourceTree = "<group>"; }; @@ -134,6 +137,8 @@ 27DCC9EA1B9FF89E00207340 /* AddressBook.m */, 27C70F061B32AF8000DADEB3 /* AppDelegate.h */, 27C70F071B32AF8000DADEB3 /* AppDelegate.m */, + 27D805711BA2649D00867494 /* ContactsTableViewController.h */, + 27D805721BA2649D00867494 /* ContactsTableViewController.m */, 27B039FD1B43B6830054B6D2 /* ContactsViewController.h */, 27B039FE1B43B6830054B6D2 /* ContactsViewController.m */, 27DCC9DD1B8A98D400207340 /* dollar103-2.png */, @@ -290,6 +295,7 @@ 27AAC22C1B50ABAF00D99171 /* NewItemTableViewController.m in Sources */, BF7776BC1B38D0DB00526CB0 /* ListItem.m in Sources */, 27C70F0B1B32AF8000DADEB3 /* ShlistServer.m in Sources */, + 27D805731BA2649D00867494 /* ContactsTableViewController.m in Sources */, 27C70F2A1B33D1C900DADEB3 /* SharedList.m in Sources */, 27C70F2D1B33F3C300DADEB3 /* NewListViewController.m in Sources */, 27C70F081B32AF8000DADEB3 /* AppDelegate.m in Sources */, diff --git a/ios-ng/shlist/AddressBook.h b/ios-ng/shlist/AddressBook.h @@ -2,6 +2,22 @@ @interface AddressBook : NSObject -@property NSMutableDictionary *name_map; +@property (strong, retain) NSMutableArray *contacts; +@property int num_contacts; + +// returns singleton instance ++ (id) shared_address_book; + +- (void) wait_for_ready; + +@property int ready; @end + +@interface Contact : NSObject + +@property NSString *first_name; +@property NSString *last_name; +@property NSMutableArray *phone_numbers; + +@end +\ No newline at end of file diff --git a/ios-ng/shlist/AddressBook.m b/ios-ng/shlist/AddressBook.m @@ -2,14 +2,33 @@ #include <AddressBook/AddressBook.h> #import <UIKit/UIKit.h> +@interface AddressBook () + +@end + +// empty implementation +@implementation Contact +@end @implementation AddressBook ++ (id)shared_address_book +{ + static AddressBook *address_book = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + address_book = [[self alloc] init]; + address_book.ready = 0; + }); + return address_book; +} + - (id)init { self = [super init]; if (self) { + _contacts = [[NSMutableArray alloc] init]; ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); if (status == kABAuthorizationStatusDenied || status == kABAuthorizationStatusRestricted) { @@ -30,6 +49,8 @@ return self; } + // ABAddressBookRegisterExternalChangeCallback(<#ABAddressBookRef addressBook#>, <#ABExternalChangeCallback callback#>, <#void *context#>) + ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { if (error) { NSLog(@"ABAddressBookRequestAccessWithCompletion error: %@", CFBridgingRelease(error)); @@ -60,46 +81,59 @@ NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook)); NSInteger numberOfPeople = [allPeople count]; - _name_map = [NSMutableDictionary dictionaryWithCapacity:numberOfPeople]; - for (NSInteger i = 0; i < numberOfPeople; i++) { ABRecordRef person = (__bridge ABRecordRef)allPeople[i]; + Contact *contact = [[Contact alloc] init]; - NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty)); - // NSString *lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty)); - // NSLog(@"Name:%@ %@", firstName, lastName); + // don't enforce these existing on purpose + contact.first_name = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty)); + contact.last_name = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty)); ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty); - - if (firstName == nil) { - // if we don't have a first name then we can't display it - continue; - } - CFIndex numberOfPhoneNumbers = ABMultiValueGetCount(phoneNumbers); + contact.phone_numbers = [[NSMutableArray alloc] init]; for (CFIndex i = 0; i < numberOfPhoneNumbers; i++) { NSString *phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phoneNumbers, i)); - if (phoneNumber == nil) { - // if we have a name but no phone number, there's - // nothing we can do + if (phoneNumber == nil) continue; - } phoneNumber = [phoneNumber stringByReplacingOccurrencesOfString:@" " withString:@""]; phoneNumber = [phoneNumber stringByReplacingOccurrencesOfString:@"(" withString:@""]; phoneNumber = [phoneNumber stringByReplacingOccurrencesOfString:@")" withString:@""]; phoneNumber = [phoneNumber stringByReplacingOccurrencesOfString:@"-" withString:@""]; - [_name_map setObject:firstName forKey:phoneNumber]; - - // NSLog(@" phone:%@", phoneNumber); + [contact.phone_numbers addObject:phoneNumber]; } - CFRelease(phoneNumbers); - // NSLog(@"============================================="); + [_contacts addObject:contact]; + } + + _num_contacts = [_contacts count]; + _ready = 1; + + NSLog(@"info: address book: %i contacts found", _num_contacts); +} + +- (void) wait_for_ready +{ + int cumulative_ms = 0; + int sleep_for_ms = 10; + // wait for the database to become ready, no upper bound + while (!_ready) { + usleep(sleep_for_ms * 1000); + cumulative_ms += sleep_for_ms; + + // if we've spun for over a second reduce polling speed + if (cumulative_ms > 1 * 1000) { + NSLog(@"warn: address book: not ready for more than %i s", + cumulative_ms / 1000); + sleep_for_ms = 1 * 1000; + } } + + NSLog(@"info: address book: ready after %i ms", cumulative_ms); } @end \ No newline at end of file diff --git a/ios-ng/shlist/Base.lproj/Main.storyboard b/ios-ng/shlist/Base.lproj/Main.storyboard @@ -30,7 +30,7 @@ <label opaque="NO" userInteractionEnabled="NO" tag="2" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="btC-Lf-VTy"> <rect key="frame" x="32" y="11" width="46" height="21"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> <switch opaque="NO" tag="5" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="n1B-AB-bme"> @@ -39,7 +39,7 @@ <label opaque="NO" userInteractionEnabled="NO" tag="4" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Owner" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0TP-dF-f2P"> <rect key="frame" x="451" y="11" width="51" height="21"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" tag="3" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Quantity" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="upb-uA-yH2"> @@ -84,7 +84,7 @@ </tableViewController> <placeholder placeholderIdentifier="IBFirstResponder" id="H64-xB-1er" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> - <point key="canvasLocation" x="1172" y="-270"/> + <point key="canvasLocation" x="1984" y="-270"/> </scene> <!--Add Item--> <scene sceneID="OeV-vW-TVD"> @@ -93,7 +93,7 @@ <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="sGb-Al-WmL"> <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/> + <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/> <sections> <tableViewSection headerTitle="Item Details" id="2DB-BM-NLj"> <cells> @@ -105,7 +105,7 @@ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Name" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GRs-CY-ps2"> <rect key="frame" x="8" y="11" width="46" height="21"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="&lt;item name&gt;" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RxZ-xc-Qog"> @@ -129,7 +129,7 @@ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Shared" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MsQ-Iq-XOk"> <rect key="frame" x="8" y="11" width="55" height="21"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> <switch opaque="NO" tag="1" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xy3-L7-YrZ"> @@ -157,7 +157,7 @@ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Needs purchase" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Uxj-my-Z2Y"> <rect key="frame" x="8" y="11" width="126" height="21"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> </subviews> @@ -179,7 +179,7 @@ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Owner" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="T4L-tN-tX4"> <rect key="frame" x="8" y="11" width="51" height="21"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;persons name&gt;" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Y92-Cj-Q4R"> @@ -203,7 +203,7 @@ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Cost" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Boa-7b-ddO"> <rect key="frame" x="8" y="11" width="37" height="21"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;cost&gt;" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QhL-xd-rVc"> @@ -243,7 +243,7 @@ <placeholder placeholderIdentifier="IBFirstResponder" id="HuD-ay-3nZ" userLabel="First Responder" sceneMemberID="firstResponder"/> <exit id="lUt-lN-Y7n" userLabel="Exit" sceneMemberID="exit"/> </objects> - <point key="canvasLocation" x="1967" y="61"/> + <point key="canvasLocation" x="2779" y="117"/> </scene> <!--Shlist--> <scene sceneID="hc1-Lv-WtP"> @@ -254,27 +254,27 @@ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <prototypes> - <tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="SharedListPrototypeCell" textLabel="zqW-ht-Knz" detailTextLabel="C9r-D2-l6m" style="IBUITableViewCellStyleSubtitle" id="cBl-Ro-lD0"> + <tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="SharedListPrototypeCell" textLabel="3Op-tK-Z2y" detailTextLabel="HIh-Ve-1bs" style="IBUITableViewCellStyleSubtitle" id="cBl-Ro-lD0"> <autoresizingMask key="autoresizingMask"/> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="cBl-Ro-lD0" id="EBK-6r-ANI"> <autoresizingMask key="autoresizingMask"/> <subviews> - <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="zqW-ht-Knz"> + <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="3Op-tK-Z2y"> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <fontDescription key="fontDescription" type="system" pointSize="16"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> - <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="C9r-D2-l6m"> + <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Detail" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="HIh-Ve-1bs"> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <fontDescription key="fontDescription" type="system" pointSize="11"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> - <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" misplaced="YES" text="3/9" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1XQ-ac-kMc"> - <rect key="frame" x="262" y="11" width="29" height="21"/> - <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> + <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" misplaced="YES" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="shg-tw-Fa9"> + <rect key="frame" x="260" y="5" width="59" height="34"/> + <fontDescription key="fontDescription" type="system" pointSize="22"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> </subviews> @@ -386,25 +386,6 @@ </objects> <point key="canvasLocation" x="2044" y="811"/> </scene> - <!--Contacts--> - <scene sceneID="QO3-Nz-2Rw"> - <objects> - <viewController id="U8c-wO-OWj" userLabel="Contacts" customClass="ContactsViewController" sceneMemberID="viewController"> - <layoutGuides> - <viewControllerLayoutGuide type="top" id="lbu-UM-pRT"/> - <viewControllerLayoutGuide type="bottom" id="FAF-HB-8uI"/> - </layoutGuides> - <view key="view" contentMode="scaleToFill" id="rZG-yU-46M"> - <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> - </view> - <tabBarItem key="tabBarItem" systemItem="contacts" id="Ify-RM-5Th"/> - </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="ess-Hw-XyD" userLabel="First Responder" sceneMemberID="firstResponder"/> - </objects> - <point key="canvasLocation" x="292" y="-702"/> - </scene> <!--Tab Bar Controller--> <scene sceneID="TmM-gX-MFR"> <objects> @@ -417,13 +398,79 @@ </tabBar> <connections> <segue destination="0GJ-5e-Vr4" kind="relationship" relationship="viewControllers" id="nLJ-0v-l7T"/> - <segue destination="U8c-wO-OWj" kind="relationship" relationship="viewControllers" id="Tf1-0f-ulH"/> + <segue destination="H4q-bc-jfz" kind="relationship" relationship="viewControllers" id="9us-ML-Tfz"/> </connections> </tabBarController> <placeholder placeholderIdentifier="IBFirstResponder" id="PWN-St-ASU" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> <point key="canvasLocation" x="-520" y="-702"/> </scene> + <!--All Contacts--> + <scene sceneID="J4l-EM-mPs"> + <objects> + <tableViewController id="eq7-8Y-2gk" customClass="ContactsTableViewController" sceneMemberID="viewController"> + <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="cQe-3h-KwL"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <prototypes> + <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="contact_cell_two_name" id="tob-T5-7c2"> + <autoresizingMask key="autoresizingMask"/> + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tob-T5-7c2" id="EB4-t3-yo4"> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Zoe-VX-ha7"> + <rect key="frame" x="16" y="11" width="42" height="21"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" tag="2" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YPU-sZ-aBG"> + <rect key="frame" x="66" y="11" width="44" height="21"/> + <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <constraints> + <constraint firstAttribute="centerY" secondItem="Zoe-VX-ha7" secondAttribute="centerY" id="1f5-Qr-raP"/> + <constraint firstAttribute="centerY" secondItem="YPU-sZ-aBG" secondAttribute="centerY" id="96i-ka-jL9"/> + <constraint firstItem="Zoe-VX-ha7" firstAttribute="leading" secondItem="EB4-t3-yo4" secondAttribute="leadingMargin" constant="8" id="SJ7-N9-uE4"/> + <constraint firstItem="YPU-sZ-aBG" firstAttribute="leading" secondItem="Zoe-VX-ha7" secondAttribute="trailing" constant="8" id="nze-5F-xiv"/> + </constraints> + </tableViewCellContentView> + </tableViewCell> + <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="contact_cell_one_name" id="MmX-cP-MzC"> + <rect key="frame" x="0.0" y="0.0" width="600" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="MmX-cP-MzC" id="iHy-1R-Dp6"> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jWS-GM-KOz"> + <rect key="frame" x="16" y="11" width="44" height="21"/> + <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <constraints> + <constraint firstAttribute="centerY" secondItem="jWS-GM-KOz" secondAttribute="centerY" id="9Wg-kH-pQN"/> + <constraint firstItem="jWS-GM-KOz" firstAttribute="leading" secondItem="iHy-1R-Dp6" secondAttribute="leadingMargin" constant="8" id="ePe-7u-V2o"/> + </constraints> + </tableViewCellContentView> + </tableViewCell> + </prototypes> + <connections> + <outlet property="dataSource" destination="eq7-8Y-2gk" id="vru-iM-UFI"/> + <outlet property="delegate" destination="eq7-8Y-2gk" id="2sK-Wj-rpe"/> + </connections> + </tableView> + <navigationItem key="navigationItem" title="All Contacts" id="12T-BK-psp"/> + </tableViewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="1ye-ky-exR" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="1072" y="-702"/> + </scene> <!--Shared Lists--> <scene sceneID="vP4-SE-UGa"> <objects> @@ -477,7 +524,26 @@ </navigationController> <placeholder placeholderIdentifier="IBFirstResponder" id="AR0-99-D0J" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> - <point key="canvasLocation" x="1967" y="-722"/> + <point key="canvasLocation" x="2779" y="-722"/> + </scene> + <!--Navigation Controller--> + <scene sceneID="9uD-bo-9f6"> + <objects> + <navigationController automaticallyAdjustsScrollViewInsets="NO" id="H4q-bc-jfz" sceneMemberID="viewController"> + <tabBarItem key="tabBarItem" systemItem="contacts" id="LgJ-3E-asO"/> + <toolbarItems/> + <navigationBar key="navigationBar" contentMode="scaleToFill" id="wuQ-EG-WNy"> + <rect key="frame" x="0.0" y="0.0" width="320" height="44"/> + <autoresizingMask key="autoresizingMask"/> + </navigationBar> + <nil name="viewControllers"/> + <connections> + <segue destination="eq7-8Y-2gk" kind="relationship" relationship="rootViewController" id="D2Z-hc-bxH"/> + </connections> + </navigationController> + <placeholder placeholderIdentifier="IBFirstResponder" id="ioj-Fm-IP0" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="260" y="-702"/> </scene> </scenes> <inferredMetricsTieBreakers> diff --git a/ios-ng/shlist/ListDetailTableViewController.m b/ios-ng/shlist/ListDetailTableViewController.m @@ -96,7 +96,8 @@ return @""; } -- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +- (UITableViewCell *) tableView:(UITableView *)tableView + cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ListDetailPrototypeCell" forIndexPath:indexPath]; diff --git a/ios-ng/shlist/SharedList.h b/ios-ng/shlist/SharedList.h @@ -11,6 +11,9 @@ @property NSString *list_members; @property NSDate *list_date; +@property int items_ready; +@property int items_total; + @end -#endif +#endif +\ No newline at end of file diff --git a/ios-ng/shlist/SharedListsTableViewController.m b/ios-ng/shlist/SharedListsTableViewController.m @@ -61,7 +61,6 @@ self.indirect_lists = [[NSMutableArray alloc] init]; [self load_initial_data]; - } - (void) didReceiveMemoryWarning @@ -79,12 +78,10 @@ - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - if (section == 0) { + if (section == 0) return [self.shared_lists count]; - } - else if (section == 1) { + else if (section == 1) return [self.indirect_lists count]; - } return 0; } @@ -95,36 +92,42 @@ [tableView deselectRowAtIndexPath:indexPath animated:NO]; } -- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +- (UITableViewCell *) tableView:(UITableView *)tableView + cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell; - // NSLog(@"SharedListsTableViewController::cellForRowAtIndexPath()"); + int row = [indexPath row]; - NSInteger section_number = [indexPath section]; - if (section_number == 0) { + if ([indexPath section] == 0) { cell = [tableView dequeueReusableCellWithIdentifier:@"SharedListPrototypeCell" forIndexPath:indexPath]; - // UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SharedListPrototypeCell"]; - - if (cell == nil) { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"SharedListPrototypeCell"]; - cell.selectionStyle = UITableViewCellSelectionStyleNone; - } - SharedList *shared_list = [self.shared_lists objectAtIndex:indexPath.row]; + SharedList *shared_list = [self.shared_lists objectAtIndex:row]; cell.textLabel.text = shared_list.list_name; cell.detailTextLabel.text = shared_list.list_members; + + // fill in the completion fraction + UILabel *completion_fraction; + completion_fraction = (UILabel *)[cell viewWithTag:1]; + + // set color based on how complete the list is + float frac = (float) shared_list.items_ready / shared_list.items_total; + if (frac == 0.0f) + completion_fraction.textColor = [UIColor blackColor]; + else if (frac < 0.5f) + completion_fraction.textColor = [UIColor redColor]; + else if (frac < 0.75f) + completion_fraction.textColor = [UIColor orangeColor]; + else + completion_fraction.textColor = [UIColor greenColor]; + + completion_fraction.text = [self fraction:shared_list.items_ready + denominator:shared_list.items_total]; } - else if (section_number == 1) { + else if ([indexPath section] == 1) { cell = [tableView dequeueReusableCellWithIdentifier:@"IndirectListPrototypeCell" forIndexPath:indexPath]; - // UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SharedListPrototypeCell"]; - - if (cell == nil) { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"IndirectListPrototypeCell"]; - cell.selectionStyle = UITableViewCellSelectionStyleNone; - } - SharedList *shared_list = [self.indirect_lists objectAtIndex:indexPath.row]; + SharedList *shared_list = [self.indirect_lists objectAtIndex:row]; cell.textLabel.text = shared_list.list_name; cell.detailTextLabel.text = shared_list.list_members; } @@ -132,24 +135,51 @@ return cell; } + +// taken from http://stackoverflow.com/questions/30859359/display-fraction-number-in-uilabel +-(NSString *)fraction:(int)numerator denominator:(int)denominator { + + NSMutableString *result = [NSMutableString string]; + + NSString *one = [NSString stringWithFormat:@"%i", numerator]; + for (int i = 0; i < one.length; i++) { + [result appendString:[self superscript:[[one substringWithRange:NSMakeRange(i, 1)] intValue]]]; + } + [result appendString:@"/"]; + + NSString *two = [NSString stringWithFormat:@"%i", denominator]; + for (int i = 0; i < two.length; i++) { + [result appendString:[self subscript:[[two substringWithRange:NSMakeRange(i, 1)] intValue]]]; + } + return result; +} + +-(NSString *)superscript:(int)num +{ + NSDictionary *superscripts = @{@0: @"\u2070", @1: @"\u00B9", @2: @"\u00B2", @3: @"\u00B3", @4: @"\u2074", @5: @"\u2075", @6: @"\u2076", @7: @"\u2077", @8: @"\u2078", @9: @"\u2079"}; + return superscripts[@(num)]; +} + +-(NSString *)subscript:(int)num +{ + NSDictionary *subscripts = @{@0: @"\u2080", @1: @"\u2081", @2: @"\u2082", @3: @"\u2083", @4: @"\u2084", @5: @"\u2085", @6: @"\u2086", @7: @"\u2087", @8: @"\u2088", @9: @"\u2089"}; + return subscripts[@(num)]; +} + - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { if (section == 0) { - if ([self.shared_lists count] == 0) { + if ([self.shared_lists count] == 0) return @"you're not in any lists"; - } - else if ([self.shared_lists count] == 1) { + else if ([self.shared_lists count] == 1) return @"shared list"; - } return @"shared lists"; } else if (section == 1) { - if ([self.indirect_lists count] == 0) { + if ([self.indirect_lists count] == 0) return @"no other shared lists"; - } - else if ([self.indirect_lists count] == 1) { + else if ([self.indirect_lists count] == 1) return @"other shared list"; - } return @"other shared lists"; } return @""; @@ -158,24 +188,18 @@ - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { - if ([indexPath section] == 0) { + if ([indexPath section] == 0) return UITableViewCellEditingStyleDelete; - } + return UITableViewCellEditingStyleInsert; } -// Override to support conditional editing of the table view. - (BOOL) tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { - // if ([indexPath section] == 0) { - // editable - return YES; - // } - - // return NO; + // all lists are editable + return YES; } -// Override to support editing the table view. - (void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath @@ -184,6 +208,9 @@ // Delete the row from the data source // [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; + //NSIndexPath *new_index_path = [NSIndexPath indexPathForRow:0 inSection:1]; + //[tableView moveRowAtIndexPath:indexPath toIndexPath:new_index_path]; + NSIndexPath *path = [self.tableView indexPathForSelectedRow]; SharedList *selected_list = [self.shared_lists objectAtIndex:[path row]]; @@ -206,25 +233,11 @@ } } -/* -// Override to support rearranging the table view. -- (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { -} -*/ - -/* -// Override to support conditional rearranging of the table view. -- (BOOL) tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { - // Return NO if you do not want the item to be re-orderable. - return YES; -} -*/ - // In a storyboard-based application, you will often want to do a little preparation before navigation - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - // Get the new view controller using [segue destinationViewController]. - // Pass the selected object to the new view controller. + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. if ([[segue identifier] isEqualToString:@"show list segue"]) { @@ -240,8 +253,7 @@ // send update list items message [_server send_message:6 contents:list.list_id]; } - // DetailObject *detail = [self detailForIndexPath:path]; - + // DetailObject *detail = [self detailForIndexPath:path];ß // ListDetailTableViewController *list_detail_tvc = [segue destinationViewController]; // list_detail_tvc.navigationItem.title = @"Test Title"; diff --git a/ios-ng/shlist/ShlistServer.m b/ios-ng/shlist/ShlistServer.m @@ -6,6 +6,8 @@ @property (strong, retain) NSMutableData *data; @property (strong, retain) AddressBook *address_book; +@property NSMutableDictionary *phnum_to_name_map; + @property (strong, nonatomic) NSString *phone_number; @property (strong, nonatomic) NSData *device_id; @@ -37,7 +39,34 @@ [outputShlistStream open]; */ - _address_book = [[AddressBook alloc] init]; + // get instance and wait for privacy window to clear + _address_book = [AddressBook shared_address_book]; + [_address_book wait_for_ready]; + + // the capacity here assumes one phone number per person + _phnum_to_name_map = [NSMutableDictionary + dictionaryWithCapacity:_address_book.num_contacts]; + + for (Contact *contact in _address_book.contacts) { + NSString *disp_name; + // show first name and last initial if possible, otherwise + // just show the first name or the last name or the phone number + if (contact.first_name && contact.last_name) + disp_name = [NSString stringWithFormat:@"%@ %@", + contact.first_name, [contact.last_name substringToIndex:1]]; + else if (contact.first_name) + disp_name = contact.first_name; + else if (contact.last_name) + disp_name = contact.last_name; + else if ([contact.phone_numbers count]) + disp_name = [contact.phone_numbers objectAtIndex:0]; + else + disp_name = @"No Name"; + + // map the persons known phone number to their massaged name + for (NSString *phone_number in contact.phone_numbers) + [_phnum_to_name_map setObject:disp_name forKey:phone_number]; + } } return self; @@ -62,14 +91,14 @@ // message type 0 [msg appendBytes:"\x00\x00" length:2]; - // phone number length is 9 - uint16_t length_network = htons(9); + // phone number length is 10 + uint16_t length_network = htons(10); [msg appendBytes:&length_network length:2]; // actual phone number const char *phone_number = "4037082094"; _phone_number = @"4037082094"; - [msg appendBytes:phone_number length:9]; + [msg appendBytes:phone_number length:10]; [self writeToServer:msg]; NSLog(@"info: sent registration message"); @@ -309,8 +338,7 @@ NSLog(@"info: parse_list: '%@' has %i fields", [list_fields objectAtIndex:0], field_count); - - NSMutableArray *friends = [[NSMutableArray alloc] init]; + NSMutableArray *members = [[NSMutableArray alloc] init]; int others = 0; // anything past the second field are list members @@ -318,19 +346,20 @@ for (id phone_number in phone_numbers) { // try to find the list member in our address book - NSString *name = _address_book.name_map[phone_number]; + NSString *name = _phnum_to_name_map[phone_number]; + // NSLog(@"info: %@ -> %@", phone_number, name); if (name) - [friends addObject:name]; + [members addObject:name]; else if ([phone_number compare:_phone_number]) - [friends addObject:@"You"]; + [members addObject:@"You"]; else // didn't find it, you don't know this person others++; } NSMutableString *members_str = - [[friends componentsJoinedByString:@", "] mutableCopy]; + [[members componentsJoinedByString:@", "] mutableCopy]; if (others) { char *plural; @@ -344,13 +373,19 @@ [members_str appendString:buf]; } - /* we've got everything we need */ + // we've got everything we need SharedList *shared_list = [[SharedList alloc] init]; shared_list.list_name = [list_fields objectAtIndex:0]; shared_list.list_id = [[list_fields objectAtIndex:1] dataUsingEncoding:NSUTF8StringEncoding]; shared_list.list_members = members_str; + // we don't currently get this information back + // XXX: lists your not in will not return this information + sranddev(); + shared_list.items_ready = rand() % 7; + shared_list.items_total = 7; + [output addObject:shared_list]; }