shlist

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

commit a7a570d95d4f221e3927a8c9e9873714461df6f9
parent 6b27fe83e60bd460f6809aa927917a77d7d6fcae
Author: Kyle Milz <kyle@green.krwm.net>
Date:   Thu, 21 Jan 2016 22:20:08 -0700

ios: commit some work in progress stuff

- change message handling over to JSON
  - most of the way there, still some left to do
- send friend add/delete messages when contacts selected/deselected :)
- there isn't anything definitively done here, I just don't want to lose this
  progress

Diffstat:
Mios/ContactsTableViewController.m | 25+++++++++++++++++++++----
Mios/EditItemTableViewController.m | 2+-
Mios/shlist.xcodeproj/project.pbxproj | 8++++++++
Mios/shlist/Base.lproj/Main.storyboard | 54+++++++++++++++++++++++++++++++++++++++++++++---------
Mios/shlist/DataStructures.h | 7+++----
Mios/shlist/MainTableViewController.h | 4+---
Mios/shlist/MainTableViewController.m | 139+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Aios/shlist/MsgTypes.h | 33+++++++++++++++++++++++++++++++++
Mios/shlist/Network.h | 10++++++++--
Mios/shlist/Network.m | 477++++++++++++++++++++++++++++---------------------------------------------------
Mios/shlist/NewListTableViewController.m | 13++++++++++---
Aios/shlist/SettingsTableViewController.h | 7+++++++
Aios/shlist/SettingsTableViewController.m | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
13 files changed, 448 insertions(+), 386 deletions(-)

diff --git a/ios/ContactsTableViewController.m b/ios/ContactsTableViewController.m @@ -1,7 +1,10 @@ #import "ContactsTableViewController.h" #import "AddressBook.h" +#import "Network.h" -@interface ContactsTableViewController () +@interface ContactsTableViewController () { + Network *network_connection; +} @property (strong, retain) AddressBook *address_book; @property (strong, retain) NSMutableArray *cells; @@ -49,6 +52,8 @@ for (NSString *letter in _section_to_letter) [_cells addObject:[letter_to_contact_map objectForKey:letter]]; + + network_connection = [Network shared_network_connection]; } - (void)didReceiveMemoryWarning @@ -120,13 +125,25 @@ UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; Contact *contact = [[_cells objectAtIndex:section] objectAtIndex:row]; - if ([cell accessoryType] == UITableViewCellAccessoryNone) + NSMutableDictionary *request = [[NSMutableDictionary alloc] init]; + if ([cell accessoryType] == UITableViewCellAccessoryNone) { + // Toggling the contact on, add friend + + [request setObject:[contact.phone_numbers objectAtIndex:0] forKey:@"friend_phnum"]; + [network_connection send_message:friend_add contents:request]; + [cell setAccessoryType:UITableViewCellAccessoryCheckmark]; - else + } + else { + // Toggling contact off, delete friend + [request setObject:[contact.phone_numbers objectAtIndex:0] forKey:@"friend_phnum"]; + [network_connection send_message:friend_delete contents:request]; + [cell setAccessoryType:UITableViewCellAccessoryNone]; + } NSLog(@"info: selected %@ %@ who has %i phone numbers", - contact.first_name, contact.last_name, [contact.phone_numbers count]); + contact.first_name, contact.last_name, [contact.phone_numbers count]); } // programatically assign section headers, in this case they're letters diff --git a/ios/EditItemTableViewController.m b/ios/EditItemTableViewController.m @@ -119,7 +119,7 @@ [string_array addObject:[NSString stringWithFormat:@"%i", _item.completed]]; NSMutableData *buffer = [[NSMutableData alloc] init]; - [buffer appendData:_list.id]; + //[buffer appendData:_list.num]; [buffer appendData:[[string_array componentsJoinedByString:@":"] dataUsingEncoding:NSUTF8StringEncoding]]; // the list item that was just edited will be updated when a response comes diff --git a/ios/shlist.xcodeproj/project.pbxproj b/ios/shlist.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 273EC9C01BB25B6300CBFCDC /* SettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 273EC9BF1BB25B6300CBFCDC /* SettingsTableViewController.m */; }; 27AAC22C1B50ABAF00D99171 /* EditItemTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 27AAC22B1B50ABAF00D99171 /* EditItemTableViewController.m */; }; 27B03A021B43B8660054B6D2 /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27B03A001B43B8660054B6D2 /* AddressBook.framework */; }; 27C70F051B32AF8000DADEB3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C70F041B32AF8000DADEB3 /* main.m */; }; @@ -38,9 +39,12 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 273EC9BE1BB25B6300CBFCDC /* SettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTableViewController.h; sourceTree = "<group>"; }; + 273EC9BF1BB25B6300CBFCDC /* SettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTableViewController.m; sourceTree = "<group>"; }; 27AAC22A1B50ABAF00D99171 /* EditItemTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EditItemTableViewController.h; path = ../EditItemTableViewController.h; sourceTree = "<group>"; }; 27AAC22B1B50ABAF00D99171 /* EditItemTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EditItemTableViewController.m; path = ../EditItemTableViewController.m; sourceTree = "<group>"; }; 27B03A001B43B8660054B6D2 /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; + 27B195B81C45FEE200D7B2E9 /* MsgTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MsgTypes.h; path = shlist/MsgTypes.h; sourceTree = "<group>"; }; 27C70EFF1B32AF8000DADEB3 /* shlist.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = shlist.app; sourceTree = BUILT_PRODUCTS_DIR; }; 27C70F031B32AF8000DADEB3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 27C70F041B32AF8000DADEB3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; }; @@ -94,6 +98,7 @@ 27C70EF61B32AF7F00DADEB3 = { isa = PBXGroup; children = ( + 27B195B81C45FEE200D7B2E9 /* MsgTypes.h */, 27B03A001B43B8660054B6D2 /* AddressBook.framework */, 27C70F011B32AF8000DADEB3 /* shlist */, 27C70F1B1B32AF8000DADEB3 /* shlistTests */, @@ -138,6 +143,8 @@ 27C70F0A1B32AF8000DADEB3 /* Network.m */, 27C70F2B1B33F3C300DADEB3 /* NewListTableViewController.h */, 27C70F2C1B33F3C300DADEB3 /* NewListTableViewController.m */, + 273EC9BE1BB25B6300CBFCDC /* SettingsTableViewController.h */, + 273EC9BF1BB25B6300CBFCDC /* SettingsTableViewController.m */, 27C70F021B32AF8000DADEB3 /* Supporting Files */, ); path = shlist; @@ -272,6 +279,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 273EC9C01BB25B6300CBFCDC /* SettingsTableViewController.m in Sources */, BF7776B91B38928D00526CB0 /* ListTableViewController.m in Sources */, 27AAC22C1B50ABAF00D99171 /* EditItemTableViewController.m in Sources */, 27C70F0B1B32AF8000DADEB3 /* Network.m in Sources */, diff --git a/ios/shlist/Base.lproj/Main.storyboard b/ios/shlist/Base.lproj/Main.storyboard @@ -602,7 +602,7 @@ <!--Settings--> <scene sceneID="VVW-AV-daH"> <objects> - <tableViewController id="fV5-WH-d49" userLabel="Settings" sceneMemberID="viewController"> + <tableViewController id="fV5-WH-d49" userLabel="Settings" customClass="SettingsTableViewController" sceneMemberID="viewController"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="0rU-JR-ipU"> <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> @@ -617,14 +617,14 @@ <subviews> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Phone Number" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ZPp-x1-VLQ"> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <fontDescription key="fontDescription" type="system" pointSize="16"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> <nil key="highlightedColor"/> </label> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Detail" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8ae-6U-Vfz"> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <fontDescription key="fontDescription" type="system" pointSize="16"/> - <color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="calibratedRGB"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> <nil key="highlightedColor"/> </label> </subviews> @@ -633,21 +633,52 @@ <segue destination="eOn-mZ-1W0" kind="showDetail" id="NXM-5v-RjK"/> </connections> </tableViewCell> - <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="0kV-we-bvq" detailTextLabel="hcO-PG-uAA" style="IBUITableViewCellStyleValue1" id="pLe-rJ-ITY"> + </cells> + </tableViewSection> + <tableViewSection headerTitle="Diagnostics" id="hrL-3J-GqW"> + <cells> + <tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="RtJ-D1-bJk"> + <rect key="frame" x="0.0" y="0.0" width="320" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="RtJ-D1-bJk" id="NuS-la-rMS"> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Network" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Oz4-Px-uoa"> + <rect key="frame" x="16" y="11" width="65" height="21"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Good" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="15d-vN-62f"> + <rect key="frame" x="541" y="11" width="43" height="21"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <constraints> + <constraint firstAttribute="centerY" secondItem="15d-vN-62f" secondAttribute="centerY" id="30n-T2-CIn"/> + <constraint firstAttribute="centerY" secondItem="Oz4-Px-uoa" secondAttribute="centerY" id="AYc-kZ-b1z"/> + <constraint firstItem="15d-vN-62f" firstAttribute="trailing" secondItem="NuS-la-rMS" secondAttribute="trailingMargin" constant="-8" id="PZV-Nm-lOT"/> + <constraint firstItem="Oz4-Px-uoa" firstAttribute="leading" secondItem="NuS-la-rMS" secondAttribute="leadingMargin" constant="8" id="oIz-Vf-gq5"/> + </constraints> + </tableViewCellContentView> + </tableViewCell> + <tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" textLabel="0kV-we-bvq" detailTextLabel="hcO-PG-uAA" style="IBUITableViewCellStyleValue1" id="pLe-rJ-ITY"> <autoresizingMask key="autoresizingMask"/> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pLe-rJ-ITY" id="RsW-FA-jWb"> <autoresizingMask key="autoresizingMask"/> <subviews> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Device Id" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="0kV-we-bvq"> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <fontDescription key="fontDescription" type="system" pointSize="16"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> <nil key="highlightedColor"/> </label> - <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Detail" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hcO-PG-uAA"> + <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="0x0" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hcO-PG-uAA"> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <fontDescription key="fontDescription" type="system" pointSize="16"/> - <color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="calibratedRGB"/> + <fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="17"/> + <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> <nil key="highlightedColor"/> </label> </subviews> @@ -662,6 +693,11 @@ </connections> </tableView> <navigationItem key="navigationItem" title="Settings" id="zoA-Im-wFY"/> + <connections> + <outlet property="device_id_label" destination="hcO-PG-uAA" id="onj-im-8FH"/> + <outlet property="network_label" destination="15d-vN-62f" id="eVb-v4-Ade"/> + <outlet property="phone_number_label" destination="8ae-6U-Vfz" id="crf-Wn-WIN"/> + </connections> </tableViewController> <placeholder placeholderIdentifier="IBFirstResponder" id="BHt-9T-HOU" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> diff --git a/ios/shlist/DataStructures.h b/ios/shlist/DataStructures.h @@ -8,17 +8,16 @@ // UILabel *names; @property NSString *name; -@property NSData *id; +@property NSNumber *num; @property NSArray *members_phone_nums; @property bool deadline; @property NSDate *date; -@property int items_ready; -@property int items_total; +@property NSNumber *items_ready; +@property NSNumber *items_total; @property UITableViewCell *cell; @end - // This object is an individual item in a list @interface ListItem : NSObject diff --git a/ios/shlist/MainTableViewController.h b/ios/shlist/MainTableViewController.h @@ -4,11 +4,9 @@ @interface MainTableViewController : UITableViewController -@property NSMutableArray *shared_lists; -@property NSMutableArray *indirect_lists; - - (void) update_address_book; +- (void) lists_get_finished:(NSArray *)lists; - (void) finished_new_list_request:(SharedList *) shlist; - (void) finished_join_list_request:(SharedList *) shlist; - (void) finished_leave_list_request:(SharedList *) shlist; diff --git a/ios/shlist/MainTableViewController.m b/ios/shlist/MainTableViewController.m @@ -3,6 +3,7 @@ #import "NewListTableViewController.h" #import "Network.h" #import "ListTableViewController.h" +#import "MsgTypes.h" #import <AddressBook/AddressBook.h> #include "libkern/OSAtomic.h" @@ -13,6 +14,9 @@ NSString *phone_num_file; } +// main data structure, [0] holds lists you're in, [1] is other lists +@property NSMutableArray *lists; + @property NSMutableDictionary *phnum_to_name_map; @property (strong, retain) AddressBook *address_book; @@ -31,9 +35,9 @@ network_connection = [Network shared_network_connection]; network_connection->shlist_tvc = self; - // main lists - self.shared_lists = [[NSMutableArray alloc] init]; - self.indirect_lists = [[NSMutableArray alloc] init]; + _lists = [[NSMutableArray alloc] init]; + [_lists addObject:[[NSMutableArray alloc] init]]; + [_lists addObject:[[NSMutableArray alloc] init]]; // store the path to the phone number file NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); @@ -43,9 +47,10 @@ phone_number = nil; if ([self load_phone_number]) { // phone number loaded, try loading device id - if ([network_connection load_device_id:[phone_number dataUsingEncoding:NSASCIIStringEncoding]]) { + if ([network_connection load_device_id:phone_number]) { // bulk update, doesn't take a payload - [network_connection send_message:3 contents:nil]; + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + [network_connection send_message:lists_get contents:dict]; } // else, device id request sent } @@ -68,7 +73,7 @@ } UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Important" - message:@"In order for us to calculate your mutual contacts, your phone number is needed." + message:@"Your phone number is needed for us to calculate your mutual contacts. Severe amounts of functionality disabled." delegate:self cancelButtonTitle:@"Nope" otherButtonTitles:@"Ok", nil]; alert.alertViewStyle = UIAlertViewStylePlainTextInput; @@ -99,7 +104,7 @@ clickedButtonAtIndex:(NSInteger)buttonIndex phone_number = entered_phone_num; - if ([network_connection load_device_id:[phone_number dataUsingEncoding:NSASCIIStringEncoding]]) { + if ([network_connection load_device_id:phone_number]) { NSLog(@"info: network: connection ready"); // bulk update, doesn't take a payload [network_connection send_message:3 contents:nil]; @@ -148,11 +153,11 @@ clickedButtonAtIndex:(NSInteger)buttonIndex - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - if (section == 0) - return [self.shared_lists count]; - else if (section == 1) - return [self.indirect_lists count]; - return 0; + if (section > 1) + // should never happen + return 0; + + return [[_lists objectAtIndex:section] count]; } // new list dialogue has been saved @@ -160,12 +165,37 @@ clickedButtonAtIndex:(NSInteger)buttonIndex { } +- (void) lists_get_finished:(NSArray *)json_lists; +{ + NSMutableArray *lists = [_lists objectAtIndex:0]; + [lists removeAllObjects]; + + for (NSDictionary *list in json_lists) { + + SharedList *tmp = [[SharedList alloc] init]; + tmp.num = [list objectForKey:@"num"]; + tmp.name = [list objectForKey:@"name"]; + // tmp.date = [list objectForKey:@"date"]; + tmp.items_ready = [list objectForKey:@"items_complete"]; + tmp.items_total = [list objectForKey:@"items_total"]; + NSArray *members = [list objectForKey:@"members"]; + tmp.members_phone_nums = members; + [lists addObject:tmp]; + + NSLog(@"adding list '%@'", [list objectForKey:@"name"]); + } + + [self.tableView reloadData]; +} + - (void) finished_new_list_request:(SharedList *) shlist { - [self.shared_lists addObject:shlist]; + [[_lists objectAtIndex:0] addObject:shlist]; + // [self.shared_lists addObject:shlist]; // response looks good, insert the new list - NSIndexPath *index_path = [NSIndexPath indexPathForRow:[self.shared_lists count] - 1 inSection:0]; + int section_0_rows = [[_lists objectAtIndex:0] count]; + NSIndexPath *index_path = [NSIndexPath indexPathForRow:section_0_rows - 1 inSection:0]; [self.tableView insertRowsAtIndexPaths:@[index_path] withRowAnimation:UITableViewRowAnimationFade]; } @@ -180,18 +210,19 @@ clickedButtonAtIndex:(NSInteger)buttonIndex return; // we're in section 1 now, a tap down here means we're doing a join list request - SharedList *list = [self.indirect_lists objectAtIndex:[indexPath row]]; + SharedList *list = [[_lists objectAtIndex:1] objectAtIndex:[indexPath row]]; NSLog(@"info: joining list '%@'", list.name); // the response for this does all of the heavy row moving work - [network_connection send_message:4 contents:list.id]; + int num = list.num; + [network_connection send_message:list_join contents:[NSData dataWithBytes:&num length:sizeof(num)]]; } - (void) finished_join_list_request:(SharedList *) shlist { SharedList *needle = nil; - for (SharedList *temp in _indirect_lists) { - if ([temp.id isEqualToData:shlist.id]) { + for (SharedList *temp in [_lists objectAtIndex:1]) { + if (temp.num == shlist.num) { needle = temp; break; } @@ -202,15 +233,19 @@ clickedButtonAtIndex:(NSInteger)buttonIndex return; // this has to be done before row moving - [_shared_lists addObject:needle]; - [_indirect_lists removeObject:needle]; + [[_lists objectAtIndex:0] addObject:needle]; + [[_lists objectAtIndex:1] removeObject:needle]; + + // [_shared_lists addObject:needle]; + // [_indirect_lists removeObject:needle]; // get the original cells index path from the matched cell NSIndexPath *orig_index_path = [self.tableView indexPathForCell:needle.cell]; // 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]; + int section_0_rows = [[_lists objectAtIndex:0] count]; + NSIndexPath *new_index_path = [NSIndexPath indexPathForRow:section_0_rows - 1 inSection:0]; [self.tableView moveRowAtIndexPath:orig_index_path toIndexPath:new_index_path]; @@ -224,8 +259,8 @@ clickedButtonAtIndex:(NSInteger)buttonIndex - (void) finished_leave_list_request:(SharedList *) shlist { SharedList *list = nil; - for (SharedList *temp in _shared_lists) { - if ([temp.id isEqualToData:shlist.id]) { + for (SharedList *temp in [_lists objectAtIndex:0]) { + if (temp.num == shlist.num) { list = temp; break; } @@ -235,8 +270,8 @@ clickedButtonAtIndex:(NSInteger)buttonIndex return; // insert the new object at the beginning to match gui moving below - [_indirect_lists insertObject:list atIndex:0]; - [_shared_lists removeObject:list]; + [[_lists objectAtIndex:1] insertObject:list atIndex:0]; + [[_lists objectAtIndex:0] removeObject:list]; // perform row move, the destination is the top of "other lists" NSIndexPath *old_path = [self.tableView indexPathForCell:list.cell]; @@ -259,38 +294,33 @@ clickedButtonAtIndex:(NSInteger)buttonIndex UITableViewCell *cell; cell = [tableView dequeueReusableCellWithIdentifier:@"SharedListPrototypeCell" forIndexPath:indexPath]; + int section = [indexPath section]; int row = [indexPath row]; - SharedList *shared_list; + SharedList *shared_list = [[_lists objectAtIndex:section] objectAtIndex:row]; UILabel *deadline_label = (UILabel *)[cell viewWithTag:3]; UILabel *fraction_label = (UILabel *)[cell viewWithTag:4]; if ([indexPath section] == 0) { // "lists you're in" section - shared_list = [self.shared_lists objectAtIndex:row]; // XXX: needs to be stored on/sent from the server deadline_label.text = @"in 3 days"; - // set color based on how complete the list is - /* - float frac = (float) shared_list.items_ready / shared_list.items_total; - if (frac == 0.0f) - fraction_label.textColor = [UIColor blackColor]; - else if (frac < 0.5f) - fraction_label.textColor = [UIColor redColor]; - else if (frac < 0.75f) - fraction_label.textColor = [UIColor orangeColor]; - else + // float frac = shared_list.items_ready / shared_list.items_total; + float frac = 0.0f; + if (frac > 0.80f) fraction_label.textColor = [UIColor greenColor]; - */ + fraction_label.hidden = NO; fraction_label.text = [self fraction:shared_list.items_ready denominator:shared_list.items_total]; + + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + } else if ([indexPath section] == 1) { // "other lists" section - shared_list = [self.indirect_lists objectAtIndex:row]; // no deadline deadline_label.text = @""; @@ -368,10 +398,15 @@ clickedButtonAtIndex:(NSInteger)buttonIndex - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { + if (section > 1) + // should not happen + return @""; + + int total = [[_lists objectAtIndex:section] count]; if (section == 0) - return [NSString stringWithFormat:@"Lists you're in (%i)", [_shared_lists count]]; + return [NSString stringWithFormat:@"Lists you're in (%i)", total]; else if (section == 1) - return [NSString stringWithFormat:@"Other lists (%i)", [_indirect_lists count]]; + return [NSString stringWithFormat:@"Other lists (%i)", total]; return @""; } @@ -399,11 +434,13 @@ clickedButtonAtIndex:(NSInteger)buttonIndex forRowAtIndexPath:(NSIndexPath *)indexPath { // we don't need to check for !section 0 because of canEditRowAtIndexPath - SharedList *list = [self.shared_lists objectAtIndex:[indexPath row]]; - NSLog(@"info: leaving '%@' id '%@'", list.name, list.id); + SharedList *list = [[_lists objectAtIndex:0] objectAtIndex:[indexPath row]]; + NSLog(@"info: leaving '%@' list num '%@'", list.name, list.num); // send leave list message, response will do all heavy lifting - [network_connection send_message:5 contents:list.id]; + NSMutableDictionary *request = [[NSMutableDictionary alloc] init]; + [request setObject:list.num forKey:@"num"]; + [network_connection send_message:list_leave contents:request]; } // customize deletion label text @@ -420,14 +457,14 @@ clickedButtonAtIndex:(NSInteger)buttonIndex // a shared list was selected, transfer into detailed view NSIndexPath *path = [self.tableView indexPathForSelectedRow]; - SharedList *list = [self.shared_lists objectAtIndex:[path row]]; + SharedList *list = [[_lists objectAtIndex:0] objectAtIndex:[path row]]; // make sure incoming view controller knows about itself [segue.destinationViewController setMetadata:list]; // send update list items message network_connection->shlist_ldvc = segue.destinationViewController; - [network_connection send_message:6 contents:list.id]; + //[network_connection send_message:6 contents:list.id]; } // DetailObject *detail = [self detailForIndexPath:path]; @@ -445,21 +482,25 @@ clickedButtonAtIndex:(NSInteger)buttonIndex } // taken from http://stackoverflow.com/questions/30859359/display-fraction-number-in-uilabel --(NSString *)fraction:(int)numerator denominator:(int)denominator +-(NSString *)fraction:(NSNumber *)numerator denominator:(NSNumber *)denominator { NSMutableString *result = [NSMutableString string]; - NSString *one = [NSString stringWithFormat:@"%i", numerator]; + NSString *one = [numerator stringValue]; for (int i = 0; i < one.length; i++) { [result appendString:[self superscript:[[one substringWithRange:NSMakeRange(i, 1)] intValue]]]; } + [result appendString:@"/"]; + return result; + + NSString *two = [denominator stringValue]; - 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; } diff --git a/ios/shlist/MsgTypes.h b/ios/shlist/MsgTypes.h @@ -0,0 +1,33 @@ +/* generated Tue 12 Jan 2016 20:40:15 MST */ +#import "Network.h" + +/* +@interface MsgTypes : NSObject { + NSPointerArray *array; +} +*/ + +int protocol_version = 0; +enum msg_types { + device_add = 0, + friend_add = 1, + friend_delete = 2, + list_add = 3, + list_join = 4, + list_leave = 5, + lists_get = 6, + lists_get_other = 7, + list_items_get = 8, + list_item_add = 9, +}; + +/* +@end +@implementation MsgTypes ++ (void)initialize { + //array = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsOpaqueMemory]; +} +*/ + +//NSPointerArray *array = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsOpaqueMemory]; +//NSArray *msg_func = @[[NSValue valueWithPointer:handlerA]]; diff --git a/ios/shlist/Network.h b/ios/shlist/Network.h @@ -2,6 +2,8 @@ #import "MainTableViewController.h" #import "ListTableViewController.h" +#import "SettingsTableViewController.h" +#import "MsgTypes.h" @interface Network : NSObject <NSStreamDelegate> { NSInputStream *inputShlistStream; @@ -11,14 +13,18 @@ @public MainTableViewController *shlist_tvc; ListTableViewController *shlist_ldvc; + SettingsTableViewController *settings_tvc; } - (void) connect; - (void) disconnect; // only networking really cares about the device id -- (bool) load_device_id:(NSData*)phone_number; -- (bool) send_message:(uint16_t)msg_type contents:(NSData *)data; +- (bool) load_device_id:(NSString *)phone_number; +- (NSData *) get_device_id; +- (bool) send_message:(uint16_t)msg_type contents:(NSMutableDictionary *)data; + + // returns singleton instance + (id) shared_network_connection; diff --git a/ios/shlist/Network.m b/ios/shlist/Network.m @@ -1,23 +1,11 @@ #import "Network.h" #import "DataStructures.h" + // #import <NSAlert.h> @interface Network () { - NSData *msg_data; - NSString *msg_string; - uint8_t msg_buffer[1024]; - unsigned int msg_buf_position; - - uint8_t msg_total_bytes_tmp[2]; - unsigned short msg_total_bytes; - unsigned int msg_total_bytes_pos; - - uint8_t msg_type_tmp[2]; - unsigned short msg_type; - unsigned int msg_type_pos; - - NSData *device_id; + NSString *device_id; NSString *device_id_file; bool connected; } @@ -44,13 +32,6 @@ device_id_file = [documentsDirectory stringByAppendingPathComponent:@"shlist_key"]; device_id = nil; - msg_buf_position = 0; - - msg_total_bytes = 0; - msg_total_bytes_pos = 0; - - msg_type = 0; - msg_type_pos = 0; connected = 0; [self connect]; } @@ -58,6 +39,11 @@ return self; } +- (NSString *) get_device_id +{ + return device_id; +} + - (void) connect { [self info:@"network: connect()"]; @@ -68,7 +54,7 @@ CFStringRef host_name = CFSTR("absentmindedproductions.ca"); - CFStreamCreatePairWithSocketToHost(NULL, host_name, 5437, &readStream, &writeStream); + CFStreamCreatePairWithSocketToHost(NULL, host_name, 9999, &readStream, &writeStream); inputShlistStream = (__bridge NSInputStream *)readStream; outputShlistStream = (__bridge NSOutputStream *)writeStream; @@ -78,6 +64,10 @@ [inputShlistStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [outputShlistStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + // Enable SSL on both streams + [inputShlistStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey]; + [outputShlistStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey]; + [inputShlistStream open]; [outputShlistStream open]; } @@ -99,13 +89,17 @@ outputShlistStream = nil; // stream is ivar, so reinit it } -- (bool) load_device_id:(NSData *)phone_number; +- (bool) load_device_id:(NSString *)phone_number; { if ([[NSFileManager defaultManager] fileExistsAtPath:device_id_file]) { // TODO: also check the length of the file // read device id from filesystem into memory - device_id = [NSData dataWithContentsOfFile:device_id_file]; - [self debug:@"network: device id loaded"]; + NSError *error = nil; + device_id = [NSString stringWithContentsOfFile:device_id_file encoding:NSUTF8StringEncoding error:&error]; + if (error != nil) + NSLog(@"%@", [error userInfo]); + + NSLog(@"network: device id loaded"); return true; } @@ -113,16 +107,27 @@ // no device id file found, send a registration message NSMutableData *msg = [NSMutableData data]; - // message type 0 - uint16_t msg_type_network = htons(0); - [msg appendBytes:&msg_type_network length:2]; + NSDictionary *request = [NSDictionary dictionaryWithObjectsAndKeys: + phone_number, @"phone_number", + @"ios", @"os", + nil]; - // phone number length is 10 - uint16_t length_network = htons(10); - [msg appendBytes:&length_network length:2]; + NSError *error = nil; + NSData *json = [NSJSONSerialization dataWithJSONObject:request options:NSJSONWritingPrettyPrinted error:&error]; + if (error != nil) { + NSLog(@"%@", [error userInfo]); + return false; + } - // append phone number - [msg appendData:phone_number]; + uint16_t version = htons(0); + uint16_t msg_type = htons(device_add); + uint16_t length = htons([json length]); + [msg appendBytes:&version length:2]; + [msg appendBytes:&msg_type length:2]; + [msg appendBytes:&length length:2]; + + // Append JSON payload + [msg appendData:json]; [outputShlistStream write:[msg bytes] maxLength:[msg length]]; [self info:@"register: sent request"]; @@ -131,35 +136,30 @@ return false; } -- (bool) send_message:(uint16_t)send_msg_type contents:(NSData *)payload +- (bool) send_message:(uint16_t)send_msg_type contents:(NSMutableDictionary *)request { if (!connected) [self connect]; NSMutableData *msg = [NSMutableData data]; + [request setObject:device_id forKey:@"device_id"]; - uint16_t msg_type_network = htons(send_msg_type); - [msg appendBytes:&msg_type_network length:2]; - - int payload_length = 0; - if (payload) - // include null separator in this length - payload_length = [payload length] + 1; - - uint16_t msg_len_network = htons([device_id length] + payload_length); - [msg appendBytes:&msg_len_network length:2]; - - if (device_id == nil) { - [self warn:@"network: send_message: called before device_id was ready"]; + NSError *error = nil; + NSData *json = [NSJSONSerialization dataWithJSONObject:request options:NSJSONWritingPrettyPrinted error:&error]; + if (error != nil) { + NSLog(@"%@", [error userInfo]); return false; } - [msg appendData:device_id]; - if (payload) { - [msg appendBytes:"\0" length:1]; - [msg appendData:payload]; - } + uint16_t version = htons(0); + uint16_t msg_type_network = htons(send_msg_type); + uint16_t length = htons([json length]); + + [msg appendBytes:&version length:2]; + [msg appendBytes:&msg_type_network length:2]; + [msg appendBytes:&length length:2]; + [msg appendData:json]; [self info:@"network: send_message: type %i, %i bytes", send_msg_type, [msg length]]; @@ -202,12 +202,11 @@ if (stream == inputShlistStream) { if (![inputShlistStream hasBytesAvailable]) { - [self warn:@"network: input stream had no bytes available"]; + [self warn:@"read: input stream had no bytes available"]; break; } - // advance the message state machine by at least one byte - [self process_response_bytes]; + [self read_ready]; } break; } @@ -245,298 +244,154 @@ } } -- (void) process_response_bytes +- (void) read_ready { - uint8_t *buffer = malloc(1024); - while ([inputShlistStream hasBytesAvailable]) { - - unsigned int buffer_pos = 0; - NSInteger buffer_length; - - buffer_length = [inputShlistStream read:buffer maxLength:1024]; - if (buffer_length < 0) { - [self info:@"network: read returned < 0: %i", buffer_length]; - // XXX: should this be break instead? - continue; - } - - if (buffer_length == 0) { - [self info:@"network: buffer length was zero!"]; - // maybe break here instead? - continue; - } - [self debug:@"network: processing %i bytes", buffer_length]; - - // start receiving a new message - if (msg_type_pos == 0) { - msg_type_tmp[0] = buffer[buffer_pos]; - msg_type_pos = 1; - buffer_pos++; - - if (buffer_length == 1) - // we've exhausted the buffer - continue; - } - - // if we got here buffer_length > 1 - if (msg_type_pos == 1) { - msg_type_pos = 2; - msg_type_tmp[1] = buffer[buffer_pos]; - - // we read a single byte from the buffer - buffer_pos++; - - // both bytes are available for reading - msg_type = ntohs(*(uint16_t *)msg_type_tmp); - if (msg_type > 7) { - [self warn:@"network: out of range msg type %i", msg_type]; - - // bad message type, reset message buffer - msg_type_pos = 0; - msg_buf_position = 0; - msg_total_bytes_pos = 0; - continue; - } - [self debug:@"network: parsed message type %i", msg_type]; - - if (buffer_pos == buffer_length) - // we've run out of bytes to process - continue; - } - - // if we got here buffer_pos < buffer_length - if (msg_total_bytes_pos == 0) { - msg_total_bytes_pos = 1; - msg_total_bytes_tmp[0] = buffer[buffer_pos]; - buffer_pos++; - - if (buffer_pos == buffer_length) - // no more bytes to process - continue; - } - - if (msg_total_bytes_pos == 1) { - msg_total_bytes_pos = 2; - msg_total_bytes_tmp[1] = buffer[buffer_pos]; - buffer_pos++; - - msg_total_bytes = ntohs(*(uint16_t *)msg_total_bytes_tmp); - if (msg_total_bytes > 1024 || msg_total_bytes == 0) { - [self warn:@"network: out of range message length: 0 < %i < 1024", - msg_total_bytes]; - - // bad message type, reset message buffer - msg_type_pos = 0; - msg_buf_position = 0; - msg_total_bytes_pos = 0; - continue; - } - [self debug:@"network: message length is %i bytes", msg_total_bytes]; - - if (buffer_pos == buffer_length) - // no more bytes to process - continue; - } - - unsigned int remaining_bytes = buffer_length - buffer_pos; - - if (msg_buf_position + remaining_bytes >= msg_total_bytes) { - [self info:@"network: buffer length has enough space to read complete message"]; - - unsigned int bytes_for_complete_message = msg_total_bytes - msg_buf_position; - memcpy(msg_buffer + msg_buf_position, &buffer[buffer_pos], bytes_for_complete_message); - msg_buf_position += bytes_for_complete_message; - - msg_data = [[NSData alloc] initWithBytes:msg_buffer length:msg_total_bytes]; - msg_string = [[NSString alloc] initWithBytes:msg_buffer length:msg_total_bytes encoding:NSASCIIStringEncoding]; - - [self handle_complete_message]; - - // reset parsing fields, leave buffer position fields alone though - msg_buf_position = 0; - msg_type_pos = 0; - msg_total_bytes_pos = 0; - - // lop off anything else that's remaining in the read buffer - continue; - } + NSInteger buffer_len; + uint16_t header[3]; - // copy any remaining data into msg buffer - memcpy(msg_buffer + msg_buf_position, &buffer[buffer_pos], remaining_bytes); - msg_buf_position += remaining_bytes; + buffer_len = [inputShlistStream read:(uint8_t *)header maxLength:6]; + if (buffer_len != 6) { + [self error:@"read: didn't return 6 bytes"]; } - // free temporary buffer, not msg_buffer - free(buffer); -} - -- (void) handle_complete_message -{ - // assert msg_type_pos == 2 and msg_total_bytes_pos == 2 and msg_buf_position == msg_total_bytes - - if (msg_type == 0) { - // registration response message - if ([[NSFileManager defaultManager] fileExistsAtPath:device_id_file]) { - // it would be strange if we got back a registration - // message type when we already have a key file - [self error:@"network: register: not overwriting key file with '%@'", msg_string]; - return; - } + uint16_t version = ntohs(header[0]); + uint16_t msg_type = ntohs(header[1]); + uint16_t payload_size = ntohs(header[2]); - [self info:@"network: register: writing new key '%@' to disk", msg_string]; - [msg_data writeToFile:device_id_file atomically:YES]; - - // set this so we're ready to send other message types - device_id = msg_data; - - // do a bulk list update - [self send_message:3 contents:nil]; + if (version != 0) { + [self error:@"read: invalid version %i", version]; + } + if (msg_type > 10) { + [self error:@"read: invalid message type %i", msg_type]; + } + if (payload_size > 4095) { + [self error:@"read: %i bytes payload too large", payload_size]; + } + if (payload_size == 0) { + // Payload doesn't contain anything, that's ok + return; } - else if (msg_type == 1) { - NSArray *fields = [msg_string componentsSeparatedByString:@"\0"]; - if ([fields count] != 3) { - [self warn:@"network: new list response has invalid number of fields %i", - [fields count]]; - return; - } + const char *payload = malloc(payload_size); + buffer_len = [inputShlistStream read:(uint8_t *)payload maxLength:payload_size]; + if (buffer_len != payload_size) { + [self error:@"read: expected %i byte payload but got %i", payload_size, buffer_len]; + return; + } + [self info:@"read: payload is %i bytes", buffer_len]; - SharedList *shlist = [[SharedList alloc] init]; - shlist.id = [[fields objectAtIndex:0] dataUsingEncoding:NSUTF8StringEncoding]; - shlist.name = [fields objectAtIndex:1]; - shlist.members_phone_nums = [NSArray arrayWithObjects:[fields objectAtIndex:2], nil]; - shlist.items_ready = 0; - shlist.items_total = 0; + NSData *data = [NSData dataWithBytes:payload length:payload_size]; - if ([self check_tvc:shlist_tvc]) - [shlist_tvc finished_new_list_request:shlist]; + NSError *error = nil; + NSDictionary *response = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingAllowFragments error:&error]; + if (error) { + NSLog(@"%@", [error userInfo]); + }; - [self info:@"network: response for new list '%@' has %i fields", - shlist.name, [fields count]]; + NSString *status = [response objectForKey:@"status"]; + if (status == nil) { + NSLog(@"read: response did not contain 'status' key"); + return; + } + if ([status compare:@"err"] == 0) { + NSLog(@"read: response error, reason = '%@'", [response objectForKey:@"reason"]); + return; } - else if (msg_type == 3) { - [self handle_bulk_list_update:msg_string]; - - if ([self check_tvc:shlist_tvc]) - [shlist_tvc.tableView reloadData]; + if (msg_type == device_add) { + [self device_add:response]; + } else if (msg_type == list_add) { + [self list_add:response]; + } else if (msg_type == lists_get) { + [self lists_get:response]; + } else if (msg_type == list_join) { + [self list_join:response]; } - else if (msg_type == 4) { - SharedList *shlist = [[SharedList alloc] init]; - // XXX: sanitize msg_data, should be base64 and 43 bytes long - shlist.id = msg_data; + // free((void *)payload); +} - // XXX: these need to be sent from the server - shlist.items_ready = 0; - shlist.items_total = 99; - // shlist.list_name = <network>; - // shlist.members = <network>; +- (void) device_add:(NSDictionary *)response +{ + device_id = [response objectForKey:@"device_id"]; - if ([self check_tvc:shlist_tvc]) - [shlist_tvc finished_join_list_request:shlist]; - [self info:@"join list: response '%@' acknowledgedd", msg_string]; - } + [self info:@"device_add: writing new key '%@' to file", device_id]; + NSError *error = nil; + [device_id writeToFile:device_id_file atomically:YES encoding:NSUTF8StringEncoding error:&error]; - else if (msg_type == 5) { + if (error != nil) + NSLog(@"%@", [error userInfo]); +} - NSArray *fields = [msg_string componentsSeparatedByString:@"\0"]; - if ([fields count] != 2) { - [self warn:@"leave list: response had wrong number (%i) of fields", - [fields count]]; - return; - } +- (void) list_add:(NSDictionary *)response +{ + NSDictionary *list = [response objectForKey:@"list"]; - SharedList *shlist = [[SharedList alloc] init]; - shlist.id = [[fields objectAtIndex:0] dataUsingEncoding:NSUTF8StringEncoding]; + SharedList *shlist = [[SharedList alloc] init]; + shlist.num = [list objectForKey:@"num"]; + shlist.name = [list objectForKey:@"name"]; - // XXX: these need to be sent from the server - // shlist.list_name = <network>; - // shlist.members = <network>; + NSArray *members = [list objectForKey:@"members"]; + shlist.members_phone_nums = members; + shlist.items_ready = [list objectForKey:@"items_complete"]; + shlist.items_total = [list objectForKey:@"items_total"]; - if ([self check_tvc:shlist_tvc]) - [shlist_tvc finished_leave_list_request:shlist]; - [self info:@"leave list: response '%@' acknowledgedd", msg_string]; - } -} + if ([self check_tvc:shlist_tvc]) + [shlist_tvc finished_new_list_request:shlist]; -- (bool) check_tvc:(MainTableViewController *) tvc -{ - if (tvc) - return true; - [self warn:@"network: trying to update main_tvc before it's ready, ignoring!"]; - return false; + [self info:@"list_add: successfully added new list '%@'", shlist.name]; } -- (void) handle_bulk_list_update:(NSString *)raw_data +- (void) lists_get:(NSDictionary *)response { + NSArray *lists = [response objectForKey:@"lists"]; + NSLog(@"lists_get: got %i lists from server", [lists count]); + // Don't attempt to update a view controller that isn't there yet if (![self check_tvc:shlist_tvc]) return; - // split over double \0 - NSArray *list_types = [raw_data componentsSeparatedByString:@"\0\0"]; - if ([list_types count] != 2) { - [self warn:@"bulk list update: wrong number if \\0\\0 found: %i", - [list_types count]]; - return; - } - - NSString *my_lists = [list_types objectAtIndex:0]; - NSString *my_friends_lists = [list_types objectAtIndex:1]; - - [shlist_tvc.shared_lists removeAllObjects]; - [shlist_tvc.indirect_lists removeAllObjects]; - - if ([my_lists length] != 0) { - NSArray *my_lists_parsed = [self parse_lists:my_lists]; - [shlist_tvc.shared_lists addObjectsFromArray:my_lists_parsed]; - } - if ([my_friends_lists length] != 0) { - NSArray *indirect_lists = [self parse_lists:my_friends_lists]; - [shlist_tvc.indirect_lists addObjectsFromArray:indirect_lists]; - } - - [self info:@"bulk list update: %i/%i your lists/other lists", - [shlist_tvc.shared_lists count], [shlist_tvc.indirect_lists count]]; + if (shlist_tvc) + [shlist_tvc lists_get_finished:lists]; } -- (NSArray *) parse_lists:(NSString *)raw_lists +- (void) list_join:(NSDictionary *)response { - // each raw list is separated by a \0 - NSArray *lists = [raw_lists componentsSeparatedByString:@"\0"]; - NSMutableArray *output = [[NSMutableArray alloc] init]; - - for (id str in lists) { - NSArray *list_fields = [str componentsSeparatedByString:@":"]; - int field_count = [list_fields count]; - - if (field_count < 3) { - [self warn:@"parse list: less than 3 fields found: %i", field_count]; - - // can't do anything with this list - continue; - } - [self debug:@"parse_list: '%@' has %i fields", - [list_fields objectAtIndex:0], field_count]; - - // we've got everything we need - SharedList *shared_list = [[SharedList alloc] init]; + SharedList *shlist = [[SharedList alloc] init]; + shlist.num = [response objectForKey:@"num"]; + + // XXX: these need to be sent from the server + // shlist.items_ready = 0; + // shlist.items_total = 99; + // shlist.list_name = <network>; + // shlist.members = <network>; + + if ([self check_tvc:shlist_tvc]) + [shlist_tvc finished_join_list_request:shlist]; + [self info:@"list_join: joined list %i", shlist.num]; +} - shared_list.name = [list_fields objectAtIndex:0]; - shared_list.id = [[list_fields objectAtIndex:1] dataUsingEncoding:NSUTF8StringEncoding]; - shared_list.members_phone_nums = [list_fields subarrayWithRange:NSMakeRange(2, field_count - 2)]; +- (void) list_leave:(NSDictionary *)response +{ + SharedList *shlist = [[SharedList alloc] init]; + shlist.num = [response objectForKey:@"num"]; - // 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; + // XXX: these need to be sent from the server + // shlist.list_name = <network>; + // shlist.members = <network>; - [output addObject:shared_list]; - } + if ([self check_tvc:shlist_tvc]) + [shlist_tvc finished_leave_list_request:shlist]; + [self info:@"list_leave: left list", shlist.num]; +} - return output; +- (bool) check_tvc:(MainTableViewController *) tvc +{ + if (tvc) + return true; + [self warn:@"network: trying to update main_tvc before it's ready, ignoring!"]; + return false; } #define LOG_LEVEL_ERROR 0 diff --git a/ios/shlist/NewListTableViewController.m b/ios/shlist/NewListTableViewController.m @@ -78,10 +78,17 @@ shared_list.deadline = _deadline_switch.isOn; // _shared_list.filters = ??? - NSLog(@"debug: %@: saving", shared_list.name); + NSLog(@"new_list: sending list_add request..."); - NSData *payload = [shared_list.name dataUsingEncoding:NSUTF8StringEncoding]; - [network_connection send_message:1 contents:payload]; + NSMutableDictionary *list = [[NSMutableDictionary alloc] init]; + [list setObject:[NSNumber numberWithInt:0] forKey:@"num"]; + [list setObject:shared_list.name forKey:@"name"]; + [list setObject:[NSNumber numberWithInt:0] forKey:@"date"]; + + NSMutableDictionary *request = [[NSMutableDictionary alloc] init]; + [request setObject:list forKey:@"list"]; + + [network_connection send_message:list_add contents:request]; } @end \ No newline at end of file diff --git a/ios/shlist/SettingsTableViewController.h b/ios/shlist/SettingsTableViewController.h @@ -0,0 +1,7 @@ +#import <UIKit/UIKit.h> + +@interface SettingsTableViewController : UITableViewController + +- (void) finish_ok_request; + +@end diff --git a/ios/shlist/SettingsTableViewController.m b/ios/shlist/SettingsTableViewController.m @@ -0,0 +1,55 @@ +#import "SettingsTableViewController.h" + +#import "Network.h" + +@interface SettingsTableViewController () { + Network *netconn; +} + +@property (weak, nonatomic) IBOutlet UILabel *phone_number_label; +@property (weak, nonatomic) IBOutlet UILabel *device_id_label; +@property (weak, nonatomic) IBOutlet UILabel *network_label; + +@end + +@implementation SettingsTableViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + netconn = [Network shared_network_connection]; + NSString *device_id = [[NSString alloc] initWithData:[netconn get_device_id] encoding:NSASCIIStringEncoding]; + _device_id_label.text = [device_id substringToIndex:8]; +} + +- (void) viewWillAppear:(BOOL)animated +{ + // check every time this view is selected + _network_label.text = @"Checking..."; + netconn->settings_tvc = self; + [netconn send_message:8 contents:nil]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void) finish_ok_request +{ + _network_label.text = @"All good"; +} + +/* +#pragma mark - Navigation + +// 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. +} +*/ + +@end