commit 61ab8aa79b907d4b93c279c6cc6b7555c6dd5000
parent 1022463dc33325984e837b505a8f68b91a77cc6b
Author: Kyle Milz <kyle@Kyles-MacBook-Pro.local>
Date: Thu, 17 Sep 2015 20:27:59 -0600
ios: get animated row insert/deletes going
Diffstat:
5 files changed, 125 insertions(+), 119 deletions(-)
diff --git a/ios-ng/shlist.xcodeproj/project.pbxproj b/ios-ng/shlist.xcodeproj/project.pbxproj
@@ -21,8 +21,6 @@
27C70F2A1B33D1C900DADEB3 /* SharedList.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C70F291B33D1C900DADEB3 /* SharedList.m */; };
27C70F2D1B33F3C300DADEB3 /* NewListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C70F2C1B33F3C300DADEB3 /* NewListViewController.m */; };
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 */; };
@@ -67,9 +65,6 @@
27C70F2C1B33F3C300DADEB3 /* NewListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewListViewController.m; sourceTree = "<group>"; };
27C70F2E1B33F4FA00DADEB3 /* SharedListsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SharedListsTableViewController.h; sourceTree = "<group>"; };
27C70F2F1B33F4FA00DADEB3 /* SharedListsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SharedListsTableViewController.m; sourceTree = "<group>"; };
- 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>"; };
@@ -89,7 +84,6 @@
files = (
27B03A021B43B8660054B6D2 /* AddressBook.framework in Frameworks */,
27B03A031B43B8660054B6D2 /* AddressBookUI.framework in Frameworks */,
- 27C70F321B3650CB00DADEB3 /* libsqlite3.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -110,11 +104,8 @@
27AAC22B1B50ABAF00D99171 /* NewItemTableViewController.m */,
27B03A001B43B8660054B6D2 /* AddressBook.framework */,
27B03A011B43B8660054B6D2 /* AddressBookUI.framework */,
- 27C70F331B36513200DADEB3 /* DBManager.h */,
- 27C70F341B36513200DADEB3 /* DBManager.m */,
27C70F091B32AF8000DADEB3 /* ShlistServer.h */,
27C70F0A1B32AF8000DADEB3 /* ShlistServer.m */,
- 27C70F311B3650CB00DADEB3 /* libsqlite3.dylib */,
27C70F011B32AF8000DADEB3 /* shlist */,
27C70F1B1B32AF8000DADEB3 /* shlistTests */,
27C70F001B32AF8000DADEB3 /* Products */,
@@ -291,7 +282,6 @@
buildActionMask = 2147483647;
files = (
BF7776B91B38928D00526CB0 /* ListDetailTableViewController.m in Sources */,
- 27C70F351B36513200DADEB3 /* DBManager.m in Sources */,
27AAC22C1B50ABAF00D99171 /* NewItemTableViewController.m in Sources */,
BF7776BC1B38D0DB00526CB0 /* ListItem.m in Sources */,
27C70F0B1B32AF8000DADEB3 /* ShlistServer.m in Sources */,
diff --git a/ios-ng/shlist/AddressBook.m b/ios-ng/shlist/AddressBook.m
@@ -92,31 +92,29 @@
- (void)listPeopleInAddressBook:(ABAddressBookRef)addressBook
{
NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
- NSInteger numberOfPeople = [allPeople count];
- for (NSInteger i = 0; i < numberOfPeople; i++) {
+ NSCharacterSet *want =[[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
+
+ for (NSInteger i = 0; i < [allPeople count]; i++) {
ABRecordRef person = (__bridge ABRecordRef)allPeople[i];
Contact *contact = [[Contact alloc] init];
- // don't enforce these existing on purpose
+ // don't enforce these existing
contact.first_name = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
contact.last_name = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
+ contact.phone_numbers = [[NSMutableArray alloc] init];
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex numberOfPhoneNumbers = ABMultiValueGetCount(phoneNumbers);
- contact.phone_numbers = [[NSMutableArray alloc] init];
for (CFIndex i = 0; i < numberOfPhoneNumbers; i++) {
- NSString *phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phoneNumbers, i));
+ NSString *pn = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phoneNumbers, i));
- if (phoneNumber == nil)
+ if (pn == nil)
continue;
- phoneNumber = [phoneNumber stringByReplacingOccurrencesOfString:@" " withString:@""];
- phoneNumber = [phoneNumber stringByReplacingOccurrencesOfString:@"(" withString:@""];
- phoneNumber = [phoneNumber stringByReplacingOccurrencesOfString:@")" withString:@""];
- phoneNumber = [phoneNumber stringByReplacingOccurrencesOfString:@"-" withString:@""];
+ NSString *cleaned = [[pn componentsSeparatedByCharactersInSet: want] componentsJoinedByString:@""];
- [contact.phone_numbers addObject:phoneNumber];
+ [contact.phone_numbers addObject:cleaned];
}
CFRelease(phoneNumbers);
diff --git a/ios-ng/shlist/Base.lproj/Main.storyboard b/ios-ng/shlist/Base.lproj/Main.storyboard
@@ -283,26 +283,6 @@
<segue destination="pMK-tA-j4s" kind="show" identifier="show list segue" id="ORk-KR-Twe"/>
</connections>
</tableViewCell>
- <tableViewCell contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="IndirectListPrototypeCell" textLabel="WuW-Sd-sxB" detailTextLabel="rf3-DG-Fgi" style="IBUITableViewCellStyleSubtitle" id="kbj-EX-eeF">
- <autoresizingMask key="autoresizingMask"/>
- <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="kbj-EX-eeF" id="fgg-hw-Da6">
- <autoresizingMask key="autoresizingMask"/>
- <subviews>
- <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="WuW-Sd-sxB">
- <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="rf3-DG-Fgi">
- <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>
- </subviews>
- </tableViewCellContentView>
- </tableViewCell>
</prototypes>
<sections/>
<connections>
diff --git a/ios-ng/shlist/SharedListsTableViewController.m b/ios-ng/shlist/SharedListsTableViewController.m
@@ -14,19 +14,6 @@
@implementation SharedListsTableViewController
-- (void) load_initial_data
-{
- // create one and only server instance, this gets passed around
- _server = [[ShlistServer alloc] init];
- _server->shlist_tvc = self;
-
- if ([_server prepare]) {
- NSLog(@"info: server connection prepared");
- // bulk update, doesn't take a payload
- [_server send_message:3 contents:nil];
- }
-}
-
- (IBAction) unwindToList:(UIStoryboardSegue *)segue
{
NewListViewController *source = [segue sourceViewController];
@@ -50,17 +37,21 @@
{
[super viewDidLoad];
- // Uncomment the following line to preserve selection between
- // presentations.
- // self.clearsSelectionOnViewWillAppear = NO;
-
// display an Edit button in the navigation bar for this view controller
self.navigationItem.leftBarButtonItem = self.editButtonItem;
self.shared_lists = [[NSMutableArray alloc] init];
self.indirect_lists = [[NSMutableArray alloc] init];
- [self load_initial_data];
+ // create one and only server instance, this gets passed around
+ _server = [[ShlistServer alloc] init];
+ _server->shlist_tvc = self;
+
+ if ([_server prepare]) {
+ NSLog(@"info: server connection prepared");
+ // bulk update, doesn't take a payload
+ [_server send_message:3 contents:nil];
+ }
}
- (void) didReceiveMemoryWarning
@@ -73,6 +64,7 @@
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
+ // "lists you're in" and "other lists"
return 2;
}
@@ -82,26 +74,55 @@
return [self.shared_lists count];
else if (section == 1)
return [self.indirect_lists count];
-
return 0;
}
-- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
+// major thing here is join list requests
+- (void)tableView:(UITableView *)tableView
+ didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
- NSLog(@"did cell selection");
- [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ [tableView deselectRowAtIndexPath:indexPath animated:YES];
+
+ // section 0 is going to segue to the list items screen
+ if ([indexPath section] == 0)
+ return;
+
+ // we're in section 1 now, a tap down here means we're doing a join list request
+ NSIndexPath *path = [self.tableView indexPathForSelectedRow];
+ SharedList *list = [self.indirect_lists objectAtIndex:[path row]];
+ NSLog(@"info: joining '%@'", list.list_name);
+
+ // this has to be done before row moving
+ [_shared_lists addObject:list];
+ [_indirect_lists removeObject:list];
+
+ UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+
+ // compute new position and start moving row as soon as possible
+ // XXX: sorting
+ NSIndexPath *new_index_path = [NSIndexPath indexPathForRow:[_shared_lists count] - 1 inSection:0];
+ [tableView moveRowAtIndexPath:indexPath toIndexPath:new_index_path];
+
+ // add > accessory indicator
+ cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
+ UILabel *fraction = (UILabel *)[cell viewWithTag:1];
+ fraction.hidden = NO;
+ fraction.text = [self fraction:list.items_ready denominator:list.items_total];
+
+ // send this last because when the response comes in the list should be in
+ // it's expected place
+ [_server send_message:4 contents:list.list_id];
}
- (UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
+ cell = [tableView dequeueReusableCellWithIdentifier:@"SharedListPrototypeCell" forIndexPath:indexPath];
int row = [indexPath row];
if ([indexPath section] == 0) {
- cell = [tableView dequeueReusableCellWithIdentifier:@"SharedListPrototypeCell" forIndexPath:indexPath];
-
SharedList *shared_list = [self.shared_lists objectAtIndex:row];
cell.textLabel.text = shared_list.list_name;
cell.detailTextLabel.text = shared_list.list_members;
@@ -111,6 +132,7 @@
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];
@@ -120,16 +142,25 @@
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 ([indexPath section] == 1) {
- cell = [tableView dequeueReusableCellWithIdentifier:@"IndirectListPrototypeCell" forIndexPath:indexPath];
-
SharedList *shared_list = [self.indirect_lists objectAtIndex:row];
cell.textLabel.text = shared_list.list_name;
cell.detailTextLabel.text = shared_list.list_members;
+
+ // Modify the look of the off the shelf cell
+ // Note, a separate prototype cell isn't used here because we
+ // can potentially swap cells a large number of times, and moving
+ // is more efficient than recreating.
+
+ // remove the > accessory and the completion fraction
+ cell.accessoryType = UITableViewCellAccessoryNone;
+ UILabel *fraction = (UILabel *)[cell viewWithTag:1];
+ fraction.hidden = YES;
}
return cell;
@@ -137,7 +168,8 @@
// taken from http://stackoverflow.com/questions/30859359/display-fraction-number-in-uilabel
--(NSString *)fraction:(int)numerator denominator:(int)denominator {
+-(NSString *)fraction:(int)numerator denominator:(int)denominator
+{
NSMutableString *result = [NSMutableString string];
@@ -168,69 +200,64 @@
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
- if (section == 0) {
- if ([self.shared_lists count] == 0)
- return @"you're not in any lists";
- else if ([self.shared_lists count] == 1)
- return @"shared list";
- return @"shared lists";
- }
- else if (section == 1) {
- if ([self.indirect_lists count] == 0)
- return @"no other shared lists";
- else if ([self.indirect_lists count] == 1)
- return @"other shared list";
- return @"other shared lists";
- }
+ if (section == 0)
+ return @"Lists you're in";
+ else if (section == 1)
+ return @"Other lists";
return @"";
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
- if ([indexPath section] == 0)
- return UITableViewCellEditingStyleDelete;
-
- return UITableViewCellEditingStyleInsert;
+ // don't have to check the section here because canEditRowAtIndexPath
+ // already said the section can't be edited
+ return UITableViewCellEditingStyleDelete;
}
- (BOOL) tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
- // all lists are editable
- return YES;
+ if ([indexPath section] == 0)
+ return YES;
+ return NO;
+}
+
+- (NSString *)tableView:(UITableView *)tableView
+ titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ return @"Leave";
}
+// this functions called when delete has been prompted and ok'd
- (void) tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
- if (editingStyle == UITableViewCellEditingStyleDelete) {
- // 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]];
+ // remove the row from the "lists you're in" section and put it in the
+ // "other lists" section
+ NSIndexPath *path = [self.tableView indexPathForSelectedRow];
+ SharedList *list = [self.shared_lists objectAtIndex:[path row]];
+ NSLog(@"info: leaving '%@'", list.list_name);
- NSLog(@"info: leaving list '%@'", selected_list.list_name);
+ [self.indirect_lists addObject:list];
+ [self.shared_lists removeObject:list];
- // send leave list message
- [_server send_message:5 contents:selected_list.list_id];
+ UITableViewCell *new_cell = [tableView cellForRowAtIndexPath:indexPath];
- // [self.shared_lists removeObjectAtIndex:[indexPath row]];
- } else if (editingStyle == UITableViewCellEditingStyleInsert) {
- // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
+ // perform row move, the destination is the top of "other lists"
+ 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.indirect_lists objectAtIndex:[path row]];
+ // remove > accessory and hide the completion fraction
+ new_cell.accessoryType = UITableViewCellAccessoryNone;
+ UILabel *fraction = (UILabel *)[new_cell viewWithTag:1];
+ fraction.hidden = YES;
- NSLog(@"info: joining list '%@'", selected_list.list_name);
+ // reset editing state back to the default
+ [tableView setEditing:FALSE animated:TRUE];
- // send join list message
- [_server send_message:4 contents:selected_list.list_id];
- }
+ // send leave list message
+ [_server send_message:5 contents:list.list_id];
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
@@ -242,6 +269,7 @@
if ([[segue identifier] isEqualToString:@"show list segue"]) {
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
+
SharedList *list = [self.shared_lists objectAtIndex:[path row]];
// only list detail table view controller has this method
@@ -261,4 +289,15 @@
NSLog(@"preparing for segue");
}
+// prevent segues from occurring when non member lists are selected
+// this isn't needed if we use 2 different prototype cells
+- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
+{
+ NSIndexPath *path = [self.tableView indexPathForSelectedRow];
+
+ if ([path section] == 0)
+ return YES;
+ return NO;
+}
+
@end
diff --git a/ios-ng/shlist/ShlistServer.m b/ios-ng/shlist/ShlistServer.m
@@ -236,19 +236,18 @@
if (msg_type == 4) {
NSLog(@"info: got response from join list request, '%@'", output);
- for (SharedList *list in shlist_tvc.indirect_lists) {
- if (list.list_name == output) {
- [shlist_tvc.shared_lists addObject:list];
- [shlist_tvc.indirect_lists removeObject:list];
- break;
- }
- }
- [shlist_tvc.tableView reloadData];
+
+ // update the already existing row entry with fresh info
+ // [shlist_tvc.tableView reloadRowsAtIndexPaths: withRowAnimation:];
+
}
if (msg_type == 5) {
- NSLog(@"info: got response from leave list request");
+ NSLog(@"info: leave list response '%@'", output);
+
+ // [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
+ /*
for (SharedList *list in shlist_tvc.shared_lists) {
if (list.list_name == output) {
[shlist_tvc.indirect_lists addObject:list];
@@ -258,6 +257,7 @@
}
}
[shlist_tvc.tableView reloadData];
+ */
}
}
break;
@@ -348,7 +348,6 @@
// try to find the list member in our address book
NSString *name = _phnum_to_name_map[phone_number];
- // NSLog(@"info: %@ -> %@", phone_number, name);
if (name)
[members addObject:name];