diff --git a/Classes/Tabs/01_Groups/GroupsView.m b/Classes/Tabs/01_Groups/GroupsView.m index 20ba9a5..4b97539 100755 --- a/Classes/Tabs/01_Groups/GroupsView.m +++ b/Classes/Tabs/01_Groups/GroupsView.m @@ -18,6 +18,7 @@ #import "GroupsView.h" #import "ChatView.h" +#import "DatabaseAvailability.h" //------------------------------------------------------------------------------------------------------------------------------------------------- @interface GroupsView() @@ -65,6 +66,7 @@ - (void)viewDidAppear:(BOOL)animated //--------------------------------------------------------------------------------------------------------------------------------------------- if ([PFUser currentUser] != nil) { + [[NSNotificationCenter defaultCenter] postNotificationName:PFUSER_READY object:nil]; [self loadGroups]; } else LoginUser(self); diff --git a/Classes/Tabs/02_Messages/MessagesView.m b/Classes/Tabs/02_Messages/MessagesView.m index 8f6d343..3c6fa94 100755 --- a/Classes/Tabs/02_Messages/MessagesView.m +++ b/Classes/Tabs/02_Messages/MessagesView.m @@ -24,6 +24,7 @@ #import "AddressBookView.h" #import "FacebookFriendsView.h" #import "NavigationController.h" +#import "DatabaseAvailability.h" //------------------------------------------------------------------------------------------------------------------------------------------------- @interface MessagesView() @@ -86,6 +87,7 @@ - (void)viewDidAppear:(BOOL)animated //--------------------------------------------------------------------------------------------------------------------------------------------- if ([PFUser currentUser] != nil) { + [[NSNotificationCenter defaultCenter] postNotificationName:PFUSER_READY object:nil]; [self loadMessages]; } else LoginUser(self); diff --git a/Classes/Tabs/03_Profile/ProfileView.m b/Classes/Tabs/03_Profile/ProfileView.m index e05ebbc..ce7dda0 100755 --- a/Classes/Tabs/03_Profile/ProfileView.m +++ b/Classes/Tabs/03_Profile/ProfileView.m @@ -20,17 +20,31 @@ #import "utilities.h" #import "ProfileView.h" - +#import "DatabaseAvailability.h" //------------------------------------------------------------------------------------------------------------------------------------------------- -@interface ProfileView() +@interface ProfileView() @property (strong, nonatomic) IBOutlet UIView *viewHeader; @property (strong, nonatomic) IBOutlet PFImageView *imageUser; @property (strong, nonatomic) IBOutlet UITableViewCell *cellName; + +@property (strong, nonatomic) IBOutlet UITableViewCell *cellSex; +@property (strong, nonatomic) IBOutlet UITableViewCell *cellDate; +@property (strong, nonatomic) IBOutlet UITableViewCell *cellInterest; +@property (strong, nonatomic) IBOutlet UITableViewCell *cellSelfDescription; + +@property (strong, nonatomic) NSArray *sexArray; + + @property (strong, nonatomic) IBOutlet UITableViewCell *cellButton; @property (strong, nonatomic) IBOutlet UITextField *fieldName; +@property (strong, nonatomic) IBOutlet UITextField *fieldSex; +@property (strong, nonatomic) IBOutlet UITextField *fieldInterest; +@property (strong, nonatomic) IBOutlet UITextField *fieldSelfDescription; +@property (strong, nonatomic) IBOutlet UITextField *fieldDate; + @end //------------------------------------------------------------------------------------------------------------------------------------------------- @@ -38,8 +52,9 @@ @interface ProfileView() @implementation ProfileView @synthesize viewHeader, imageUser; -@synthesize cellName, cellButton; -@synthesize fieldName; +@synthesize cellName, cellButton, cellSex, cellDate, cellInterest, cellSelfDescription; +@synthesize fieldName, fieldDate, fieldInterest, fieldSelfDescription, fieldSex; + //------------------------------------------------------------------------------------------------------------------------------------------------- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil @@ -70,6 +85,21 @@ - (void)viewDidLoad //--------------------------------------------------------------------------------------------------------------------------------------------- imageUser.layer.cornerRadius = imageUser.frame.size.width / 2; imageUser.layer.masksToBounds = YES; + + //setup sex picker + UIPickerView *sexPicker = [[UIPickerView alloc] init]; + //[sexPicker numberOfRowsInComponent:1]; + [sexPicker setDataSource:self]; + [sexPicker setDelegate:self]; + sexPicker.showsSelectionIndicator = YES; + [fieldSex setInputView:sexPicker]; + self.sexArray = [[NSArray alloc] initWithObjects:@"Male",@"Female",@"Unknown",nil]; + + //setup date picker + UIDatePicker *datePicker = [[UIDatePicker alloc] init]; + datePicker.datePickerMode = UIDatePickerModeDate; + [datePicker addTarget:self action:@selector(updateDateField:) forControlEvents:UIControlEventValueChanged]; + [fieldDate setInputView:datePicker]; } //------------------------------------------------------------------------------------------------------------------------------------------------- @@ -80,6 +110,7 @@ - (void)viewDidAppear:(BOOL)animated //--------------------------------------------------------------------------------------------------------------------------------------------- if ([PFUser currentUser] != nil) { + [[NSNotificationCenter defaultCenter] postNotificationName:PFUSER_READY object:nil]; [self loadUser]; } else LoginUser(self); @@ -92,6 +123,41 @@ - (void)dismissKeyboard [self.view endEditing:YES]; } +#pragma mark - Picker view +-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component +{ + return 3; +} + +-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView +{ + return 1; +} + +-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component +{ + return [self.sexArray objectAtIndex:row]; +} + +-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component +{ + NSLog(@"Selected Row %ld", (long)row); + switch (row) { + case 0: + self.fieldSex.text = @"Male"; + break; + case 1: + self.fieldSex.text = @"Female"; + break; + case 2: + self.fieldSex.text = @"Unknown"; + break; + + default: + break; + } +} + #pragma mark - Backend actions //------------------------------------------------------------------------------------------------------------------------------------------------- @@ -104,30 +170,45 @@ - (void)loadUser [imageUser loadInBackground]; fieldName.text = user[PF_USER_FULLNAME]; -} + fieldSex.text = user[PF_USER_SEX]; + fieldDate.text = user[PF_USER_BIRTHDAY]; + fieldInterest.text = user[PF_USER_INTEREST]; + fieldSelfDescription.text = user[PF_USER_SELF_DESCRIPTION]; + } //------------------------------------------------------------------------------------------------------------------------------------------------- - (void)saveUser //------------------------------------------------------------------------------------------------------------------------------------------------- { NSString *fullname = fieldName.text; + NSString *sex = fieldSex.text; + NSString *interest = fieldInterest.text; + NSString *selfDescription = fieldSelfDescription.text; + NSString *birthday = fieldDate.text; if ([fullname length] != 0) { PFUser *user = [PFUser currentUser]; user[PF_USER_FULLNAME] = fullname; user[PF_USER_FULLNAME_LOWER] = [fullname lowercaseString]; + user[PF_USER_SEX] = sex; + user[PF_USER_INTEREST] = interest; + user[PF_USER_SELF_DESCRIPTION] = selfDescription; + user[PF_USER_BIRTHDAY] = birthday; [user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) { if (error == nil) { [ProgressHUD showSuccess:@"Saved."]; + [[NSNotificationCenter defaultCenter] postNotificationName:PFUSER_READY object:nil]; } else [ProgressHUD showError:@"Network error."]; + }]; } else [ProgressHUD showError:@"Name field must be set."]; } + #pragma mark - User actions //------------------------------------------------------------------------------------------------------------------------------------------------- @@ -159,6 +240,8 @@ - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger ParsePushUserResign(); PostNotification(NOTIFICATION_USER_LOGGED_OUT); [self actionCleanup]; + [[NSNotificationCenter defaultCenter] postNotificationName:PFUSER_LOGOUT object:nil]; + [self dismissViewControllerAnimated:YES completion:nil]; LoginUser(self); } } @@ -178,6 +261,14 @@ - (IBAction)actionSave:(id)sender [self saveUser]; } + +-(void)updateDateField:(id)sender +{ + UIDatePicker *picker = (UIDatePicker *)self.fieldDate.inputView; + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.dateFormat = @"dd-MMM-yyyy"; + self.fieldDate.text = [NSString stringWithFormat:@"%@",[dateFormatter stringFromDate:picker.date]]; +} #pragma mark - UIImagePickerControllerDelegate //------------------------------------------------------------------------------------------------------------------------------------------------- @@ -220,7 +311,7 @@ - (void)imagePickerController:(UIImagePickerController *)picker didFinishPicking - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView //------------------------------------------------------------------------------------------------------------------------------------------------- { - return 2; + return 6; } //------------------------------------------------------------------------------------------------------------------------------------------------- @@ -235,8 +326,38 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N //------------------------------------------------------------------------------------------------------------------------------------------------- { if (indexPath.section == 0) return cellName; - if (indexPath.section == 1) return cellButton; + if (indexPath.section == 1) return cellSex; + if (indexPath.section == 2) return cellDate; + if (indexPath.section == 3) return cellInterest; + if (indexPath.section == 4) return cellSelfDescription; + if (indexPath.section == 5) return cellButton; return nil; } +-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section +{ + NSString *sectionName; + switch (section) { + case 0: + sectionName = NSLocalizedString(@"Name", @"user Name"); + break; + case 1: + sectionName = NSLocalizedString(@"Sex", @"sex"); + break; + case 2: + sectionName = NSLocalizedString(@"Birthday", @"birthday"); + break; + case 3: + sectionName = NSLocalizedString(@"Interest", @"interest"); + break; + case 4: + sectionName = NSLocalizedString(@"Self Description", @"selfDescription"); + break; + default: + sectionName = @""; + break; + } + return sectionName; +} + @end diff --git a/Classes/Tabs/03_Profile/ProfileView.xib b/Classes/Tabs/03_Profile/ProfileView.xib index d01027d..fc0df1b 100755 --- a/Classes/Tabs/03_Profile/ProfileView.xib +++ b/Classes/Tabs/03_Profile/ProfileView.xib @@ -9,8 +9,16 @@ + + + + + + + + @@ -101,6 +109,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/Tabs/BTLEPeripheralViewController.h b/Classes/Tabs/BTLEPeripheralViewController.h deleted file mode 100755 index 694681e..0000000 --- a/Classes/Tabs/BTLEPeripheralViewController.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - - File: LEPeripheralViewController.h - - Abstract: Interface to allow the user to enter data that will be - transferred to a version of the app in Central Mode, when it is brought - close enough. - - Version: 1.0 - - Disclaimer: IMPORTANT: This Apple software is supplied to you by - Apple Inc. ("Apple") in consideration of your agreement to the - following terms, and your use, installation, modification or - redistribution of this Apple software constitutes acceptance of these - terms. If you do not agree with these terms, please do not use, - install, modify or redistribute this Apple software. - - In consideration of your agreement to abide by the following terms, and - subject to these terms, Apple grants you a personal, non-exclusive - license, under Apple's copyrights in this original Apple software (the - "Apple Software"), to use, reproduce, modify and redistribute the Apple - Software, with or without modifications, in source and/or binary forms; - provided that if you redistribute the Apple Software in its entirety and - without modifications, you must retain this notice and the following - text and disclaimers in all such redistributions of the Apple Software. - Neither the name, trademarks, service marks or logos of Apple Inc. - may be used to endorse or promote products derived from the Apple - Software without specific prior written permission from Apple. Except - as expressly stated in this notice, no other rights or licenses, express - or implied, are granted by Apple herein, including but not limited to - any patent rights that may be infringed by your derivative works or by - other works in which the Apple Software may be incorporated. - - The Apple Software is provided by Apple on an "AS IS" basis. APPLE - MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION - THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS - FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND - OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. - - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, - MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED - AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), - STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - - Copyright (C) 2012 Apple Inc. All Rights Reserved. - - */ - - - -#import - -@interface BTLEPeripheralViewController : UIViewController - -@end diff --git a/Classes/Tabs/BTLEPeripheralViewController.m b/Classes/Tabs/BTLEPeripheralViewController.m deleted file mode 100755 index 8cc76a3..0000000 --- a/Classes/Tabs/BTLEPeripheralViewController.m +++ /dev/null @@ -1,601 +0,0 @@ -/* - - File: LEPeripheralViewController.m - - Abstract: Interface to allow the user to enter data that will be - transferred to a version of the app in Central Mode, when it is brought - close enough. - - Version: 1.0 - - Disclaimer: IMPORTANT: This Apple software is supplied to you by - Apple Inc. ("Apple") in consideration of your agreement to the - following terms, and your use, installation, modification or - redistribution of this Apple software constitutes acceptance of these - terms. If you do not agree with these terms, please do not use, - install, modify or redistribute this Apple software. - - In consideration of your agreement to abide by the following terms, and - subject to these terms, Apple grants you a personal, non-exclusive - license, under Apple's copyrights in this original Apple software (the - "Apple Software"), to use, reproduce, modify and redistribute the Apple - Software, with or without modifications, in source and/or binary forms; - provided that if you redistribute the Apple Software in its entirety and - without modifications, you must retain this notice and the following - text and disclaimers in all such redistributions of the Apple Software. - Neither the name, trademarks, service marks or logos of Apple Inc. - may be used to endorse or promote products derived from the Apple - Software without specific prior written permission from Apple. Except - as expressly stated in this notice, no other rights or licenses, express - or implied, are granted by Apple herein, including but not limited to - any patent rights that may be infringed by your derivative works or by - other works in which the Apple Software may be incorporated. - - The Apple Software is provided by Apple on an "AS IS" basis. APPLE - MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION - THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS - FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND - OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. - - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, - MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED - AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), - STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - - Copyright (C) 2012 Apple Inc. All Rights Reserved. - - */ - -#import "BTLEPeripheralViewController.h" -#import -#import "TransferService.h" - - -@interface BTLEPeripheralViewController () -@property (strong, nonatomic) IBOutlet UITextView *textView; -@property (strong, nonatomic) IBOutlet UISwitch *advertisingSwitch; -@property (strong, nonatomic) CBPeripheralManager *peripheralManager; -@property (strong, nonatomic) CBMutableCharacteristic *transferCharacteristic; -@property (strong, nonatomic) NSData *dataToSend; -@property (nonatomic, readwrite) NSInteger sendDataIndex; -////////////Central Manager -@property (strong, nonatomic) CBCentralManager *centralManager; -@property (strong, nonatomic) CBPeripheral *discoveredPeripheral; -@property (strong, nonatomic) NSMutableData *data; -@property (strong, nonatomic) IBOutlet UITextView *central_textview; - -@property (retain) NSTimer *switchTimer; - -@end - -#define NOTIFY_MTU 20 - -@implementation BTLEPeripheralViewController - -#pragma mark - View Lifecycle - - - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - // Start up the CBPeripheralManager - _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil]; - - - // Start up the CBCentralManager - _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; - - // And somewhere to store the incoming data - _data = [[NSMutableData alloc] init]; -} - - -- (void)viewWillDisappear:(BOOL)animated -{ - // Don't keep it going while we're not showing. - [self.peripheralManager stopAdvertising]; - - [super viewWillDisappear:animated]; -} - - -#pragma mark - Central Methods - - - -/** centralManagerDidUpdateState is a required protocol method. - * Usually, you'd check for other states to make sure the current device supports LE, is powered on, etc. - * In this instance, we're just using it to wait for CBCentralManagerStatePoweredOn, which indicates - * the Central is ready to be used. - */ -- (void)centralManagerDidUpdateState:(CBCentralManager *)central -{ - if (central.state != CBCentralManagerStatePoweredOn) { - // In a real app, you'd deal with all the states correctly - return; - } - - // The state must be CBCentralManagerStatePoweredOn... - - // ... so start scanning - [self scan]; - -} - - -/** Scan for peripherals - specifically for our service's 128bit CBUUID - */ -- (void)scan -{ - [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] - options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }]; - - NSLog(@"Scanning started"); -} - - -/** This callback comes whenever a peripheral that is advertising the TRANSFER_SERVICE_UUID is discovered. - * We check the RSSI, to make sure it's close enough that we're interested in it, and if it is, - * we start the connection process - */ -- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI -{ - // Reject any where the value is above reasonable range - if (RSSI.integerValue > -15) { - return; - } - - // Reject if the signal strength is too low to be close enough (Close is around -22dB) - if (RSSI.integerValue < -35) { - return; - } - - NSLog(@"Discovered %@ at %@", peripheral.name, RSSI); - - // Ok, it's in range - have we already seen it? - if (self.discoveredPeripheral != peripheral) { - - // Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it - self.discoveredPeripheral = peripheral; - - // And connect - NSLog(@"Connecting to peripheral %@", peripheral); - [self.centralManager connectPeripheral:peripheral options:nil]; - } -} - - -/** If the connection fails for whatever reason, we need to deal with it. - */ -- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error -{ - NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]); - [self cleanup]; -} - - -/** We've connected to the peripheral, now we need to discover the services and characteristics to find the 'transfer' characteristic. - */ -- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral -{ - NSLog(@"Peripheral Connected"); - - // Stop scanning - [self.centralManager stopScan]; - NSLog(@"Scanning stopped"); - - // Clear the data that we may already have - [self.data setLength:0]; - - // Make sure we get the discovery callbacks - peripheral.delegate = self; - - // Search only for services that match our UUID - [peripheral discoverServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]]; -} - - -/** The Transfer Service was discovered - */ -- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error -{ - if (error) { - NSLog(@"Error discovering services: %@", [error localizedDescription]); - [self cleanup]; - return; - } - - // Discover the characteristic we want... - - // Loop through the newly filled peripheral.services array, just in case there's more than one. - for (CBService *service in peripheral.services) { - [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]] forService:service]; - } -} - - -/** The Transfer characteristic was discovered. - * Once this has been found, we want to subscribe to it, which lets the peripheral know we want the data it contains - */ -- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error -{ - // Deal with errors (if any) - if (error) { - NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); - [self cleanup]; - return; - } - - // Again, we loop through the array, just in case. - for (CBCharacteristic *characteristic in service.characteristics) { - - // And check if it's the right one - if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { - - // If it is, subscribe to it - [peripheral setNotifyValue:YES forCharacteristic:characteristic]; - } - } - - // Once this is complete, we just need to wait for the data to come in. -} - - -/** This callback lets us know more data has arrived via notification on the characteristic - */ -- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error -{ - if (error) { - NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); - return; - } - - NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]; - - // Have we got everything we need? - if ([stringFromData isEqualToString:@"EOM"]) { - - // We have, so show the data, - [self.central_textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]]; - - // Cancel our subscription to the characteristic - [peripheral setNotifyValue:NO forCharacteristic:characteristic]; - - // and disconnect from the peripehral - [self.centralManager cancelPeripheralConnection:peripheral]; - } - - // Otherwise, just add the data on to what we already have - [self.data appendData:characteristic.value]; - - // Log it - NSLog(@"Received: %@", stringFromData); -} - - -/** The peripheral letting us know whether our subscribe/unsubscribe happened or not - */ -- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error -{ - if (error) { - NSLog(@"Error changing notification state: %@", error.localizedDescription); - } - - // Exit if it's not the transfer characteristic - if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { - return; - } - - // Notification has started - if (characteristic.isNotifying) { - NSLog(@"Notification began on %@", characteristic); - } - - // Notification has stopped - else { - // so disconnect from the peripheral - NSLog(@"Notification stopped on %@. Disconnecting", characteristic); - [self.centralManager cancelPeripheralConnection:peripheral]; - } -} - - -/** Once the disconnection happens, we need to clean up our local copy of the peripheral - */ -- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error -{ - NSLog(@"Peripheral Disconnected"); - self.discoveredPeripheral = nil; - - // We're disconnected, so start scanning again - [self scan]; -} - - -/** Call this when things either go wrong, or you're done with the connection. - * This cancels any subscriptions if there are any, or straight disconnects if not. - * (didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved) - */ -- (void)cleanup -{ - // Don't do anything if we're not connected - if (!self.discoveredPeripheral.isConnected) { - return; - } - - // See if we are subscribed to a characteristic on the peripheral - if (self.discoveredPeripheral.services != nil) { - for (CBService *service in self.discoveredPeripheral.services) { - if (service.characteristics != nil) { - for (CBCharacteristic *characteristic in service.characteristics) { - if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { - if (characteristic.isNotifying) { - // It is notifying, so unsubscribe - [self.discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic]; - - // And we're done. - return; - } - } - } - } - } - } - - // If we've got this far, we're connected, but we're not subscribed, so we just disconnect - [self.centralManager cancelPeripheralConnection:self.discoveredPeripheral]; -} - - - - -#pragma mark - Peripheral Methods - - - -/** Required protocol method. A full app should take care of all the possible states, - * but we're just waiting for to know when the CBPeripheralManager is ready - */ -- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral -{ - // Opt out from any other state - if (peripheral.state != CBPeripheralManagerStatePoweredOn) { - return; - } - - // We're in CBPeripheralManagerStatePoweredOn state... - NSLog(@"self.peripheralManager powered on."); - - // ... so build our service. - - // Start with the CBMutableCharacteristic - self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID] - properties:CBCharacteristicPropertyNotify - value:nil - permissions:CBAttributePermissionsReadable]; - - // Then the service - CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] - primary:YES]; - - // Add the characteristic to the service - transferService.characteristics = @[self.transferCharacteristic]; - - // And add it to the peripheral manager - [self.peripheralManager addService:transferService]; -} - - -/** Catch when someone subscribes to our characteristic, then start sending them data - */ -- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic -{ - NSLog(@"Central subscribed to characteristic"); - - // Get the data - self.dataToSend = [self.textView.text dataUsingEncoding:NSUTF8StringEncoding]; - - // Reset the index - self.sendDataIndex = 0; - - // Start sending - [self sendData]; -} - - -/** Recognise when the central unsubscribes - */ -- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic -{ - NSLog(@"Central unsubscribed from characteristic"); -} - - -/** Sends the next amount of data to the connected central - */ -- (void)sendData -{ - // First up, check if we're meant to be sending an EOM - static BOOL sendingEOM = NO; - - if (sendingEOM) { - - // send it - BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; - - // Did it send? - if (didSend) { - - // It did, so mark it as sent - sendingEOM = NO; - - NSLog(@"Sent: EOM"); - } - - // It didn't send, so we'll exit and wait for peripheralManagerIsReadyToUpdateSubscribers to call sendData again - return; - } - - // We're not sending an EOM, so we're sending data - - // Is there any left to send? - - if (self.sendDataIndex >= self.dataToSend.length) { - - // No data left. Do nothing - return; - } - - // There's data left, so send until the callback fails, or we're done. - - BOOL didSend = YES; - - while (didSend) { - - // Make the next chunk - - // Work out how big it should be - NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex; - - // Can't be longer than 20 bytes - if (amountToSend > NOTIFY_MTU) amountToSend = NOTIFY_MTU; - - // Copy out the data we want - NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend]; - - // Send it - didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; - - // If it didn't work, drop out and wait for the callback - if (!didSend) { - return; - } - - NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding]; - NSLog(@"Sent: %@", stringFromData); - - // It did send, so update our index - self.sendDataIndex += amountToSend; - - // Was it the last one? - if (self.sendDataIndex >= self.dataToSend.length) { - - // It was - send an EOM - - // Set this so if the send fails, we'll send it next time - sendingEOM = YES; - - // Send it - BOOL eomSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; - - if (eomSent) { - // It sent, we're all done - sendingEOM = NO; - - NSLog(@"Sent: EOM"); - } - - return; - } - } -} - - -/** This callback comes in when the PeripheralManager is ready to send the next chunk of data. - * This is to ensure that packets will arrive in the order they are sent - */ -- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral -{ - // Start sending again - [self sendData]; -} - - - -#pragma mark - TextView Methods - - - -/** This is called when a change happens, so we know to stop advertising - */ -- (void)textViewDidChange:(UITextView *)textView -{ - // If we're already advertising, stop - if (self.advertisingSwitch.on) { - [self.advertisingSwitch setOn:NO]; - [self.peripheralManager stopAdvertising]; - } -} - - -/** Adds the 'Done' button to the title bar - */ -- (void)textViewDidBeginEditing:(UITextView *)textView -{ - // We need to add this manually so we have a way to dismiss the keyboard - UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonSystemItemDone target:self action:@selector(dismissKeyboard)]; - self.navigationItem.rightBarButtonItem = rightButton; -} - - -/** Finishes the editing */ -- (void)dismissKeyboard -{ - [self.textView resignFirstResponder]; - self.navigationItem.rightBarButtonItem = nil; -} - - - -#pragma mark - Switch Methods - - - -/** Start advertising - */ -- (IBAction)switchChanged:(id)sender -{ - if (self.advertisingSwitch.on) { - // All we advertise is our service's UUID - [self btle_seq]; - // [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }]; - } - - else { - [self.peripheralManager stopAdvertising]; - } -} - --(void)btle_switch_mode:(NSTimer *)switchtimer -{ -// NSLog(@"Timer is fired off"); - -// if (self.peripheralManager.state == CBPeripheralManagerStatePoweredOn) { -// [self.peripheralManager stopAdvertising]; -// return; -// } - -} - -- (void)btle_seq -{ - [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }]; - - - self.switchTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(btle_switch_mode:) userInfo:nil repeats:YES]; - - - -} - - - - - -@end diff --git a/Classes/Tabs/Contacts.h b/Classes/Tabs/Contacts.h new file mode 100644 index 0000000..d85bd95 --- /dev/null +++ b/Classes/Tabs/Contacts.h @@ -0,0 +1,24 @@ +// +// Contacts.h +// app +// +// Created by kiddjacky on 7/21/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import +#import + + +@interface Contacts : NSManagedObject + +@property (nonatomic, retain) NSDecimalNumber * age; +@property (nonatomic, retain) NSString * interest; +@property (nonatomic, retain) NSString * selfDescription; +@property (nonatomic, retain) NSString * sex; +@property (nonatomic, retain) id thumbnail; +@property (nonatomic, retain) NSString * userFullName; +@property (nonatomic, retain) NSString * userName; +@property (nonatomic, retain) NSString * firstLetter; + +@end diff --git a/Classes/Tabs/Contacts.m b/Classes/Tabs/Contacts.m new file mode 100644 index 0000000..dc1b1ea --- /dev/null +++ b/Classes/Tabs/Contacts.m @@ -0,0 +1,23 @@ +// +// Contacts.m +// app +// +// Created by kiddjacky on 7/21/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import "Contacts.h" + + +@implementation Contacts + +@dynamic age; +@dynamic interest; +@dynamic selfDescription; +@dynamic sex; +@dynamic thumbnail; +@dynamic userFullName; +@dynamic userName; +@dynamic firstLetter; + +@end diff --git a/Classes/Tabs/ContactsView.h b/Classes/Tabs/ContactsView.h new file mode 100644 index 0000000..2712391 --- /dev/null +++ b/Classes/Tabs/ContactsView.h @@ -0,0 +1,15 @@ +// +// ContactsView.h +// app +// +// Created by kiddjacky on 5/16/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import +#import "CoreDataTableViewController.h" + +@interface ContactsView : CoreDataTableViewController +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; + +@end diff --git a/Classes/Tabs/ContactsView.m b/Classes/Tabs/ContactsView.m new file mode 100644 index 0000000..7f0e8f7 --- /dev/null +++ b/Classes/Tabs/ContactsView.m @@ -0,0 +1,185 @@ +// +// ContactsView.m +// app +// +// Created by kiddjacky on 5/16/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import "ContactsView.h" +#import +#import "ProgressHUD.h" +#import "AppConstant.h" +#import "DatabaseAvailability.h" +#import "utilities.h" + +#import "Contacts.h" +#import "contactDetailsVC.h" + +@implementation ContactsView + +//------------------------------------------------------------------------------------------------------------------------------------------------- +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +//------------------------------------------------------------------------------------------------------------------------------------------------- +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + [[NSNotificationCenter defaultCenter] addObserverForName:DatabaseAvailabilityNotification + object:nil + queue:nil + usingBlock:^(NSNotification *note) { + NSLog(@"Get Contact database notification"); + self.managedObjectContext = note.userInfo[DatabaseAvailabilityContext]; + }]; + if (self) + { + [self.tabBarItem setImage:[UIImage imageNamed:@"contact-icon"]]; + self.tabBarItem.title = @"Contacts"; + } + return self; +} + +- (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext +{ + _managedObjectContext = managedObjectContext; + + NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Contacts"]; + request.predicate = nil; + request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"userFullName" + ascending:YES + selector:@selector(localizedStandardCompare:)]]; + + + //NSLog(@"Discover set managed object context %@", managedObjectContext); + + + self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request + managedObjectContext:managedObjectContext + sectionNameKeyPath:@"firstLetter" + cacheName:@"MyCache"]; + + + +} + +-(void)viewDidLoad +{ + [super viewDidLoad]; + self.title = @"Contacts"; + self.tableView.tableFooterView = [[UIView alloc] init]; + // Initialize the refresh control. + self.refreshControl = [[UIRefreshControl alloc] init]; + self.refreshControl.backgroundColor = [UIColor purpleColor]; + self.refreshControl.tintColor = [UIColor whiteColor]; + [self.refreshControl addTarget:self + action:@selector(reloadData) + forControlEvents:UIControlEventValueChanged]; + + +} + +//------------------------------------------------------------------------------------------------------------------------------------------------- +- (void)viewDidAppear:(BOOL)animated +//------------------------------------------------------------------------------------------------------------------------------------------------- +{ + [super viewDidAppear:animated]; + //--------------------------------------------------------------------------------------------------------------------------------------------- + if ([PFUser currentUser] != nil) + { + [[NSNotificationCenter defaultCenter] postNotificationName:PFUSER_READY object:nil]; + //[self loadContacts]; + } + else LoginUser(self); +} + + +- (void)reloadData +{ + // Reload table data + [self.tableView reloadData]; + + // End the refreshing + if (self.refreshControl) { + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + [formatter setDateFormat:@"MMM d, h:mm a"]; + NSString *title = [NSString stringWithFormat:@"Last update: %@", [formatter stringFromDate:[NSDate date]]]; + NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject:[UIColor whiteColor] + forKey:NSForegroundColorAttributeName]; + NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:title attributes:attrsDictionary]; + self.refreshControl.attributedTitle = attributedTitle; + + [self.refreshControl endRefreshing]; + } +} + + +#pragma mark - table view + + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; + if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"]; + + + Contacts *contact = [self.fetchedResultsController objectAtIndexPath:indexPath]; + cell.textLabel.text = contact.userFullName; + cell.detailTextLabel.text = contact.selfDescription; + NSLog(@"update contacts view, first letter %@",contact.firstLetter); + if (contact.thumbnail != nil) { + cell.imageView.image = [UIImage imageWithData:contact.thumbnail]; + } + /* + cell.imageView.image = [UIImage imageWithData:contact.thumbnail]; + if (!cell.imageView.image) { + dispatch_queue_t q = dispatch_queue_create("Thumbnail Contact Photo", 0); + dispatch_async(q, ^{ + NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:contact.thumbnailURL]]; + [self.managedObjectContext performBlock:^{ + contact.thumbnail = imageData; + dispatch_async(dispatch_get_main_queue(), ^{ + [cell setNeedsLayout]; + }); + }]; + }); + } + */ + + return cell; + +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + Contacts *contact = [self.fetchedResultsController objectAtIndexPath:indexPath]; + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + contactDetailsVC *ivc = [[contactDetailsVC alloc] init]; + ivc.contact = contact; + [self.navigationController pushViewController:ivc animated:YES]; +} + +#pragma mark - Table view delegate +-(void)prepareViewController:(id)vc forSegue:(NSString *)segueIdentifier fromIndexPath:(NSIndexPath *)indexPath +{ + Contacts *user_contact = [self.fetchedResultsController objectAtIndexPath:indexPath]; + if ([vc isKindOfClass:[contactDetailsVC class]]) { + contactDetailsVC *dv = (contactDetailsVC *)vc; + dv.contact = user_contact; + // NSLog(@"debug prepare = %@", dv.discoverUser.userName); + } +} + +-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender +{ + NSIndexPath *indexPath = nil; + if([sender isKindOfClass:[UITableViewCell class]]) { + indexPath = [self.tableView indexPathForCell:sender]; + } + [self prepareViewController:segue.destinationViewController + forSegue:segue.identifier + fromIndexPath:indexPath]; +} + + + +@end diff --git a/Classes/Tabs/CoreDataTableViewController.h b/Classes/Tabs/CoreDataTableViewController.h new file mode 100644 index 0000000..bd58a04 --- /dev/null +++ b/Classes/Tabs/CoreDataTableViewController.h @@ -0,0 +1,38 @@ +// +// CoreDataTableViewController.h +// +// Created for Stanford CS193p Fall 2013. +// Copyright 2013 Stanford University. All rights reserved. +// +// This class mostly just copies the code from NSFetchedResultsController's documentation page +// into a subclass of UITableViewController. +// +// Just subclass this and set the fetchedResultsController. +// The only UITableViewDataSource method you'll HAVE to implement is tableView:cellForRowAtIndexPath:. +// And you can use the NSFetchedResultsController method objectAtIndexPath: to do it. +// +// Remember that once you create an NSFetchedResultsController, you CANNOT modify its @propertys. +// If you want new fetch parameters (predicate, sorting, etc.), +// create a NEW NSFetchedResultsController and set this class's fetchedResultsController @property again. +// + +#import +#import + +@interface CoreDataTableViewController : UITableViewController + +// The controller (this class fetches nothing if this is not set). +@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController; + +// Causes the fetchedResultsController to refetch the data. +// You almost certainly never need to call this. +// The NSFetchedResultsController class observes the context +// (so if the objects in the context change, you do not need to call performFetch +// since the NSFetchedResultsController will notice and update the table automatically). +// This will also automatically be called if you change the fetchedResultsController @property. +- (void)performFetch; + +// Set to YES to get some debugging output in the console. +@property BOOL debug; + +@end diff --git a/Classes/Tabs/CoreDataTableViewController.m b/Classes/Tabs/CoreDataTableViewController.m new file mode 100644 index 0000000..cf56e64 --- /dev/null +++ b/Classes/Tabs/CoreDataTableViewController.m @@ -0,0 +1,142 @@ +// +// CoreDataTableViewController.m +// +// Created for Stanford CS193p Fall 2013. +// Copyright 2013 Stanford University. All rights reserved. +// + +#import "CoreDataTableViewController.h" + +@implementation CoreDataTableViewController + +#pragma mark - Fetching + +- (void)performFetch +{ + if (self.fetchedResultsController) { + if (self.fetchedResultsController.fetchRequest.predicate) { + if (self.debug) NSLog(@"[%@ %@] fetching %@ with predicate: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName, self.fetchedResultsController.fetchRequest.predicate); + } else { + if (self.debug) NSLog(@"[%@ %@] fetching all %@ (i.e., no predicate)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName); + } + NSError *error; + BOOL success = [self.fetchedResultsController performFetch:&error]; + if (!success) NSLog(@"[%@ %@] performFetch: failed", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); + if (error) NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]); + } else { + if (self.debug) NSLog(@"[%@ %@] no NSFetchedResultsController (yet?)", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); + } + [self.tableView reloadData]; +} + +- (void)setFetchedResultsController:(NSFetchedResultsController *)newfrc +{ + NSFetchedResultsController *oldfrc = _fetchedResultsController; + if (newfrc != oldfrc) { + _fetchedResultsController = newfrc; + newfrc.delegate = self; + if ((!self.title || [self.title isEqualToString:oldfrc.fetchRequest.entity.name]) && (!self.navigationController || !self.navigationItem.title)) { + self.title = newfrc.fetchRequest.entity.name; + } + if (newfrc) { + if (self.debug) NSLog(@"[%@ %@] %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), oldfrc ? @"updated" : @"set"); + [self performFetch]; + } else { + if (self.debug) NSLog(@"[%@ %@] reset to nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); + [self.tableView reloadData]; + } + } +} + +#pragma mark - UITableViewDataSource + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + NSInteger sections = [[self.fetchedResultsController sections] count]; + return sections; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + NSInteger rows = 0; + if ([[self.fetchedResultsController sections] count] > 0) { + id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; + rows = [sectionInfo numberOfObjects]; + } + return rows; +} + +- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section +{ + return [[[self.fetchedResultsController sections] objectAtIndex:section] name]; +} + +- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index +{ + return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index]; +} + +- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView +{ + return [self.fetchedResultsController sectionIndexTitles]; +} + +#pragma mark - NSFetchedResultsControllerDelegate + +- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller +{ + [self.tableView beginUpdates]; +} + +- (void)controller:(NSFetchedResultsController *)controller + didChangeSection:(id )sectionInfo + atIndex:(NSUInteger)sectionIndex + forChangeType:(NSFetchedResultsChangeType)type +{ + switch(type) + { + case NSFetchedResultsChangeInsert: + [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; + break; + + case NSFetchedResultsChangeDelete: + [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; + break; + } +} + + +- (void)controller:(NSFetchedResultsController *)controller + didChangeObject:(id)anObject + atIndexPath:(NSIndexPath *)indexPath + forChangeType:(NSFetchedResultsChangeType)type + newIndexPath:(NSIndexPath *)newIndexPath +{ + switch(type) + { + case NSFetchedResultsChangeInsert: + [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; + break; + + case NSFetchedResultsChangeDelete: + [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; + break; + + case NSFetchedResultsChangeUpdate: + [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; + break; + + case NSFetchedResultsChangeMove: + [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; + [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; + break; + } +} + +- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller +{ + [self.tableView endUpdates]; +} + +@end + diff --git a/Classes/Tabs/CurrentUser.h b/Classes/Tabs/CurrentUser.h new file mode 100644 index 0000000..66786d2 --- /dev/null +++ b/Classes/Tabs/CurrentUser.h @@ -0,0 +1,43 @@ +// +// CurrentUser.h +// app +// +// Created by kiddjacky on 5/24/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import +#import + +@class Contacts, DiscoverUser; + +@interface CurrentUser : NSManagedObject + +@property (nonatomic, retain) NSDecimalNumber * age; +@property (nonatomic, retain) NSDate * birthday; +@property (nonatomic, retain) NSString * interest; +@property (nonatomic, retain) NSString * selfDescription; +@property (nonatomic, retain) NSString * sex; +@property (nonatomic, retain) NSString * userName; +@property (nonatomic, retain) id thumbnail; +@property (nonatomic, retain) id picture; +@property (nonatomic, retain) NSData * contactList; +@property (nonatomic, retain) NSString * userFullName; +@property (nonatomic, retain) NSSet *contacts; +@property (nonatomic, retain) NSSet *discovers; +@property (nonatomic, retain) NSString *firstLetter; +@end + +@interface CurrentUser (CoreDataGeneratedAccessors) + +- (void)addContactsObject:(Contacts *)value; +- (void)removeContactsObject:(Contacts *)value; +- (void)addContacts:(NSSet *)values; +- (void)removeContacts:(NSSet *)values; + +- (void)addDiscoversObject:(DiscoverUser *)value; +- (void)removeDiscoversObject:(DiscoverUser *)value; +- (void)addDiscovers:(NSSet *)values; +- (void)removeDiscovers:(NSSet *)values; + +@end diff --git a/Classes/Tabs/CurrentUser.m b/Classes/Tabs/CurrentUser.m new file mode 100644 index 0000000..1cac22e --- /dev/null +++ b/Classes/Tabs/CurrentUser.m @@ -0,0 +1,54 @@ +// +// CurrentUser.m +// app +// +// Created by kiddjacky on 5/24/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import "CurrentUser.h" +#import "Contacts.h" +#import "DiscoverUser.h" + + +@implementation CurrentUser + +@dynamic age; +@dynamic birthday; +@dynamic interest; +@dynamic selfDescription; +@dynamic sex; +@dynamic userName; +@dynamic thumbnail; +@dynamic picture; +@dynamic contactList; +@dynamic userFullName; +@dynamic contacts; +@dynamic discovers; +@dynamic firstLetter; + + +@end + + +@interface Contacts (firstLetter) + +@end + +@implementation Contacts (firstLetter) + +- (NSString *)firstLetter { + [self willAccessValueForKey:@"firstLetter"]; + NSString *aString = [[self valueForKey:@"userFullName"] uppercaseString]; + + // support UTF-16: + NSString *stringToReturn = [aString substringWithRange:[aString rangeOfComposedCharacterSequenceAtIndex:0]]; + + // OR no UTF-16 support: + //NSString *stringToReturn = [aString substringToIndex:1]; + + [self didAccessValueForKey:@"firstLetter"]; + return stringToReturn; +} + +@end diff --git a/Classes/Tabs/DiscoverUser.h b/Classes/Tabs/DiscoverUser.h index 9b884f3..799deb1 100644 --- a/Classes/Tabs/DiscoverUser.h +++ b/Classes/Tabs/DiscoverUser.h @@ -2,7 +2,7 @@ // DiscoverUser.h // app // -// Created by kiddjacky on 4/18/15. +// Created by kiddjacky on 7/7/15. // Copyright (c) 2015 KZ. All rights reserved. // @@ -12,9 +12,11 @@ @interface DiscoverUser : NSManagedObject -@property (nonatomic, retain) NSString * userName; -@property (nonatomic, retain) NSDate * timeMeet; -@property (nonatomic, retain) NSNumber * longtitude; @property (nonatomic, retain) NSNumber * latitude; +@property (nonatomic, retain) NSNumber * longitude; +@property (nonatomic, retain) NSData * thumbnail; +@property (nonatomic, retain) NSDate * timeMeet; +@property (nonatomic, retain) NSString * userFullName; +@property (nonatomic, retain) NSString * userName; @end diff --git a/Classes/Tabs/DiscoverUser.m b/Classes/Tabs/DiscoverUser.m index 72fd1b6..2d58f01 100644 --- a/Classes/Tabs/DiscoverUser.m +++ b/Classes/Tabs/DiscoverUser.m @@ -2,7 +2,7 @@ // DiscoverUser.m // app // -// Created by kiddjacky on 4/18/15. +// Created by kiddjacky on 7/7/15. // Copyright (c) 2015 KZ. All rights reserved. // @@ -11,9 +11,11 @@ @implementation DiscoverUser -@dynamic userName; -@dynamic timeMeet; -@dynamic longtitude; @dynamic latitude; +@dynamic longitude; +@dynamic thumbnail; +@dynamic timeMeet; +@dynamic userFullName; +@dynamic userName; @end diff --git a/Classes/Tabs/DiscoversView+MOC.h b/Classes/Tabs/DiscoversView+MOC.h new file mode 100644 index 0000000..3754ecc --- /dev/null +++ b/Classes/Tabs/DiscoversView+MOC.h @@ -0,0 +1,13 @@ +// +// DiscoversView+MOC.h +// app +// +// Created by kiddjacky on 5/3/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import "DiscoversView.h" + +@interface DiscoversView (MOC) +- (NSManagedObjectContext *)createMainQueueManagedObjectContext; +@end diff --git a/Classes/Tabs/DiscoversView+MOC.m b/Classes/Tabs/DiscoversView+MOC.m new file mode 100644 index 0000000..43b434a --- /dev/null +++ b/Classes/Tabs/DiscoversView+MOC.m @@ -0,0 +1,99 @@ +// +// DiscoversView+MOC.m +// app +// +// Created by kiddjacky on 5/3/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import "DiscoversView+MOC.h" + +@implementation DiscoversView (MOC) + +#pragma mark - Core Data + +- (void)saveContext:(NSManagedObjectContext *)managedObjectContext +{ + NSError *error = nil; + if (managedObjectContext != nil) { + if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { + // Replace this implementation with code to handle the error appropriately. + // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + NSLog(@"Unresolved error %@, %@", error, [error userInfo]); + abort(); + } + } +} + +// Returns the managed object context for the application. +// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application. +- (NSManagedObjectContext *)createMainQueueManagedObjectContext +{ + NSManagedObjectContext *managedObjectContext = nil; + NSPersistentStoreCoordinator *coordinator = [self createPersistentStoreCoordinator]; + if (coordinator != nil) { + managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; + [managedObjectContext setPersistentStoreCoordinator:coordinator]; + } + return managedObjectContext; +} + +// Returns the managed object model for the application. +// If the model doesn't already exist, it is created from the application's model. +- (NSManagedObjectModel *)createManagedObjectModel +{ + NSManagedObjectModel *managedObjectModel = nil; + NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Discover" withExtension:@"momd"]; + managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; + return managedObjectModel; +} + +// Returns the persistent store coordinator for the application. +// If the coordinator doesn't already exist, it is created and the application's store added to it. +- (NSPersistentStoreCoordinator *)createPersistentStoreCoordinator +{ + NSPersistentStoreCoordinator *persistentStoreCoordinator = nil; + NSManagedObjectModel *managedObjectModel = [self createManagedObjectModel]; + + NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MOC.sqlite"]; + + NSError *error = nil; + persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel]; + if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { + /* + Replace this implementation with code to handle the error appropriately. + + abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + + Typical reasons for an error here include: + * The persistent store is not accessible; + * The schema for the persistent store is incompatible with current managed object model. + Check the error message to determine what the actual problem was. + + + If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory. + + If you encounter schema incompatibility errors during development, you can reduce their frequency by: + * Simply deleting the existing store: + [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil] + + * Performing automatic lightweight migration by passing the following dictionary as the options parameter: + @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} + + Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. + + */ + NSLog(@"Unresolved error %@, %@", error, [error userInfo]); + abort(); + } + + return persistentStoreCoordinator; +} + +// Returns the URL to the application's Documents directory + +- (NSURL *)applicationDocumentsDirectory +{ + return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; +} +@end diff --git a/Classes/Tabs/DiscoversView.h b/Classes/Tabs/DiscoversView.h index 30d16ae..0de978e 100644 --- a/Classes/Tabs/DiscoversView.h +++ b/Classes/Tabs/DiscoversView.h @@ -7,7 +7,8 @@ // #import +#import "CoreDataTableViewController.h" -@interface DiscoversView : UITableViewController - +@interface DiscoversView : CoreDataTableViewController +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; @end diff --git a/Classes/Tabs/DiscoversView.m b/Classes/Tabs/DiscoversView.m index 0e616dd..5fffcaa 100644 --- a/Classes/Tabs/DiscoversView.m +++ b/Classes/Tabs/DiscoversView.m @@ -7,32 +7,12 @@ // #import "DiscoversView.h" -#import -#import "TransferService.h" -#import - - - - -@interface DiscoversView () -//setup BTLE -@property (strong, nonatomic) CBPeripheralManager *peripheralManager; -@property (strong, nonatomic) CBCentralManager *centralManager; -@property (strong, nonatomic) CBPeripheral *discoveredPeripheral; -//unused for now -@property (strong, nonatomic) NSMutableData *data; -@property (strong, nonatomic) CBMutableCharacteristic *transferCharacteristic; -@property (strong, nonatomic) NSData *dataToSend; -@property (nonatomic, readwrite) NSInteger sendDataIndex; -@property (strong, nonatomic) IBOutlet UITextView *central_textview; -@property (strong, nonatomic) IBOutlet UITextView *textView; -@property (strong, nonatomic) IBOutlet UISwitch *advertisingSwitch; - -@property (strong, nonatomic) NSMutableArray *discoveredDevices; -@property (strong, nonatomic) CLLocationManager *locationManager; -@property (readonly) CLLocationCoordinate2D *coordinate; -@end +#import "detailsView.h" +#import "DiscoverUser.h" +#import "discoversCell.h" + +#import "DatabaseAvailability.h" #import #import "ProgressHUD.h" @@ -46,20 +26,27 @@ @interface DiscoversView () -15) { - return; - } - - // Reject if the signal strength is too low to be close enough (Close is around -22dB) - if (RSSI.integerValue < -35) { - return; - } - */ - NSLog(@"Discovered %@ at %@", peripheral.name, RSSI); - NSString *userName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; - - BOOL matched = 0; - for (NSString *foundUser in self.discoveredDevices) { - //NSLog(@"discoverd before %@", discovered.name); - if ([userName isEqualToString:foundUser]) { - matched = 1; - } - } - - /* use peripheral.name to filter - for (CBPeripheral *discovered in self.discoveredDevices) { - //NSLog(@"discoverd before %@", discovered.name); - if (discovered.name == peripheral.name) { - matched = 1; - } - } - */ - - // Ok, it's in range - have we already seen it? - //if (self.discoveredPeripheral != peripheral) { - if (!matched) { - // Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it - //self.discoveredPeripheral = peripheral; - - /* no need to connect - // And connect - NSLog(@"Connecting to peripheral %@", peripheral); - [self.centralManager connectPeripheral:peripheral options:nil]; - */ - //NSString *userName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; - - NSLog(@"userName is %@, advertisement Data is %@, RSSI value is %@", userName, advertisementData, RSSI); - if (userName != NULL) { - [self.discoveredDevices addObject:userName]; - PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME]; - [query whereKey:PF_USER_USERNAME equalTo:userName]; - [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) - { - if ([objects count] != 0) - { - - PFUser *user = [objects firstObject]; - NSLog(@"found user %@", user.username); - [DiscoverItems addObject:user]; - [discoverLocation addObject:currentLocation]; - [discoverTime addObject:eventDate]; - [self.tableView reloadData]; - } - }]; - - } - } -} - - -/** If the connection fails for whatever reason, we need to deal with it. - */ -- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error -{ - NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]); - [self cleanup]; -} - - -/** We've connected to the peripheral, now we need to discover the services and characteristics to find the 'transfer' characteristic. - */ -- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral -{ - NSLog(@"Peripheral Connected"); - - // Stop scanning - [self.centralManager stopScan]; - NSLog(@"Scanning stopped"); - - // Clear the data that we may already have - [self.data setLength:0]; - - // Make sure we get the discovery callbacks - peripheral.delegate = self; - - // Search only for services that match our UUID - [peripheral discoverServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]]; } -/** The Transfer Service was discovered - */ -- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error -{ - if (error) { - NSLog(@"Error discovering services: %@", [error localizedDescription]); - [self cleanup]; - return; - } - - // Discover the characteristic we want... - - // Loop through the newly filled peripheral.services array, just in case there's more than one. - for (CBService *service in peripheral.services) { - [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]] forService:service]; - } -} - - -/** The Transfer characteristic was discovered. - * Once this has been found, we want to subscribe to it, which lets the peripheral know we want the data it contains - */ -- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error -{ - // Deal with errors (if any) - if (error) { - NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); - [self cleanup]; - return; - } - - // Again, we loop through the array, just in case. - for (CBCharacteristic *characteristic in service.characteristics) { - - // And check if it's the right one - if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { - - // If it is, subscribe to it - [peripheral setNotifyValue:YES forCharacteristic:characteristic]; - } - } - - // Once this is complete, we just need to wait for the data to come in. -} - - -/** This callback lets us know more data has arrived via notification on the characteristic - */ -- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error -{ - if (error) { - NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); - return; - } - - NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]; - - // Have we got everything we need? - if ([stringFromData isEqualToString:@"EOM"]) { - - // We have, so show the data, - [self.central_textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]]; - - // Cancel our subscription to the characteristic - [peripheral setNotifyValue:NO forCharacteristic:characteristic]; - - // and disconnect from the peripehral - [self.centralManager cancelPeripheralConnection:peripheral]; - } - - // Otherwise, just add the data on to what we already have - [self.data appendData:characteristic.value]; - - // Log it - NSLog(@"Received: %@", stringFromData); -} - - -/** The peripheral letting us know whether our subscribe/unsubscribe happened or not - */ -- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error -{ - if (error) { - NSLog(@"Error changing notification state: %@", error.localizedDescription); - } - - // Exit if it's not the transfer characteristic - if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { - return; - } - - // Notification has started - if (characteristic.isNotifying) { - NSLog(@"Notification began on %@", characteristic); - } - - // Notification has stopped - else { - // so disconnect from the peripheral - NSLog(@"Notification stopped on %@. Disconnecting", characteristic); - [self.centralManager cancelPeripheralConnection:peripheral]; - } -} - - -/** Once the disconnection happens, we need to clean up our local copy of the peripheral - */ -- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error -{ - NSLog(@"Peripheral Disconnected"); - self.discoveredPeripheral = nil; - - // We're disconnected, so start scanning again - [self scan]; -} - - -/** Call this when things either go wrong, or you're done with the connection. - * This cancels any subscriptions if there are any, or straight disconnects if not. - * (didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved) - */ -- (void)cleanup -{ - // Don't do anything if we're not connected - if (!self.discoveredPeripheral == CBPeripheralStateConnecting) { - return; - } - - // See if we are subscribed to a characteristic on the peripheral - if (self.discoveredPeripheral.services != nil) { - for (CBService *service in self.discoveredPeripheral.services) { - if (service.characteristics != nil) { - for (CBCharacteristic *characteristic in service.characteristics) { - if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { - if (characteristic.isNotifying) { - // It is notifying, so unsubscribe - [self.discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic]; - - // And we're done. - return; - } - } - } - } - } - } - - // If we've got this far, we're connected, but we're not subscribed, so we just disconnect - [self.centralManager cancelPeripheralConnection:self.discoveredPeripheral]; -} - - - - -#pragma mark - Peripheral Methods - - - -/** Required protocol method. A full app should take care of all the possible states, - * but we're just waiting for to know when the CBPeripheralManager is ready - */ -- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral +#pragma mark - Table view delegate +-(void)prepareViewController:(id)vc forSegue:(NSString *)segueIdentifier fromIndexPath:(NSIndexPath *)indexPath { - // Opt out from any other state - if (peripheral.state != CBPeripheralManagerStatePoweredOn) { - return; + DiscoverUser *discoverUser = [self.fetchedResultsController objectAtIndexPath:indexPath]; + if ([vc isKindOfClass:[detailsView class]]) { + detailsView *dv = (detailsView *)vc; + dv.discoverUser = discoverUser; } - - // We're in CBPeripheralManagerStatePoweredOn state... - NSLog(@"self.peripheralManager powered on."); - [self btle_seq]; - // ... so build our service. - - // Start with the CBMutableCharacteristic - self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID] - properties:CBCharacteristicPropertyNotify - value:nil - permissions:CBAttributePermissionsReadable]; - - // Then the service - CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] - primary:YES]; - - // Add the characteristic to the service - transferService.characteristics = @[self.transferCharacteristic]; - - // And add it to the peripheral manager - [self.peripheralManager addService:transferService]; -} - - -/** Catch when someone subscribes to our characteristic, then start sending them data - */ -- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic -{ - NSLog(@"Central subscribed to characteristic"); - - // Get the data - self.dataToSend = [self.textView.text dataUsingEncoding:NSUTF8StringEncoding]; - - // Reset the index - self.sendDataIndex = 0; - - // Start sending - [self sendData]; } - -/** Recognise when the central unsubscribes - */ -- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic +-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - NSLog(@"Central unsubscribed from characteristic"); -} - - -/** Sends the next amount of data to the connected central - */ -- (void)sendData -{ - // First up, check if we're meant to be sending an EOM - static BOOL sendingEOM = NO; - - if (sendingEOM) { - - // send it - BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; - - // Did it send? - if (didSend) { - - // It did, so mark it as sent - sendingEOM = NO; - - NSLog(@"Sent: EOM"); - } - - // It didn't send, so we'll exit and wait for peripheralManagerIsReadyToUpdateSubscribers to call sendData again - return; - } - - // We're not sending an EOM, so we're sending data - - // Is there any left to send? - - if (self.sendDataIndex >= self.dataToSend.length) { - - // No data left. Do nothing - return; - } - - // There's data left, so send until the callback fails, or we're done. - - BOOL didSend = YES; - - while (didSend) { - - // Make the next chunk - - // Work out how big it should be - NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex; - - // Can't be longer than 20 bytes - if (amountToSend > NOTIFY_MTU) amountToSend = NOTIFY_MTU; - - // Copy out the data we want - NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend]; - - // Send it - didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; - - // If it didn't work, drop out and wait for the callback - if (!didSend) { - return; - } - - NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding]; - NSLog(@"Sent: %@", stringFromData); - - // It did send, so update our index - self.sendDataIndex += amountToSend; - - // Was it the last one? - if (self.sendDataIndex >= self.dataToSend.length) { - - // It was - send an EOM - - // Set this so if the send fails, we'll send it next time - sendingEOM = YES; - - // Send it - BOOL eomSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; - - if (eomSent) { - // It sent, we're all done - sendingEOM = NO; - - NSLog(@"Sent: EOM"); - } - - return; - } + NSIndexPath *indexPath = nil; + if([sender isKindOfClass:[UITableViewCell class]]) { + indexPath = [self.tableView indexPathForCell:sender]; } + [self prepareViewController:segue.destinationViewController + forSegue:segue.identifier + fromIndexPath:indexPath]; } -/** This callback comes in when the PeripheralManager is ready to send the next chunk of data. - * This is to ensure that packets will arrive in the order they are sent - */ -- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral -{ - // Start sending again - [self sendData]; -} - - -/** Start advertising - */ -- (IBAction)switchChanged:(id)sender +//------------------------------------------------------------------------------------------------------------------------------------------------- +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +//------------------------------------------------------------------------------------------------------------------------------------------------- { - if (self.advertisingSwitch.on) { - // All we advertise is our service's UUID - [self btle_seq]; - // [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }]; - } - - else { - [self.peripheralManager stopAdvertising]; + /* + id detailvc = [self.splitViewController.viewControllers lastObject]; + if([detailvc isKindOfClass:[UINavigationController class]]) { + detailvc = [((UINavigationController *)detailvc).viewControllers firstObject]; + [self prepareViewController:detailvc forSegue:nil fromIndexPath:indexPath]; } -} - --(void)btle_switch_mode:(NSTimer *)switchtimer -{ - // NSLog(@"Timer is fired off"); - - // if (self.peripheralManager.state == CBPeripheralManagerStatePoweredOn) { - // [self.peripheralManager stopAdvertising]; - // return; - // } + */ + DiscoverUser *discoverUser = [self.fetchedResultsController objectAtIndexPath:indexPath]; + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + detailsView *dv = [[detailsView alloc] init]; + dv.discoverUser = discoverUser; + CLLocationDegrees longitude = [discoverUser.longitude doubleValue]; + CLLocationDegrees latitude = [discoverUser.latitude doubleValue]; + CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude]; + dv.location = location; + dv.context = self.managedObjectContext; + [self.navigationController pushViewController:dv animated:YES]; + /* + //--------------------------------------------------------------------------------------------------------------------------------------------- + PFUser *user = DiscoverItems[indexPath.row]; + //NSString *discoverId = discover.objectId; + //--------------------------------------------------------------------------------------------------------------------------------------------- + //CreateMessageItem([PFUser currentUser], discoverId, discover[PF_GROUPS_NAME]); + NSString *discoverId = StartPrivateChat([PFUser currentUser], user); + //--------------------------------------------------------------------------------------------------------------------------------------------- + ChatView *chatView = [[ChatView alloc] initWith:discoverId]; + chatView.hidesBottomBarWhenPushed = YES; + [self.navigationController pushViewController:chatView animated:YES]; + */ } -- (void)btle_seq -{ - PFUser *user = [PFUser currentUser]; - - [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] , CBAdvertisementDataLocalNameKey : user.username }]; - NSLog(@"send out advertisment data, user name is %@", user.username); - - //self.switchTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(btle_switch_mode:) userInfo:nil repeats:YES]; - - - -} @end diff --git a/Classes/Tabs/PhotoDatabaseAvailability.h b/Classes/Tabs/PhotoDatabaseAvailability.h new file mode 100644 index 0000000..7fc3452 --- /dev/null +++ b/Classes/Tabs/PhotoDatabaseAvailability.h @@ -0,0 +1,15 @@ +// +// PhotoDatabaseAvailability.h +// Photomania +// +// Created by CS193p Instructor. +// Copyright (c) 2013 Stanford University. All rights reserved. +// + +#ifndef Photomania_PhotoDatabaseAvailability_h +#define Photomania_PhotoDatabaseAvailability_h + +#define DatabaseAvailabilityNotification @"DatabaseAvailabilityNotification" +#define PhotoDatabaseAvailabilityContext @"Context" + +#endif diff --git a/Classes/Tabs/contactDetailsVC.h b/Classes/Tabs/contactDetailsVC.h new file mode 100644 index 0000000..1be7582 --- /dev/null +++ b/Classes/Tabs/contactDetailsVC.h @@ -0,0 +1,17 @@ +// +// contactDetailsVC.h +// app +// +// Created by kiddjacky on 5/16/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import +#import "Contacts.h" +#import "DiscoverUser.h" + +@interface contactDetailsVC : UIViewController +@property (strong, nonatomic) Contacts *contact; +@property (strong, nonatomic) DiscoverUser *discoverUser; + +@end diff --git a/Classes/Tabs/contactDetailsVC.m b/Classes/Tabs/contactDetailsVC.m new file mode 100644 index 0000000..34880b1 --- /dev/null +++ b/Classes/Tabs/contactDetailsVC.m @@ -0,0 +1,195 @@ +// +// contactDetailsVC.m +// app +// +// Created by kiddjacky on 5/16/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import "contactDetailsVC.h" +#import +#import +#import +#import "DiscoverUser.h" + +#import "ProgressHUD.h" + +#import "AppConstant.h" +#import "messages.h" +#import "utilities.h" + +#import "ChatView.h" +#import "Contacts.h" + +@interface contactDetailsVC () +@property UIButton *chat; +@property UILabel *userFullName; +@property UILabel *age; +@property UILabel *interest; +@property UILabel *selfDescription; + +@property UIView *chatContainerView; +@property UIView *labelContainerView; +@property UILabel *label; +@end + + +@implementation contactDetailsVC + +-(void)viewDidLoad { + [super viewDidLoad]; + [self loadView]; + [self loadUser]; + + self.label = [[UILabel alloc] init]; +// [self.label setBackgroundColor:[UIColor redColor]]; + self.label.lineBreakMode = NSLineBreakByWordWrapping; + self.label.numberOfLines = 10; + NSString *full_name = [NSString stringWithFormat:@"Full name = %@", self.contact.userFullName ]; + NSString *age = [NSString stringWithFormat:@"Age = %@", self.contact.age ]; + NSString *sex = [NSString stringWithFormat:@"Sex = %@", self.contact.sex ]; + NSString *interest = [NSString stringWithFormat:@"interest = %@", self.contact.interest ]; + NSString *self_description = [NSString stringWithFormat:@"self description = %@", self.contact.selfDescription ]; + + self.label.text = [NSString stringWithFormat:@"%@ \r %@ \r %@ \r %@ \r %@", full_name, age, sex, interest, self_description]; + [self.label setFont:[UIFont fontWithName:@"System" size:30]]; + NSLog(@"text label = %@", self.label.text); + self.label.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + [self.label sizeToFit]; + self.labelContainerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)]; + self.labelContainerView.translatesAutoresizingMaskIntoConstraints = NO; +// [self.labelContainerView setBackgroundColor:[UIColor blueColor]]; + [self.labelContainerView addSubview:self.label]; + [self.view addSubview:self.labelContainerView]; + + + _chat = [UIButton buttonWithType:UIButtonTypeCustom]; + self.chat.layer.cornerRadius = 10; + self.chat.clipsToBounds = YES; + [self.chat setTitle:@"Chat" forState:UIControlStateNormal]; + [self.chat setBackgroundColor:[UIColor blueColor]]; + self.chat.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + + self.chatContainerView = [[UIView alloc] initWithFrame:CGRectZero]; + self.chatContainerView.translatesAutoresizingMaskIntoConstraints = NO; + + [self.chatContainerView addSubview:self.chat]; + [self.view addSubview:self.chatContainerView]; + + NSDictionary *viewsDictionary = @{@"chat_view":self.chatContainerView, @"labelView":self.labelContainerView}; + + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.chatContainerView + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeHeight + multiplier:0.1 + constant:0.0]]; + + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.labelContainerView + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeHeight + multiplier:0.1 + constant:0.0]]; + + + + NSArray *constraint_POS_V_label = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[labelView]" + options:0 + metrics:nil + views:viewsDictionary]; + + NSArray *constraint_POS_H_label = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[labelView]-50-|" + options:0 + metrics:nil + views:viewsDictionary]; + + + + + NSArray *constraint_POS_V_chat = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[chat_view]-50-|" + options:0 + metrics:nil + views:viewsDictionary]; + + NSArray *constraint_POS_H_chat = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[chat_view]-50-|" + options:0 + metrics:nil + views:viewsDictionary]; + [self.view addConstraints:constraint_POS_V_chat]; + [self.view addConstraints:constraint_POS_H_chat]; + [self.view addConstraints:constraint_POS_V_label]; + [self.view addConstraints:constraint_POS_H_label]; + + + [self.chat addTarget:self action:@selector(actionChat) forControlEvents:UIControlEventTouchUpInside]; + +} + +-(void)loadView +{ + CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame]; + UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame]; + contentView.backgroundColor = [UIColor whiteColor]; + self.view = contentView; + + +} + +-(void)actionChat +{ + PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME]; + [query whereKey:PF_USER_USERNAME equalTo:self.contact.userName]; + [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) + { + if ([objects count] != 0) + { + PFUser *user = [objects firstObject]; + //CreateMessageItem([PFUser currentUser], discoverId, discover[PF_GROUPS_NAME]); + NSString *discoverId = StartPrivateChat([PFUser currentUser], user); + //--------------------------------------------------------------------------------------------------------------------------------------------- + ChatView *chatView = [[ChatView alloc] initWith:discoverId]; + chatView.hidesBottomBarWhenPushed = YES; + [self.navigationController pushViewController:chatView animated:YES]; + } + }]; + + //NSString *discoverId = discover.objectId; + //--------------------------------------------------------------------------------------------------------------------------------------------- + +} + + + +- (void)loadUser +//------------------------------------------------------------------------------------------------------------------------------------------------- +{ + + + // PFUser *user = [PFUser currentUser]; + + + // self.label.text = user[PF_USER_FULLNAME]; + NSLog(@"debug = %@", self.contact.userName); + + PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME]; + [query whereKey:PF_USER_USERNAME equalTo:self.contact.userName]; + [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) + { + if ([objects count] != 0) + { + NSLog(@"debug 2 = %@ objects count = %lu" , self.contact.userName, (unsigned long)[objects count]); + PFUser *user = [objects firstObject]; + //CreateMessageItem([PFUser currentUser], discoverId, discover[PF_GROUPS_NAME]); +// self.imageUser.layer.cornerRadius = self.imageUser.frame.size.width / 2; +// [self.imageUser setFile:user[PF_USER_PICTURE]]; +// [self.imageUser loadInBackground]; + } + }]; + +} + + +@end diff --git a/Classes/Tabs/contactsCell.h b/Classes/Tabs/contactsCell.h new file mode 100644 index 0000000..b4c4f40 --- /dev/null +++ b/Classes/Tabs/contactsCell.h @@ -0,0 +1,13 @@ +// +// contactsCell.h +// app +// +// Created by Daniel Lau on 7/20/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import + +@interface contactsCell : UITableViewCell + +@end diff --git a/Classes/Tabs/contactsCell.m b/Classes/Tabs/contactsCell.m new file mode 100644 index 0000000..8366b45 --- /dev/null +++ b/Classes/Tabs/contactsCell.m @@ -0,0 +1,23 @@ +// +// contactsCell.m +// app +// +// Created by Daniel Lau on 7/20/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import "contactsCell.h" + +@implementation contactsCell + +- (void)awakeFromNib { + // Initialization code +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +@end diff --git a/Classes/Tabs/contactsCell.xib b/Classes/Tabs/contactsCell.xib new file mode 100644 index 0000000..99387cc --- /dev/null +++ b/Classes/Tabs/contactsCell.xib @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/Classes/Tabs/detailsView.h b/Classes/Tabs/detailsView.h new file mode 100644 index 0000000..1236080 --- /dev/null +++ b/Classes/Tabs/detailsView.h @@ -0,0 +1,17 @@ +// +// detailsView.h +// app +// +// Created by kiddjacky on 4/28/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import +#import +#import "DiscoverUser.h" + +@interface detailsView : UIViewController +@property (strong, nonatomic) NSManagedObjectContext *context; +@property (strong, nonatomic) CLLocation *location; +@property (strong, nonatomic) DiscoverUser *discoverUser; +@end diff --git a/Classes/Tabs/detailsView.m b/Classes/Tabs/detailsView.m new file mode 100644 index 0000000..10db664 --- /dev/null +++ b/Classes/Tabs/detailsView.m @@ -0,0 +1,449 @@ +// +// detailsView.m +// app +// +// Created by kiddjacky on 4/28/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import "detailsView.h" +#import +#import "DiscoverUser.h" + +#import + +#import +#import + +#import "ProgressHUD.h" + +#import "AppConstant.h" +#import "messages.h" +#import "utilities.h" + +#import "ChatView.h" +#import "Contacts.h" +#import "CurrentUser.h" +#import "DatabaseAvailability.h" + +@interface detailsView () +@property MKMapView *mapView; +@property UIView *mapContainerView; +@property UIView *pokeContainerView; +@property UIView *chatContainerView; +@property UIView *imageContainerView; +@property UIView *labelContainerView; +@property UIButton *poke; +@property UIButton *chat; +@property PFImageView *imageUser; +@property UILabel *label; + +@end + + +@implementation detailsView + +@synthesize location; + +-(void)viewDidLoad { + [super viewDidLoad]; + self.imageUser = [[PFImageView alloc] init]; + [self loadView]; + [self loadUser]; + + + + NSLog(@"corner radius = %f", self.imageUser.frame.size.width / 2); +// self.imageUser.layer.cornerRadius = 10; + self.imageUser.layer.masksToBounds = YES; +// [self.imageUser setBackgroundColor:[UIColor grayColor]]; + self.imageUser.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + self.imageContainerView = [[UIView alloc] initWithFrame:CGRectZero]; + self.imageContainerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.imageContainerView addSubview:self.imageUser]; + [self.view addSubview:self.imageContainerView]; + + self.label = [[UILabel alloc] init]; + // [self.label setBackgroundColor:[UIColor redColor]]; + self.label.text = self.discoverUser.userName; + [self.label setFont:[UIFont fontWithName:@"System" size:30]]; + NSLog(@"text label = %@", self.label.text); + self.label.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + self.labelContainerView = [[UIView alloc] initWithFrame:CGRectZero]; + self.labelContainerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.labelContainerView addSubview:self.label]; + [self.view addSubview:self.labelContainerView]; + + + //self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext; + + _poke = [UIButton buttonWithType:UIButtonTypeCustom]; + self.poke.layer.cornerRadius = 10; + self.poke.clipsToBounds = YES; + [self.poke setTitle:@"Add" forState:UIControlStateNormal]; + [self.poke setBackgroundColor:[UIColor blueColor]]; + + self.poke.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + + _chat = [UIButton buttonWithType:UIButtonTypeCustom]; + self.chat.layer.cornerRadius = 10; + self.chat.clipsToBounds = YES; + [self.chat setTitle:@"Chat" forState:UIControlStateNormal]; + [self.chat setBackgroundColor:[UIColor blueColor]]; + self.chat.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + + self.chatContainerView = [[UIView alloc] initWithFrame:CGRectZero]; + self.chatContainerView.translatesAutoresizingMaskIntoConstraints = NO; + self.pokeContainerView = [[UIView alloc] initWithFrame:CGRectZero]; + self.pokeContainerView.translatesAutoresizingMaskIntoConstraints = NO; + + [self.chatContainerView addSubview:self.chat]; + [self.pokeContainerView addSubview:self.poke]; + + [self.view addSubview:self.chatContainerView]; + [self.view addSubview:self.pokeContainerView]; + + + + self.mapContainerView = [[UIView alloc] initWithFrame:CGRectZero]; + self.mapContainerView.translatesAutoresizingMaskIntoConstraints = NO; + + _mapView = [[MKMapView alloc] initWithFrame:self.mapContainerView.frame]; + //self.mapView.delegate = self; + self.mapView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + [self.mapContainerView addSubview:self.mapView]; + + MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.location.coordinate, 1000, 1000); + [self.mapView setRegion:region animated:NO]; + MKPointAnnotation *pa = [[MKPointAnnotation alloc] init]; + pa.coordinate = location.coordinate; + [self.mapView addAnnotation:pa]; + //self.mapView.layer.cornerRadius = 5; + //self.mapView.layer.masksToBounds = YES; + + [self.view addSubview:self.mapContainerView]; + + // Width constraint, half of parent view width + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.mapContainerView + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeWidth + multiplier:0.5 + constant:0]]; + + // Height constraint, half of parent view height + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.mapContainerView + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeHeight + multiplier:0.5 + constant:0]]; + + // Center horizontally + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.mapContainerView + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0.0]]; + /* + // Center vertically + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.mapContainerView + attribute:NSLayoutAttributeCenterY + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeCenterY + multiplier:1.0 + constant:0.0]]; + */ + + NSDictionary *viewsDictionary = @{@"mapView":self.mapContainerView, @"poke_view":self.pokeContainerView, @"chat_view":self.chatContainerView, @"imageView":self.imageContainerView, @"labelView":self.labelContainerView}; + + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.imageContainerView + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeHeight + multiplier:0.2 + constant:0.0]]; + + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.imageContainerView + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeWidth + multiplier:0.2 + constant:0.0]]; + + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.labelContainerView + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeHeight + multiplier:0.1 + constant:0.0]]; + + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.labelContainerView + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeWidth + multiplier:0.6 + constant:0.0]]; + + + NSArray *constraint_POS_V_image = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[imageView]" + options:0 + metrics:nil + views:viewsDictionary]; + + NSArray *constraint_POS_H_image = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[imageView]" + options:0 + metrics:nil + views:viewsDictionary]; + + NSArray *constraint_POS_V_label = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[labelView]" + options:0 + metrics:nil + views:viewsDictionary]; + + NSArray *constraint_POS_H_label = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[imageView]-10-[labelView]" + options:0 + metrics:nil + views:viewsDictionary]; + + + NSArray *constraint_POS_V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[mapView]-100-|" + options:0 + metrics:nil + views:viewsDictionary]; + + NSArray *constraint_POS_V_button1 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[mapView]-20-[poke_view]" + options:0 + metrics:nil + views:viewsDictionary]; + + NSArray *constraint_POS_V_button2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[mapView]-20-[chat_view]" + options:0 + metrics:nil + views:viewsDictionary]; + + NSArray *constraint_POS_H_button1 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[poke_view]" + options:0 + metrics:nil + views:viewsDictionary]; + + NSArray *constraint_POS_H_button2 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[poke_view]-20-[chat_view]" + options:0 + metrics:nil + views:viewsDictionary]; + NSArray *constraint_POS_H_button3 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[chat_view]-20-|" + options:0 + metrics:nil + views:viewsDictionary]; + + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.pokeContainerView + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeHeight + multiplier:0.1 + constant:0.0]]; + + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.chatContainerView + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeHeight + multiplier:0.1 + constant:0.0]]; + + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.chatContainerView + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:self.pokeContainerView + attribute:NSLayoutAttributeWidth + multiplier:1.0 + constant:0.0]]; + /* + NSArray *constraint_POS_H = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[mapView]-10-|" + options:0 + metrics:nil + views:viewsDictionary]; + */ + //[self.view addConstraints:constraint_POS_H]; + [self.view addConstraints:constraint_POS_V]; + [self.view addConstraints:constraint_POS_V_image]; + [self.view addConstraints:constraint_POS_H_image]; + [self.view addConstraints:constraint_POS_V_label]; + [self.view addConstraints:constraint_POS_H_label]; + [self.view addConstraints:constraint_POS_H_button1]; + [self.view addConstraints:constraint_POS_H_button2]; + [self.view addConstraints:constraint_POS_H_button3]; + [self.view addConstraints:constraint_POS_V_button1]; + [self.view addConstraints:constraint_POS_V_button2]; + + [self.chat addTarget:self action:@selector(actionChat) forControlEvents:UIControlEventTouchUpInside]; + [self.poke addTarget:self action:@selector(actionAdd) forControlEvents:UIControlEventTouchUpInside]; + +} + +-(void)loadView +{ + CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame]; + UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame]; + contentView.backgroundColor = [UIColor whiteColor]; + self.view = contentView; + + +} + +-(void)actionAdd { + PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME]; + NSLog(@"discover user to be added is %@",self.discoverUser.userName); + [query whereKey:PF_USER_USERNAME equalTo:self.discoverUser.userName]; + [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) + { + if ([objects count] != 0) + { + NSLog(@"add discover user as contact!"); + PFUser *user = [objects firstObject]; + NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Contacts"]; + request.predicate = [NSPredicate predicateWithFormat:@"userName = %@", user[PF_USER_USERNAME]]; + NSError *error; + NSArray *matches = [self.context executeFetchRequest:request error:&error]; + Contacts *contact = nil; + //CurrentUser *currentUser = nil; + + if (error) { + NSLog(@"request error!"); + } + else if ([matches count]>=1) { + //they are already friend? + NSLog(@"is this user in the contact list?"); + contact = [matches firstObject]; + NSLog(@"the name of contact is %@", user.username); + + } + else { + + contact = [NSEntityDescription insertNewObjectForEntityForName:@"Contacts" + inManagedObjectContext:self.context]; + contact.userName = user.username; + contact.userFullName = user[PF_USER_FULLNAME]; + contact.sex = user[PF_USER_SEX]; + contact.age = user[PF_USER_AGE]; + contact.interest = user[PF_USER_INTEREST]; + contact.selfDescription = user[PF_USER_SELF_DESCRIPTION]; + //contact.thumbnail = user[PF_USER_THUMBNAIL]; + PFFile *contactThumbnail = user[PF_USER_THUMBNAIL]; + [contactThumbnail getDataInBackgroundWithBlock:^(NSData *data, NSError *error) { + + if(!error) { + contact.thumbnail = data; + [self save_and_post]; + } + }]; + + [self save_and_post]; + + + + //add contact to current user contact list + PFUser *user = [PFUser currentUser]; + NSLog(@"original contact list is %@", user[PF_USER_CONTACTS]); + NSMutableArray *contactList = [[NSMutableArray alloc] init]; + [contactList addObject:contact.userName]; + [contactList addObjectsFromArray:user[PF_USER_CONTACTS]]; + NSLog(@"now contact list is %@", contactList); + user[PF_USER_CONTACTS] = contactList; + [user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) + { + if (error == nil) + { + [ProgressHUD showSuccess:@"Add Contact!"]; + } + else [ProgressHUD showError:@"Network error."]; + }]; + } + + } + }]; + +} + +-(void) save_and_post +{ + NSError *error=nil; + + + + if (![self.context save:&error]) { + NSLog(@"Couldn't save %@", [error localizedDescription]); + } + + NSLog(@"Added!"); + //setup notification to other view controller that the context is avaiable. + NSDictionary *userInfo = self.context ? @{DatabaseAvailabilityContext : self.context } : nil; + [[NSNotificationCenter defaultCenter] postNotificationName:DatabaseAvailabilityNotification object:self userInfo:userInfo]; +} + +-(void)actionChat +{ + PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME]; + [query whereKey:PF_USER_USERNAME equalTo:self.discoverUser.userName]; + [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) + { + if ([objects count] != 0) + { + PFUser *user = [objects firstObject]; + //CreateMessageItem([PFUser currentUser], discoverId, discover[PF_GROUPS_NAME]); + NSString *discoverId = StartPrivateChat([PFUser currentUser], user); + //--------------------------------------------------------------------------------------------------------------------------------------------- + ChatView *chatView = [[ChatView alloc] initWith:discoverId]; + chatView.hidesBottomBarWhenPushed = YES; + [self.navigationController pushViewController:chatView animated:YES]; + } + }]; + + //NSString *discoverId = discover.objectId; + //--------------------------------------------------------------------------------------------------------------------------------------------- + +} + + + +- (void)loadUser +//------------------------------------------------------------------------------------------------------------------------------------------------- +{ + + + // PFUser *user = [PFUser currentUser]; + + + // self.label.text = user[PF_USER_FULLNAME]; + NSLog(@"debug = %@", self.discoverUser.userName); + + + PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME]; + [query whereKey:PF_USER_USERNAME equalTo:self.discoverUser.userName]; + [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) + { + if ([objects count] != 0) + { + NSLog(@"debug 2 = %@ objects count = %lu" , self.discoverUser.userName, (unsigned long)[objects count]); + PFUser *user = [objects firstObject]; + //CreateMessageItem([PFUser currentUser], discoverId, discover[PF_GROUPS_NAME]); + self.imageUser.layer.cornerRadius = self.imageUser.frame.size.width / 2; + [self.imageUser setFile:user[PF_USER_PICTURE]]; + [self.imageUser loadInBackground]; + } + }]; + +} + + +@end diff --git a/Classes/Tabs/discoversCell.h b/Classes/Tabs/discoversCell.h new file mode 100644 index 0000000..0021100 --- /dev/null +++ b/Classes/Tabs/discoversCell.h @@ -0,0 +1,19 @@ +// +// discoversCell.h +// app +// +// Created by Daniel Lau on 6/27/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import +#import + +@interface discoversCell : UITableViewCell + +- (void)bindData:(PFObject *)discovered_users_; +@property (nonatomic, weak) IBOutlet UIImageView *imageUser; +@property (nonatomic, weak) IBOutlet UILabel *userFullName; +@property (nonatomic, weak) IBOutlet UILabel *localDateTime; + +@end diff --git a/Classes/Tabs/discoversCell.m b/Classes/Tabs/discoversCell.m new file mode 100644 index 0000000..e966036 --- /dev/null +++ b/Classes/Tabs/discoversCell.m @@ -0,0 +1,68 @@ +// +// discoversCell.m +// app +// +// Created by Daniel Lau on 6/27/15. +// Copyright (c) 2015 KZ. All rights reserved. +// +#import +#import + +#import "AppConstant.h" +#import "utilities.h" + + +#import "discoversCell.h" + +@interface discoversCell() +{ + PFObject *discovered_users; +} +/* +@property (strong, nonatomic) IBOutlet UIImageView *imageUser; +@property (strong, nonatomic) IBOutlet UILabel *userFullName; +@property (strong, nonatomic) IBOutlet UILabel *localDateTime; +*/ +@end + +@implementation discoversCell + +@synthesize imageUser = _imageUser; +@synthesize userFullName = _userFullName; +@synthesize localDateTime = _localDateTime; + + +- (void)awakeFromNib { + // Initialization code + // _userFullName.text = @"test1"; + // _localDateTime.text = @"test2"; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +- (void)bindData:(PFObject *)discovered_users_ +//------------------------------------------------------------------------------------------------------------------------------------------------- +{ + /* + discovered_users = discovered_users_; + + imageUser.layer.cornerRadius = imageUser.frame.size.width/2; + imageUser.layer.masksToBounds = YES; + //--------------------------------------------------------------------------------------------------------------------------------------------- + + PFUser *lastUser = discovered_users[PF_MESSAGES_LASTUSER]; + [imageUser setFile:lastUser[PF_USER_PICTURE]]; + [imageUser loadInBackground]; + + userFullName.text = @"test"; + localDateTime.text = @"test"; + */ + +} + + +@end diff --git a/Classes/Tabs/discoversCell.xib b/Classes/Tabs/discoversCell.xib new file mode 100644 index 0000000..6cf6510 --- /dev/null +++ b/Classes/Tabs/discoversCell.xib @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/Tabs/test.h b/Classes/Tabs/test.h deleted file mode 100644 index e063b25..0000000 --- a/Classes/Tabs/test.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// test.h -// app -// -// Created by kiddjacky on 4/18/15. -// Copyright (c) 2015 KZ. All rights reserved. -// - -#import - -@interface test : UITableViewController - -@end diff --git a/Classes/Tabs/test.m b/Classes/Tabs/test.m deleted file mode 100644 index 50bba31..0000000 --- a/Classes/Tabs/test.m +++ /dev/null @@ -1,530 +0,0 @@ -// -// test.m -// app -// -// Created by kiddjacky on 4/18/15. -// Copyright (c) 2015 KZ. All rights reserved. -// - -#import "test.h" - -#import -#import "TransferService.h" -#import -#import "ProgressHUD.h" - -#import "AppConstant.h" -#import "messages.h" -#import "utilities.h" - -#import "GroupsView.h" -#import "ChatView.h" -#import -#import "TransferService.h" - -@interface test() -@property (strong, nonatomic) IBOutlet UITextView *textView; -@property (strong, nonatomic) IBOutlet UISwitch *advertisingSwitch; -@property (strong, nonatomic) CBPeripheralManager *peripheralManager; -@property (strong, nonatomic) CBMutableCharacteristic *transferCharacteristic; -@property (strong, nonatomic) NSData *dataToSend; -@property (nonatomic, readwrite) NSInteger sendDataIndex; -////////////Central Manager -@property (strong, nonatomic) CBCentralManager *centralManager; -@property (strong, nonatomic) CBPeripheral *discoveredPeripheral; -@property (strong, nonatomic) NSMutableData *data; -@property (strong, nonatomic) IBOutlet UITextView *central_textview; - -@property (retain) NSTimer *switchTimer; - -@end - - -#define NOTIFY_MTU 20 - - -//------------------------------------------------------------------------------------------------------------------------------------------------- -@interface test() -{ - NSMutableArray *discovers; -} -@end -//------------------------------------------------------------------------------------------------------------------------------------------------- - -@implementation test - -//------------------------------------------------------------------------------------------------------------------------------------------------- -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil -//------------------------------------------------------------------------------------------------------------------------------------------------- -{ - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - if (self) - { - [self.tabBarItem setImage:[UIImage imageNamed:@"tab_discover"]]; - self.tabBarItem.title = @"Discovers"; - } - return self; -} - -//------------------------------------------------------------------------------------------------------------------------------------------------- -- (void)viewDidLoad -//------------------------------------------------------------------------------------------------------------------------------------------------- -{ - [super viewDidLoad]; - self.title = @"Groups"; - //--------------------------------------------------------------------------------------------------------------------------------------------- - /*self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"New" style:UIBarButtonItemStylePlain target:self - action:@selector(actionNew)];*/ - //--------------------------------------------------------------------------------------------------------------------------------------------- - self.tableView.tableFooterView = [[UIView alloc] init]; - - //--------------------------------------------------------------------------------------------------------------------------------------------- - discovers = [[NSMutableArray alloc] init]; - - // Start up the CBPeripheralManager - _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil]; - - - // Start up the CBCentralManager - _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; - - // And somewhere to store the incoming data - _data = [[NSMutableData alloc] init]; -} - -//------------------------------------------------------------------------------------------------------------------------------------------------- -- (void)viewDidAppear:(BOOL)animated -//------------------------------------------------------------------------------------------------------------------------------------------------- -{ - [super viewDidAppear:animated]; - //--------------------------------------------------------------------------------------------------------------------------------------------- - if ([PFUser currentUser] != nil) - { - //[self loadGroups]; - } - else LoginUser(self); -} - -- (void)btle_seq -{ - [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }]; - - self.switchTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(btle_switch_mode:) userInfo:nil repeats:YES]; - - -} - -#pragma mark - Central Methods - - - -/** centralManagerDidUpdateState is a required protocol method. - * Usually, you'd check for other states to make sure the current device supports LE, is powered on, etc. - * In this instance, we're just using it to wait for CBCentralManagerStatePoweredOn, which indicates - * the Central is ready to be used. - */ -- (void)centralManagerDidUpdateState:(CBCentralManager *)central -{ - if (central.state != CBCentralManagerStatePoweredOn) { - // In a real app, you'd deal with all the states correctly - return; - } - - // The state must be CBCentralManagerStatePoweredOn... - - // ... so start scanning - [self scan]; - -} - - -/** Scan for peripherals - specifically for our service's 128bit CBUUID - */ -- (void)scan -{ - [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] - options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }]; - - NSLog(@"Scanning started"); -} - - -/** This callback comes whenever a peripheral that is advertising the TRANSFER_SERVICE_UUID is discovered. - * We check the RSSI, to make sure it's close enough that we're interested in it, and if it is, - * we start the connection process - */ -- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI -{ - // Reject any where the value is above reasonable range - if (RSSI.integerValue > -15) { - return; - } - - // Reject if the signal strength is too low to be close enough (Close is around -22dB) - if (RSSI.integerValue < -35) { - return; - } - - NSLog(@"Discovered %@ at %@", peripheral.name, RSSI); - - // Ok, it's in range - have we already seen it? - if (self.discoveredPeripheral != peripheral) { - - // Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it - self.discoveredPeripheral = peripheral; - - // And connect - NSLog(@"Connecting to peripheral %@", peripheral); - [self.centralManager connectPeripheral:peripheral options:nil]; - } -} - - -/** If the connection fails for whatever reason, we need to deal with it. - */ -- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error -{ - NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]); - [self cleanup]; -} - - -/** We've connected to the peripheral, now we need to discover the services and characteristics to find the 'transfer' characteristic. - */ -- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral -{ - NSLog(@"Peripheral Connected"); - - // Stop scanning - [self.centralManager stopScan]; - NSLog(@"Scanning stopped"); - - // Clear the data that we may already have - [self.data setLength:0]; - - // Make sure we get the discovery callbacks - peripheral.delegate = self; - - // Search only for services that match our UUID - [peripheral discoverServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]]; -} - - -/** The Transfer Service was discovered - */ -- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error -{ - if (error) { - NSLog(@"Error discovering services: %@", [error localizedDescription]); - [self cleanup]; - return; - } - - // Discover the characteristic we want... - - // Loop through the newly filled peripheral.services array, just in case there's more than one. - for (CBService *service in peripheral.services) { - [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]] forService:service]; - } -} - - -/** The Transfer characteristic was discovered. - * Once this has been found, we want to subscribe to it, which lets the peripheral know we want the data it contains - */ -- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error -{ - // Deal with errors (if any) - if (error) { - NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); - [self cleanup]; - return; - } - - // Again, we loop through the array, just in case. - for (CBCharacteristic *characteristic in service.characteristics) { - - // And check if it's the right one - if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { - - // If it is, subscribe to it - [peripheral setNotifyValue:YES forCharacteristic:characteristic]; - } - } - - // Once this is complete, we just need to wait for the data to come in. -} - - -/** This callback lets us know more data has arrived via notification on the characteristic - */ -- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error -{ - if (error) { - NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); - return; - } - - NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]; - - // Have we got everything we need? - if ([stringFromData isEqualToString:@"EOM"]) { - - // We have, so show the data, - [self.central_textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]]; - - // Cancel our subscription to the characteristic - [peripheral setNotifyValue:NO forCharacteristic:characteristic]; - - // and disconnect from the peripehral - [self.centralManager cancelPeripheralConnection:peripheral]; - } - - // Otherwise, just add the data on to what we already have - [self.data appendData:characteristic.value]; - - // Log it - NSLog(@"Received: %@", stringFromData); -} - - -/** The peripheral letting us know whether our subscribe/unsubscribe happened or not - */ -- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error -{ - if (error) { - NSLog(@"Error changing notification state: %@", error.localizedDescription); - } - - // Exit if it's not the transfer characteristic - if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { - return; - } - - // Notification has started - if (characteristic.isNotifying) { - NSLog(@"Notification began on %@", characteristic); - } - - // Notification has stopped - else { - // so disconnect from the peripheral - NSLog(@"Notification stopped on %@. Disconnecting", characteristic); - [self.centralManager cancelPeripheralConnection:peripheral]; - } -} - - -/** Once the disconnection happens, we need to clean up our local copy of the peripheral - */ -- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error -{ - NSLog(@"Peripheral Disconnected"); - self.discoveredPeripheral = nil; - - // We're disconnected, so start scanning again - [self scan]; -} - - -/** Call this when things either go wrong, or you're done with the connection. - * This cancels any subscriptions if there are any, or straight disconnects if not. - * (didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved) - */ -- (void)cleanup -{ - // Don't do anything if we're not connected - if (!self.discoveredPeripheral.isConnected) { - return; - } - - // See if we are subscribed to a characteristic on the peripheral - if (self.discoveredPeripheral.services != nil) { - for (CBService *service in self.discoveredPeripheral.services) { - if (service.characteristics != nil) { - for (CBCharacteristic *characteristic in service.characteristics) { - if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { - if (characteristic.isNotifying) { - // It is notifying, so unsubscribe - [self.discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic]; - - // And we're done. - return; - } - } - } - } - } - } - - // If we've got this far, we're connected, but we're not subscribed, so we just disconnect - [self.centralManager cancelPeripheralConnection:self.discoveredPeripheral]; -} - - - - -#pragma mark - Peripheral Methods - - - -/** Required protocol method. A full app should take care of all the possible states, - * but we're just waiting for to know when the CBPeripheralManager is ready - */ -- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral -{ - // Opt out from any other state - if (peripheral.state != CBPeripheralManagerStatePoweredOn) { - return; - } - - // We're in CBPeripheralManagerStatePoweredOn state... - NSLog(@"self.peripheralManager powered on."); - - // ... so build our service. - - // Start with the CBMutableCharacteristic - self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID] - properties:CBCharacteristicPropertyNotify - value:nil - permissions:CBAttributePermissionsReadable]; - - // Then the service - CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] - primary:YES]; - - // Add the characteristic to the service - transferService.characteristics = @[self.transferCharacteristic]; - - // And add it to the peripheral manager - [self.peripheralManager addService:transferService]; -} - - -/** Catch when someone subscribes to our characteristic, then start sending them data - */ -- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic -{ - NSLog(@"Central subscribed to characteristic"); - - // Get the data - self.dataToSend = [self.textView.text dataUsingEncoding:NSUTF8StringEncoding]; - - // Reset the index - self.sendDataIndex = 0; - - // Start sending - [self sendData]; -} - - -/** Recognise when the central unsubscribes - */ -- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic -{ - NSLog(@"Central unsubscribed from characteristic"); -} - - -/** Sends the next amount of data to the connected central - */ -- (void)sendData -{ - // First up, check if we're meant to be sending an EOM - static BOOL sendingEOM = NO; - - if (sendingEOM) { - - // send it - BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; - - // Did it send? - if (didSend) { - - // It did, so mark it as sent - sendingEOM = NO; - - NSLog(@"Sent: EOM"); - } - - // It didn't send, so we'll exit and wait for peripheralManagerIsReadyToUpdateSubscribers to call sendData again - return; - } - - // We're not sending an EOM, so we're sending data - - // Is there any left to send? - - if (self.sendDataIndex >= self.dataToSend.length) { - - // No data left. Do nothing - return; - } - - // There's data left, so send until the callback fails, or we're done. - - BOOL didSend = YES; - - while (didSend) { - - // Make the next chunk - - // Work out how big it should be - NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex; - - // Can't be longer than 20 bytes - if (amountToSend > NOTIFY_MTU) amountToSend = NOTIFY_MTU; - - // Copy out the data we want - NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend]; - - // Send it - didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; - - // If it didn't work, drop out and wait for the callback - if (!didSend) { - return; - } - - NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding]; - NSLog(@"Sent: %@", stringFromData); - - // It did send, so update our index - self.sendDataIndex += amountToSend; - - // Was it the last one? - if (self.sendDataIndex >= self.dataToSend.length) { - - // It was - send an EOM - - // Set this so if the send fails, we'll send it next time - sendingEOM = YES; - - // Send it - BOOL eomSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; - - if (eomSent) { - // It sent, we're all done - sendingEOM = NO; - - NSLog(@"Sent: EOM"); - } - - return; - } - } -} - - -/** This callback comes in when the PeripheralManager is ready to send the next chunk of data. - * This is to ensure that packets will arrive in the order they are sent - */ -- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral -{ - // Start sending again - [self sendData]; -} - - -@end - diff --git a/Classes/User/LoginView.h b/Classes/User/LoginView.h index 8127f9e..f10c5bc 100755 --- a/Classes/User/LoginView.h +++ b/Classes/User/LoginView.h @@ -14,5 +14,5 @@ //------------------------------------------------------------------------------------------------------------------------------------------------- @interface LoginView : UITableViewController //------------------------------------------------------------------------------------------------------------------------------------------------- - +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; @end diff --git a/Classes/User/LoginView.m b/Classes/User/LoginView.m index 3814bda..c1b7395 100755 --- a/Classes/User/LoginView.m +++ b/Classes/User/LoginView.m @@ -16,6 +16,13 @@ #import "pushnotification.h" #import "LoginView.h" +#import "DataBaseAvailability.h" +#import "utilities.h" +#import "AppDelegate.h" +#import "DiscoverUser.h" +#import "CurrentUser.h" +#import "Contacts.h" + //------------------------------------------------------------------------------------------------------------------------------------------------- @interface LoginView() @@ -35,6 +42,22 @@ @implementation LoginView @synthesize cellEmail, cellPassword, cellButton; @synthesize fieldEmail, fieldPassword; +//------------------------------------------------------------------------------------------------------------------------------------------------- +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +//------------------------------------------------------------------------------------------------------------------------------------------------- +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + + + return self; +} + +- (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext +{ + _managedObjectContext = managedObjectContext; + +} + //------------------------------------------------------------------------------------------------------------------------------------------------- - (void)viewDidLoad //------------------------------------------------------------------------------------------------------------------------------------------------- @@ -79,6 +102,14 @@ - (IBAction)actionLogin:(id)sender { ParsePushUserAssign(); [ProgressHUD showSuccess:[NSString stringWithFormat:@"Welcome back %@!", user[PF_USER_FULLNAME]]]; + AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; + self.managedObjectContext = appDelegate.DiscoverDatabaseContext; + [self loadUserDatabase]; + //post notification + //setup notification to other view controller that the context is avaiable. + NSDictionary *userInfo = self.managedObjectContext ? @{DatabaseAvailabilityContext : self.managedObjectContext } : nil; + [[NSNotificationCenter defaultCenter] postNotificationName:DatabaseAvailabilityNotification object:self userInfo:userInfo]; + [self dismissViewControllerAnimated:YES completion:nil]; } else [ProgressHUD showError:error.userInfo[@"error"]]; @@ -128,4 +159,95 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField return YES; } +-(void) loadUserDatabase +{ + NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"CurrentUser"]; + request.predicate = nil; + NSError *error; + NSArray *matches = [self.managedObjectContext executeFetchRequest:request error:&error]; + + //delete all existing database + //[request release]; + for(NSManagedObject *user in matches) { + [self.managedObjectContext deleteObject:user]; + } + + NSFetchRequest *dis_request = [NSFetchRequest fetchRequestWithEntityName:@"DiscoverUser"]; + request.predicate = nil; + NSError *dis_error; + NSArray *dis_matches = [self.managedObjectContext executeFetchRequest:dis_request error:&dis_error]; + + //[request release]; + for(NSManagedObject *user in dis_matches) { + [self.managedObjectContext deleteObject:user]; + } + + NSFetchRequest *con_request = [NSFetchRequest fetchRequestWithEntityName:@"Contacts"]; + request.predicate = nil; + NSError *con_error; + NSArray *con_matches = [self.managedObjectContext executeFetchRequest:con_request error:&con_error]; + + //[request release]; + for(NSManagedObject *user in con_matches) { + [self.managedObjectContext deleteObject:user]; + } + + NSError *saveError = nil; + [self.managedObjectContext save:&saveError]; + + //load new database + CurrentUser *current_user = nil; + NSLog(@"setup the current user after login"); + PFUser *user = [PFUser currentUser]; + NSLog(@"setup setp1 load currentUser %@", user.username); + current_user = [NSEntityDescription + insertNewObjectForEntityForName:@"CurrentUser" + inManagedObjectContext:self.managedObjectContext]; + current_user.userName = user[PF_USER_USERNAME]; + current_user.userFullName = user[PF_USER_FULLNAME]; + current_user.sex = user[PF_USER_SEX]; + current_user.birthday = user[PF_USER_BIRTHDAY]; + current_user.interest = user[PF_USER_INTEREST]; + current_user.selfDescription = user[PF_USER_SELF_DESCRIPTION]; + current_user.thumbnail = user[PF_USER_THUMBNAIL]; + //current_user.contactList = user[PF_USER_CONTACTS]; + + //NSLog(@"user name is %@, contact list is %@", current_user.userName, current_user.contactList); + + //load contacts + for (NSString * contact_name in user[PF_USER_CONTACTS]) { + NSLog(@"setup the contact %@", contact_name); + PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME]; + [query whereKey:PF_USER_USERNAME equalTo:contact_name]; + [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) + { + if ([objects count] != 0) + { + PFUser *user = [objects firstObject]; + Contacts *contact = [NSEntityDescription + insertNewObjectForEntityForName:@"Contacts" + inManagedObjectContext:self.managedObjectContext]; + contact.userName = user.username; + contact.userFullName = user[PF_USER_FULLNAME]; + contact.sex = user[PF_USER_SEX]; + contact.age = user[PF_USER_AGE]; + contact.interest = user[PF_USER_INTEREST]; + contact.selfDescription = user[PF_USER_SELF_DESCRIPTION]; + contact.thumbnail = user[PF_USER_THUMBNAIL]; + + } + }]; + + } + //load discovers + //loadDiscover function + + //SAVE CONTEXT + NSError *contactSaveError = nil; + [self.managedObjectContext save:&contactSaveError]; + + +} + + @end diff --git a/Classes/User/RegisterView.m b/Classes/User/RegisterView.m index b7e617a..203c389 100755 --- a/Classes/User/RegisterView.m +++ b/Classes/User/RegisterView.m @@ -16,6 +16,12 @@ #import "pushnotification.h" #import "RegisterView.h" +#import "DatabaseAvailability.h" +#import "utilities.h" +#import "AppDelegate.h" +#import "DiscoverUser.h" +#import "CurrentUser.h" +#import "Contacts.h" //------------------------------------------------------------------------------------------------------------------------------------------------- @interface RegisterView() @@ -91,6 +97,13 @@ - (IBAction)actionRegister:(id)sender { ParsePushUserAssign(); [ProgressHUD showSuccess:@"Succeed."]; + NSManagedObjectContext *context=((AppDelegate *) [UIApplication sharedApplication].delegate).DiscoverDatabaseContext; + [self loadUserDatabase:user.username fromContext:context]; + //post notification + //setup notification to other view controller that the context is avaiable. + NSDictionary *userInfo = context ? @{DatabaseAvailabilityContext : context } : nil; + [[NSNotificationCenter defaultCenter] postNotificationName:DatabaseAvailabilityNotification object:self userInfo:userInfo]; + [self dismissViewControllerAnimated:YES completion:nil]; } else [ProgressHUD showError:error.userInfo[@"error"]]; @@ -145,4 +158,71 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField return YES; } +-(void) loadUserDatabase:(NSString *)userName fromContext:(NSManagedObjectContext *)context +{ + NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"CurrentUser"]; + request.predicate = nil; + NSError *error; + NSArray *matches = [context executeFetchRequest:request error:&error]; + + //delete all existing database + //[request release]; + for(NSManagedObject *user in matches) { + [context deleteObject:user]; + } + + NSFetchRequest *dis_request = [NSFetchRequest fetchRequestWithEntityName:@"DiscoverUser"]; + request.predicate = nil; + NSError *dis_error; + NSArray *dis_matches = [context executeFetchRequest:dis_request error:&dis_error]; + + //[request release]; + for(NSManagedObject *user in dis_matches) { + [context deleteObject:user]; + } + + NSFetchRequest *con_request = [NSFetchRequest fetchRequestWithEntityName:@"Contacts"]; + request.predicate = nil; + NSError *con_error; + NSArray *con_matches = [context executeFetchRequest:con_request error:&con_error]; + + //[request release]; + for(NSManagedObject *user in con_matches) { + [context deleteObject:user]; + } + + NSError *saveError = nil; + [context save:&saveError]; + + //load new database + PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME]; + [query whereKey:PF_USER_USERNAME equalTo:userName]; + [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) + { + if ([objects count] != 0) + { + NSLog(@"setup the current user after register"); + PFUser *user = [objects firstObject]; + CurrentUser *current_user = [NSEntityDescription + insertNewObjectForEntityForName:@"CurrentUser" + inManagedObjectContext:context]; + current_user.userName = user.username; + current_user.userFullName = user[PF_USER_FULLNAME]; + current_user.sex = user[PF_USER_SEX]; + current_user.birthday = user[PF_USER_BIRTHDAY]; + current_user.interest = user[PF_USER_INTEREST]; + current_user.selfDescription = user[PF_USER_SELF_DESCRIPTION]; + current_user.thumbnail = user[PF_USER_THUMBNAIL]; + current_user.contactList = user[PF_USER_CONTACTS]; + + + //SAVE CONTEXT + NSError *contactSaveError = nil; + [context save:&contactSaveError]; + + + } + }]; +} + @end diff --git a/Classes/User/RegisterView.xib b/Classes/User/RegisterView.xib index 8527525..b6e05bd 100755 --- a/Classes/User/RegisterView.xib +++ b/Classes/User/RegisterView.xib @@ -1,6 +1,7 @@ + diff --git a/Classes/Utilities/general/utilities.m b/Classes/Utilities/general/utilities.m index 0dd5053..6e31061 100755 --- a/Classes/Utilities/general/utilities.m +++ b/Classes/Utilities/general/utilities.m @@ -13,6 +13,21 @@ #import "WelcomeView.h" #import "NavigationController.h" + +//for load user +#import + +#import + +#import "ProgressHUD.h" + +#import "AppConstant.h" +#import "DiscoverUser.h" +#import "CurrentUser.h" +#import "Contacts.h" +#import "DatabaseAvailability.h" + + //------------------------------------------------------------------------------------------------------------------------------------------------- void LoginUser(id target) //------------------------------------------------------------------------------------------------------------------------------------------------- @@ -21,6 +36,7 @@ void LoginUser(id target) [target presentViewController:navigationController animated:YES completion:nil]; } + //------------------------------------------------------------------------------------------------------------------------------------------------- void PostNotification(NSString *notification) //------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Discover.xcdatamodeld/Discover.xcdatamodel/contents b/Discover.xcdatamodeld/Discover.xcdatamodel/contents index c8ac6d6..098ae5b 100644 --- a/Discover.xcdatamodeld/Discover.xcdatamodel/contents +++ b/Discover.xcdatamodeld/Discover.xcdatamodel/contents @@ -1,12 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - + + + \ No newline at end of file diff --git a/Resources/Images/tabbar/contact-icon.png b/Resources/Images/tabbar/contact-icon.png new file mode 100644 index 0000000..eba5e4c Binary files /dev/null and b/Resources/Images/tabbar/contact-icon.png differ diff --git a/Resources/Images/tabbar/tab_discovers.png b/Resources/Images/tabbar/tab_discovers.png index d73ac24..e18cb6d 100644 Binary files a/Resources/Images/tabbar/tab_discovers.png and b/Resources/Images/tabbar/tab_discovers.png differ diff --git a/app.xcodeproj/project.pbxproj b/app.xcodeproj/project.pbxproj index c5468d8..642d24c 100755 --- a/app.xcodeproj/project.pbxproj +++ b/app.xcodeproj/project.pbxproj @@ -125,14 +125,26 @@ 29EB240E19E9292500D7AA97 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 29EB240D19E9292500D7AA97 /* AppDelegate.m */; }; 29EB241619E9292500D7AA97 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 29EB241519E9292500D7AA97 /* Images.xcassets */; }; 29EB241919E9292500D7AA97 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 29EB241719E9292500D7AA97 /* LaunchScreen.xib */; }; - DE1C96E01AE37BB400610AF7 /* DiscoverUser+bluechat.m in Sources */ = {isa = PBXBuildFile; fileRef = DE1C96DF1AE37BB400610AF7 /* DiscoverUser+bluechat.m */; }; - DE1C96E51AE37F7B00610AF7 /* test.m in Sources */ = {isa = PBXBuildFile; fileRef = DE1C96E41AE37F7B00610AF7 /* test.m */; }; + 685AE2511B1DA8F600C8D9E9 /* Whale_preview_180.png in Resources */ = {isa = PBXBuildFile; fileRef = 685AE2501B1DA8F600C8D9E9 /* Whale_preview_180.png */; }; + 685AE2531B1DAB5000C8D9E9 /* Whale_preview_120.png in Resources */ = {isa = PBXBuildFile; fileRef = 685AE2521B1DAB5000C8D9E9 /* Whale_preview_120.png */; }; + 689D00E91B1D9BFD003E21F3 /* contact-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 689D00E81B1D9BFD003E21F3 /* contact-icon.png */; }; + 68E9C3E51B5CDDC700B3B900 /* contactsCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 68E9C3E31B5CDDC700B3B900 /* contactsCell.m */; }; + 68E9C3E61B5CDDC700B3B900 /* contactsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 68E9C3E41B5CDDC700B3B900 /* contactsCell.xib */; }; DE1C96EA1AE73D1100610AF7 /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE1C96E91AE73D1100610AF7 /* CoreBluetooth.framework */; }; - DE4AA4811AC9B4FE008309D0 /* BTLEPeripheralViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DE4AA4801AC9B4FE008309D0 /* BTLEPeripheralViewController.m */; }; + DE31A2DD1AF7152800FD8DE2 /* CoreDataTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DE31A2DC1AF7152800FD8DE2 /* CoreDataTableViewController.m */; }; + DE31A2E31AF7321700FD8DE2 /* AppDelegate+MOC.m in Sources */ = {isa = PBXBuildFile; fileRef = DE31A2E21AF7321700FD8DE2 /* AppDelegate+MOC.m */; }; + DE31A2E61AF7357400FD8DE2 /* DiscoversView+MOC.m in Sources */ = {isa = PBXBuildFile; fileRef = DE31A2E51AF7357400FD8DE2 /* DiscoversView+MOC.m */; }; DE6DA8251ABF54CE007A683B /* DiscoversView.m in Sources */ = {isa = PBXBuildFile; fileRef = DE6DA8241ABF54CE007A683B /* DiscoversView.m */; }; + DEB34C2D1AF0A7DF000A42B8 /* detailsView.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB34C2C1AF0A7DF000A42B8 /* detailsView.m */; }; DEBB7B351AE2FD21009CD940 /* tab_discovers.png in Resources */ = {isa = PBXBuildFile; fileRef = DEBB7B341AE2FD21009CD940 /* tab_discovers.png */; }; DEBB7B481AE3753C009CD940 /* Discover.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DEBB7B461AE3753C009CD940 /* Discover.xcdatamodeld */; }; - DEBB7B4B1AE37599009CD940 /* DiscoverUser.m in Sources */ = {isa = PBXBuildFile; fileRef = DEBB7B4A1AE37599009CD940 /* DiscoverUser.m */; }; + DEBCFF6B1B5E2C5E003A47B2 /* Contacts.m in Sources */ = {isa = PBXBuildFile; fileRef = DEBCFF6A1B5E2C5E003A47B2 /* Contacts.m */; }; + DEBF53C91B4CDA0D00891128 /* DiscoverUser.m in Sources */ = {isa = PBXBuildFile; fileRef = DEBF53C81B4CDA0D00891128 /* DiscoverUser.m */; }; + DEBF53CD1B4CF9C900891128 /* discoversCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DEBF53CB1B4CF9C900891128 /* discoversCell.m */; }; + DEBF53CE1B4CF9C900891128 /* discoversCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DEBF53CC1B4CF9C900891128 /* discoversCell.xib */; }; + DEE855401B081778000AA5AC /* ContactsView.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE8553F1B081778000AA5AC /* ContactsView.m */; }; + DEE855461B08232E000AA5AC /* contactDetailsVC.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE855451B08232E000AA5AC /* contactDetailsVC.m */; }; + DEE855521B12817C000AA5AC /* CurrentUser.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE855511B12817C000AA5AC /* CurrentUser.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -353,21 +365,42 @@ 29EB241519E9292500D7AA97 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 29EB241819E9292500D7AA97 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 29EB254F19E92ACD00D7AA97 /* AppConstant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppConstant.h; sourceTree = ""; }; - DE1C96DE1AE37BB400610AF7 /* DiscoverUser+bluechat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DiscoverUser+bluechat.h"; sourceTree = ""; }; - DE1C96DF1AE37BB400610AF7 /* DiscoverUser+bluechat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "DiscoverUser+bluechat.m"; sourceTree = ""; }; - DE1C96E31AE37F7B00610AF7 /* test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = test.h; sourceTree = ""; }; - DE1C96E41AE37F7B00610AF7 /* test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = test.m; sourceTree = ""; }; + 685AE2501B1DA8F600C8D9E9 /* Whale_preview_180.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Whale_preview_180.png; path = Images.xcassets/AppIcon.appiconset/Whale_preview_180.png; sourceTree = ""; }; + 685AE2521B1DAB5000C8D9E9 /* Whale_preview_120.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Whale_preview_120.png; path = Images.xcassets/AppIcon.appiconset/Whale_preview_120.png; sourceTree = ""; }; + 689D00E81B1D9BFD003E21F3 /* contact-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "contact-icon.png"; sourceTree = ""; }; + 68E9C3E21B5CDDC700B3B900 /* contactsCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = contactsCell.h; sourceTree = ""; }; + 68E9C3E31B5CDDC700B3B900 /* contactsCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = contactsCell.m; sourceTree = ""; }; + 68E9C3E41B5CDDC700B3B900 /* contactsCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = contactsCell.xib; sourceTree = ""; }; DE1C96E61AE47D7400610AF7 /* app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = app.entitlements; sourceTree = ""; }; DE1C96E91AE73D1100610AF7 /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; }; - DE4AA47F1AC9B4FE008309D0 /* BTLEPeripheralViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BTLEPeripheralViewController.h; sourceTree = ""; }; - DE4AA4801AC9B4FE008309D0 /* BTLEPeripheralViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BTLEPeripheralViewController.m; sourceTree = ""; }; + DE31A2DB1AF7152800FD8DE2 /* CoreDataTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoreDataTableViewController.h; sourceTree = ""; }; + DE31A2DC1AF7152800FD8DE2 /* CoreDataTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoreDataTableViewController.m; sourceTree = ""; }; + DE31A2E11AF7321700FD8DE2 /* AppDelegate+MOC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AppDelegate+MOC.h"; sourceTree = ""; }; + DE31A2E21AF7321700FD8DE2 /* AppDelegate+MOC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AppDelegate+MOC.m"; sourceTree = ""; }; + DE31A2E41AF7357400FD8DE2 /* DiscoversView+MOC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DiscoversView+MOC.h"; sourceTree = ""; }; + DE31A2E51AF7357400FD8DE2 /* DiscoversView+MOC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "DiscoversView+MOC.m"; sourceTree = ""; }; + DE31A2E71AF74D2700FD8DE2 /* PhotoDatabaseAvailability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PhotoDatabaseAvailability.h; sourceTree = ""; }; + DE31A2EA1AF8689100FD8DE2 /* DatabaseAvailability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DatabaseAvailability.h; sourceTree = ""; }; DE4AA4831AC9B582008309D0 /* TransferService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TransferService.h; sourceTree = ""; }; DE6DA8231ABF54CE007A683B /* DiscoversView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoversView.h; sourceTree = ""; }; DE6DA8241ABF54CE007A683B /* DiscoversView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoversView.m; sourceTree = ""; }; + DEB34C2B1AF0A7DF000A42B8 /* detailsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = detailsView.h; sourceTree = ""; }; + DEB34C2C1AF0A7DF000A42B8 /* detailsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = detailsView.m; sourceTree = ""; }; DEBB7B341AE2FD21009CD940 /* tab_discovers.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tab_discovers.png; sourceTree = ""; }; DEBB7B471AE3753C009CD940 /* Discover.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Discover.xcdatamodel; sourceTree = ""; }; - DEBB7B491AE37599009CD940 /* DiscoverUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoverUser.h; sourceTree = ""; }; - DEBB7B4A1AE37599009CD940 /* DiscoverUser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoverUser.m; sourceTree = ""; }; + DEBCFF691B5E2C5E003A47B2 /* Contacts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Contacts.h; path = Classes/Tabs/Contacts.h; sourceTree = ""; }; + DEBCFF6A1B5E2C5E003A47B2 /* Contacts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Contacts.m; path = Classes/Tabs/Contacts.m; sourceTree = ""; }; + DEBF53C71B4CDA0D00891128 /* DiscoverUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoverUser.h; sourceTree = ""; }; + DEBF53C81B4CDA0D00891128 /* DiscoverUser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoverUser.m; sourceTree = ""; }; + DEBF53CA1B4CF9C900891128 /* discoversCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = discoversCell.h; sourceTree = ""; }; + DEBF53CB1B4CF9C900891128 /* discoversCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = discoversCell.m; sourceTree = ""; }; + DEBF53CC1B4CF9C900891128 /* discoversCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = discoversCell.xib; sourceTree = ""; }; + DEE8553E1B081778000AA5AC /* ContactsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsView.h; sourceTree = ""; }; + DEE8553F1B081778000AA5AC /* ContactsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactsView.m; sourceTree = ""; }; + DEE855441B08232E000AA5AC /* contactDetailsVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = contactDetailsVC.h; sourceTree = ""; }; + DEE855451B08232E000AA5AC /* contactDetailsVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = contactDetailsVC.m; sourceTree = ""; }; + DEE855501B12817C000AA5AC /* CurrentUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CurrentUser.h; sourceTree = ""; }; + DEE855511B12817C000AA5AC /* CurrentUser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CurrentUser.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -375,11 +408,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 29A299661A5575BF00117608 /* CoreGraphics.framework in Frameworks */, DE1C96EA1AE73D1100610AF7 /* CoreBluetooth.framework in Frameworks */, 29A2996E1A55763100117608 /* Social.framework in Frameworks */, 29A2996A1A5575CC00117608 /* AudioToolbox.framework in Frameworks */, 29A299681A5575C400117608 /* CFNetwork.framework in Frameworks */, - 29A299661A5575BF00117608 /* CoreGraphics.framework in Frameworks */, 29A299641A5575AF00117608 /* CoreLocation.framework in Frameworks */, 29A299621A5575A900117608 /* MobileCoreServices.framework in Frameworks */, 29A299601A5575A100117608 /* QuartzCore.framework in Frameworks */, @@ -431,7 +464,7 @@ 292338921AA350A400A47A39 /* Tabs */ = { isa = PBXGroup; children = ( - DE1C96E21AE37F2B00610AF7 /* 05_test */, + DE1C96E21AE37F2B00610AF7 /* 05_Contacts */, DE6DA81F1ABF5453007A683B /* 04_Discovers */, 292338931AA350A400A47A39 /* 01_Groups */, 292338961AA350A400A47A39 /* 02_Messages */, @@ -452,7 +485,6 @@ 292338961AA350A400A47A39 /* 02_Messages */ = { isa = PBXGroup; children = ( - DE1C96E11AE37F0900610AF7 /* New Group */, 292338971AA350A400A47A39 /* 01_SelectSingle */, 2923389B1AA350A400A47A39 /* 02_SelectMultiple */, 2923389C1AA350A400A47A39 /* 03_AddressBook */, @@ -858,6 +890,7 @@ 29A5312C1AAEEF9500263CB1 /* tabbar */ = { isa = PBXGroup; children = ( + 689D00E81B1D9BFD003E21F3 /* contact-icon.png */, 29A5312D1AAEEF9500263CB1 /* tab_groups@2x.png */, 29A5312E1AAEEF9500263CB1 /* tab_messages@2x.png */, 29A5312F1AAEEF9500263CB1 /* tab_profile@2x.png */, @@ -877,6 +910,8 @@ 29EB23FC19E9292500D7AA97 = { isa = PBXGroup; children = ( + DEBCFF691B5E2C5E003A47B2 /* Contacts.h */, + DEBCFF6A1B5E2C5E003A47B2 /* Contacts.m */, 2923388B1AA350A400A47A39 /* Classes */, 2927192F19F284AC009C308B /* Vendors */, 29B8FE7319E92E4500E7A503 /* Resources */, @@ -900,7 +935,12 @@ DE1C96E61AE47D7400610AF7 /* app.entitlements */, 29EB254F19E92ACD00D7AA97 /* AppConstant.h */, 29EB240C19E9292500D7AA97 /* AppDelegate.h */, + 685AE2501B1DA8F600C8D9E9 /* Whale_preview_180.png */, + 685AE2521B1DAB5000C8D9E9 /* Whale_preview_120.png */, 29EB240D19E9292500D7AA97 /* AppDelegate.m */, + DE31A2EA1AF8689100FD8DE2 /* DatabaseAvailability.h */, + DE31A2E11AF7321700FD8DE2 /* AppDelegate+MOC.h */, + DE31A2E21AF7321700FD8DE2 /* AppDelegate+MOC.m */, 29EB241519E9292500D7AA97 /* Images.xcassets */, 29EB241719E9292500D7AA97 /* LaunchScreen.xib */, 29EB240819E9292500D7AA97 /* Supporting Files */, @@ -941,20 +981,25 @@ path = Frameworks; sourceTree = ""; }; - DE1C96E11AE37F0900610AF7 /* New Group */ = { - isa = PBXGroup; - children = ( - ); - name = "New Group"; - sourceTree = ""; - }; - DE1C96E21AE37F2B00610AF7 /* 05_test */ = { + DE1C96E21AE37F2B00610AF7 /* 05_Contacts */ = { isa = PBXGroup; children = ( - DE1C96E31AE37F7B00610AF7 /* test.h */, - DE1C96E41AE37F7B00610AF7 /* test.m */, + DEE8553E1B081778000AA5AC /* ContactsView.h */, + DEE8553F1B081778000AA5AC /* ContactsView.m */, +<<<<<<< Updated upstream + DEE855501B12817C000AA5AC /* CurrentUser.h */, + DEE855511B12817C000AA5AC /* CurrentUser.m */, +======= + DEE8554A1B09BE93000AA5AC /* Contacts.h */, + 68E9C3E21B5CDDC700B3B900 /* contactsCell.h */, + 68E9C3E31B5CDDC700B3B900 /* contactsCell.m */, + 68E9C3E41B5CDDC700B3B900 /* contactsCell.xib */, + DEE8554B1B09BE93000AA5AC /* Contacts.m */, +>>>>>>> Stashed changes + DEE855441B08232E000AA5AC /* contactDetailsVC.h */, + DEE855451B08232E000AA5AC /* contactDetailsVC.m */, ); - name = 05_test; + name = 05_Contacts; sourceTree = ""; }; DE6DA81F1ABF5453007A683B /* 04_Discovers */ = { @@ -962,13 +1007,19 @@ children = ( DE6DA8231ABF54CE007A683B /* DiscoversView.h */, DE6DA8241ABF54CE007A683B /* DiscoversView.m */, + DE31A2E71AF74D2700FD8DE2 /* PhotoDatabaseAvailability.h */, + DE31A2E41AF7357400FD8DE2 /* DiscoversView+MOC.h */, + DE31A2E51AF7357400FD8DE2 /* DiscoversView+MOC.m */, DEBB7B461AE3753C009CD940 /* Discover.xcdatamodeld */, - DE1C96DE1AE37BB400610AF7 /* DiscoverUser+bluechat.h */, - DE1C96DF1AE37BB400610AF7 /* DiscoverUser+bluechat.m */, - DEBB7B491AE37599009CD940 /* DiscoverUser.h */, - DEBB7B4A1AE37599009CD940 /* DiscoverUser.m */, - DE4AA47F1AC9B4FE008309D0 /* BTLEPeripheralViewController.h */, - DE4AA4801AC9B4FE008309D0 /* BTLEPeripheralViewController.m */, + DEBF53C71B4CDA0D00891128 /* DiscoverUser.h */, + DEBF53C81B4CDA0D00891128 /* DiscoverUser.m */, + DEBF53CA1B4CF9C900891128 /* discoversCell.h */, + DEBF53CB1B4CF9C900891128 /* discoversCell.m */, + DEBF53CC1B4CF9C900891128 /* discoversCell.xib */, + DEB34C2B1AF0A7DF000A42B8 /* detailsView.h */, + DEB34C2C1AF0A7DF000A42B8 /* detailsView.m */, + DE31A2DB1AF7152800FD8DE2 /* CoreDataTableViewController.h */, + DE31A2DC1AF7152800FD8DE2 /* CoreDataTableViewController.m */, DE4AA4831AC9B582008309D0 /* TransferService.h */, ); name = 04_Discovers; @@ -1061,9 +1112,11 @@ 29A531351AAEEF9500263CB1 /* tab_messages@2x.png in Resources */, 292338C81AA350A400A47A39 /* AddressBookView.xib in Resources */, 29EB241919E9292500D7AA97 /* LaunchScreen.xib in Resources */, + 685AE2511B1DA8F600C8D9E9 /* Whale_preview_180.png in Resources */, 292339C01AA38E0F00A47A39 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */, 292338CC1AA350A400A47A39 /* MessagesView.xib in Resources */, 292339C71AA38E0F00A47A39 /* JSQMessagesLoadEarlierHeaderView.xib in Resources */, + 685AE2531B1DAB5000C8D9E9 /* Whale_preview_120.png in Resources */, 29A531341AAEEF9500263CB1 /* tab_groups@2x.png in Resources */, 292338CA1AA350A400A47A39 /* MessagesCell.xib in Resources */, 292338F71AA374C300A47A39 /* SelectMultipleView.xib in Resources */, @@ -1072,8 +1125,10 @@ 292339A21AA38E0F00A47A39 /* JSQMessagesAssets.bundle in Resources */, 292338C61AA350A400A47A39 /* SelectSingleView.xib in Resources */, 29A531361AAEEF9500263CB1 /* tab_profile@2x.png in Resources */, + 689D00E91B1D9BFD003E21F3 /* contact-icon.png in Resources */, 29A531331AAEEF9500263CB1 /* profile_blank@2x.png in Resources */, DEBB7B351AE2FD21009CD940 /* tab_discovers.png in Resources */, + DEBF53CE1B4CF9C900891128 /* discoversCell.xib in Resources */, 29A531311AAEEF9500263CB1 /* messages_blank@2x.png in Resources */, 29A531321AAEEF9500263CB1 /* messages_compose@2x.png in Resources */, 292338FC1AA37C4100A47A39 /* FacebookFriendsView.xib in Resources */, @@ -1081,6 +1136,7 @@ 292338D41AA350A400A47A39 /* WelcomeView.xib in Resources */, 29A531301AAEEF9500263CB1 /* chat_blank@2x.png in Resources */, 292339C21AA38E0F00A47A39 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */, + 68E9C3E61B5CDDC700B3B900 /* contactsCell.xib in Resources */, 292339CA1AA38E0F00A47A39 /* JSQMessagesToolbarContentView.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1092,6 +1148,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DEE855521B12817C000AA5AC /* CurrentUser.m in Sources */, 292338F61AA374C300A47A39 /* SelectMultipleView.m in Sources */, 292338C71AA350A400A47A39 /* AddressBookView.m in Sources */, 292339B41AA38E0F00A47A39 /* JSQMessagesCollectionViewLayoutAttributes.m in Sources */, @@ -1105,6 +1162,7 @@ 292339B91AA38E0F00A47A39 /* JSQMessagesBubbleImage.m in Sources */, 292339311AA38DBD00A47A39 /* UIImageView+AFNetworking.m in Sources */, 292339A91AA38E0F00A47A39 /* UIView+JSQMessages.m in Sources */, + DEE855461B08232E000AA5AC /* contactDetailsVC.m in Sources */, 2923392C1AA38DBD00A47A39 /* AFURLSessionManager.m in Sources */, 292339AD1AA38E0F00A47A39 /* JSQMessagesAvatarImageFactory.m in Sources */, 292339301AA38DBD00A47A39 /* UIButton+AFNetworking.m in Sources */, @@ -1131,20 +1189,25 @@ 292339321AA38DBD00A47A39 /* UIProgressView+AFNetworking.m in Sources */, 292339281AA38DBD00A47A39 /* AFSecurityPolicy.m in Sources */, 2923392F1AA38DBD00A47A39 /* UIAlertView+AFNetworking.m in Sources */, + DEBF53C91B4CDA0D00891128 /* DiscoverUser.m in Sources */, 292339B31AA38E0F00A47A39 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m in Sources */, + DEB34C2D1AF0A7DF000A42B8 /* detailsView.m in Sources */, 292339C91AA38E0F00A47A39 /* JSQMessagesToolbarContentView.m in Sources */, + DEE855401B081778000AA5AC /* ContactsView.m in Sources */, 292339B11AA38E0F00A47A39 /* JSQMessagesToolbarButtonFactory.m in Sources */, 2923392E1AA38DBD00A47A39 /* UIActivityIndicatorView+AFNetworking.m in Sources */, 2923392B1AA38DBD00A47A39 /* AFURLResponseSerialization.m in Sources */, 292338C41AA350A400A47A39 /* GroupsView.m in Sources */, + DEBCFF6B1B5E2C5E003A47B2 /* Contacts.m in Sources */, 292339B21AA38E0F00A47A39 /* JSQMessagesCollectionViewFlowLayout.m in Sources */, 292339BA1AA38E0F00A47A39 /* JSQPhotoMediaItem.m in Sources */, 292339A41AA38E0F00A47A39 /* JSQSystemSoundPlayer+JSQMessages.m in Sources */, 292339A61AA38E0F00A47A39 /* UIColor+JSQMessages.m in Sources */, 292338D61AA350A400A47A39 /* pushnotification.m in Sources */, 292339C81AA38E0F00A47A39 /* JSQMessagesMediaPlaceholderView.m in Sources */, - DE4AA4811AC9B4FE008309D0 /* BTLEPeripheralViewController.m in Sources */, - DE1C96E01AE37BB400610AF7 /* DiscoverUser+bluechat.m in Sources */, + DE31A2E31AF7321700FD8DE2 /* AppDelegate+MOC.m in Sources */, + DE31A2DD1AF7152800FD8DE2 /* CoreDataTableViewController.m in Sources */, + DEBF53CD1B4CF9C900891128 /* discoversCell.m in Sources */, 292339331AA38DBD00A47A39 /* UIRefreshControl+AFNetworking.m in Sources */, 292339A71AA38E0F00A47A39 /* UIDevice+JSQMessages.m in Sources */, 292339C11AA38E0F00A47A39 /* JSQMessagesCollectionViewCellOutgoing.m in Sources */, @@ -1152,16 +1215,15 @@ 292339291AA38DBD00A47A39 /* AFURLConnectionOperation.m in Sources */, 292339AF1AA38E0F00A47A39 /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */, 292339B01AA38E0F00A47A39 /* JSQMessagesTimestampFormatter.m in Sources */, + DE31A2E61AF7357400FD8DE2 /* DiscoversView+MOC.m in Sources */, 292339341AA38DBD00A47A39 /* UIWebView+AFNetworking.m in Sources */, 296DD5E91A1F557900AB9F8C /* ProgressHUD.m in Sources */, 292339C31AA38E0F00A47A39 /* JSQMessagesComposerTextView.m in Sources */, 292338C51AA350A400A47A39 /* SelectSingleView.m in Sources */, 292339AE1AA38E0F00A47A39 /* JSQMessagesBubbleImageFactory.m in Sources */, - DE1C96E51AE37F7B00610AF7 /* test.m in Sources */, 292339B81AA38E0F00A47A39 /* JSQMessagesAvatarImage.m in Sources */, 2923392A1AA38DBD00A47A39 /* AFURLRequestSerialization.m in Sources */, 292339A51AA38E0F00A47A39 /* NSString+JSQMessages.m in Sources */, - DEBB7B4B1AE37599009CD940 /* DiscoverUser.m in Sources */, 292339CB1AA38E0F00A47A39 /* JSQMessagesTypingIndicatorFooterView.m in Sources */, 292339B71AA38E0F00A47A39 /* JSQMessage.m in Sources */, 292338D11AA350A400A47A39 /* RegisterView.m in Sources */, @@ -1170,6 +1232,7 @@ 292339B61AA38E0F00A47A39 /* JSQMediaItem.m in Sources */, 292338C91AA350A400A47A39 /* MessagesCell.m in Sources */, DEBB7B481AE3753C009CD940 /* Discover.xcdatamodeld in Sources */, + 68E9C3E51B5CDDC700B3B900 /* contactsCell.m in Sources */, 292338CF1AA350A400A47A39 /* LoginView.m in Sources */, 29EB240B19E9292500D7AA97 /* main.m in Sources */, ); diff --git a/app.xcodeproj/project.xcworkspace/xcuserdata/dlau.xcuserdatad/UserInterfaceState.xcuserstate b/app.xcodeproj/project.xcworkspace/xcuserdata/dlau.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..5e2e456 Binary files /dev/null and b/app.xcodeproj/project.xcworkspace/xcuserdata/dlau.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/app.xcodeproj/project.xcworkspace/xcuserdata/kiddjacky.xcuserdatad/UserInterfaceState.xcuserstate b/app.xcodeproj/project.xcworkspace/xcuserdata/kiddjacky.xcuserdatad/UserInterfaceState.xcuserstate index 28c556c..a0f70f1 100644 Binary files a/app.xcodeproj/project.xcworkspace/xcuserdata/kiddjacky.xcuserdatad/UserInterfaceState.xcuserstate and b/app.xcodeproj/project.xcworkspace/xcuserdata/kiddjacky.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/app.xcodeproj/xcuserdata/dlau.xcuserdatad/xcschemes/app.xcscheme b/app.xcodeproj/xcuserdata/dlau.xcuserdatad/xcschemes/app.xcscheme new file mode 100644 index 0000000..eb2bfd8 --- /dev/null +++ b/app.xcodeproj/xcuserdata/dlau.xcuserdatad/xcschemes/app.xcscheme @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app.xcodeproj/xcuserdata/dlau.xcuserdatad/xcschemes/xcschememanagement.plist b/app.xcodeproj/xcuserdata/dlau.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..a96fa39 --- /dev/null +++ b/app.xcodeproj/xcuserdata/dlau.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + app.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 29EB240419E9292500D7AA97 + + primary + + + + + diff --git a/app.xcodeproj/xcuserdata/kiddjacky.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/app.xcodeproj/xcuserdata/kiddjacky.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index a95417f..fecf64b 100644 --- a/app.xcodeproj/xcuserdata/kiddjacky.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/app.xcodeproj/xcuserdata/kiddjacky.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -10,11 +10,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Classes/Tabs/01_Groups/GroupsView.m" - timestampString = "449213571.011079" + timestampString = "452842236.458952" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "153" - endingLineNumber = "153" + startingLineNumber = "155" + endingLineNumber = "155" landmarkName = "-tableView:cellForRowAtIndexPath:" landmarkType = "5"> diff --git a/app/AppConstant.h b/app/AppConstant.h index 7fecd98..6d37fad 100755 --- a/app/AppConstant.h +++ b/app/AppConstant.h @@ -34,6 +34,12 @@ #define PF_USER_FACEBOOKID @"facebookId" // String #define PF_USER_PICTURE @"picture" // File #define PF_USER_THUMBNAIL @"thumbnail" // File +#define PF_USER_SEX @"sex" // String +#define PF_USER_AGE @"age" // Number +#define PF_USER_BIRTHDAY @"birthday" // String +#define PF_USER_INTEREST @"interest" // String +#define PF_USER_SELF_DESCRIPTION @"selfDescription" // String +#define PF_USER_CONTACTS @"contacts" // Array of contact names //----------------------------------------------------------------------- #define PF_CHAT_CLASS_NAME @"Chat" // Class name #define PF_CHAT_USER @"user" // Pointer to User Class diff --git a/app/AppDelegate+MOC.h b/app/AppDelegate+MOC.h new file mode 100644 index 0000000..d75d802 --- /dev/null +++ b/app/AppDelegate+MOC.h @@ -0,0 +1,13 @@ +// +// AppDelegate+MOC.h +// app +// +// Created by kiddjacky on 5/3/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate (MOC) +- (NSManagedObjectContext *)createMainQueueManagedObjectContext; +@end diff --git a/app/AppDelegate+MOC.m b/app/AppDelegate+MOC.m new file mode 100644 index 0000000..c780b0f --- /dev/null +++ b/app/AppDelegate+MOC.m @@ -0,0 +1,100 @@ +// +// AppDelegate+MOC.m +// app +// +// Created by kiddjacky on 5/3/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#import "AppDelegate+MOC.h" +#import + + +@implementation AppDelegate (MOC) +#pragma mark - Core Data + +- (void)saveContext:(NSManagedObjectContext *)managedObjectContext +{ + NSError *error = nil; + if (managedObjectContext != nil) { + if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { + // Replace this implementation with code to handle the error appropriately. + // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + NSLog(@"Unresolved error %@, %@", error, [error userInfo]); + abort(); + } + } +} + +// Returns the managed object context for the application. +// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application. +- (NSManagedObjectContext *)createMainQueueManagedObjectContext +{ + NSManagedObjectContext *managedObjectContext = nil; + NSPersistentStoreCoordinator *coordinator = [self createPersistentStoreCoordinator]; + if (coordinator != nil) { + managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; + [managedObjectContext setPersistentStoreCoordinator:coordinator]; + } + return managedObjectContext; +} + +// Returns the managed object model for the application. +// If the model doesn't already exist, it is created from the application's model. +- (NSManagedObjectModel *)createManagedObjectModel +{ + NSManagedObjectModel *managedObjectModel = nil; + NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Discover" withExtension:@"momd"]; + managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; + return managedObjectModel; +} + +// Returns the persistent store coordinator for the application. +// If the coordinator doesn't already exist, it is created and the application's store added to it. +- (NSPersistentStoreCoordinator *)createPersistentStoreCoordinator +{ + NSPersistentStoreCoordinator *persistentStoreCoordinator = nil; + NSManagedObjectModel *managedObjectModel = [self createManagedObjectModel]; + + NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MOC.sqlite"]; + + NSError *error = nil; + persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel]; + if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { + /* + Replace this implementation with code to handle the error appropriately. + + abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + + Typical reasons for an error here include: + * The persistent store is not accessible; + * The schema for the persistent store is incompatible with current managed object model. + Check the error message to determine what the actual problem was. + + + If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory. + + If you encounter schema incompatibility errors during development, you can reduce their frequency by: + * Simply deleting the existing store: + [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil] + + * Performing automatic lightweight migration by passing the following dictionary as the options parameter: + @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} + + Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. + + */ + NSLog(@"Unresolved error %@, %@", error, [error userInfo]); + abort(); + } + + return persistentStoreCoordinator; +} + +// Returns the URL to the application's Documents directory + +- (NSURL *)applicationDocumentsDirectory +{ + return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; +} +@end diff --git a/app/AppDelegate.h b/app/AppDelegate.h index eaa1844..7f4c11d 100755 --- a/app/AppDelegate.h +++ b/app/AppDelegate.h @@ -16,17 +16,23 @@ #import "MessagesView.h" #import "ProfileView.h" #import "DiscoversView.h" +#import "ContactsView.h" //------------------------------------------------------------------------------------------------------------------------------------------------- @interface AppDelegate : UIResponder //------------------------------------------------------------------------------------------------------------------------------------------------- +@property (strong, nonatomic) NSManagedObjectContext *DiscoverDatabaseContext; + + @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) UITabBarController *tabBarController; + @property (strong, nonatomic) GroupsView *groupsView; @property (strong, nonatomic) MessagesView *messagesView; @property (strong, nonatomic) ProfileView *profileView; @property (strong, nonatomic) DiscoversView *discoversView; +@property (strong, nonatomic) ContactsView *contactsView; @end diff --git a/app/AppDelegate.m b/app/AppDelegate.m index 11537fe..7ff556b 100755 --- a/app/AppDelegate.m +++ b/app/AppDelegate.m @@ -23,7 +23,40 @@ #import "NavigationController.h" #import "DiscoversView.h" -@implementation AppDelegate +#import +#import "TransferService.h" +#import +#import "DiscoverUser.h" +#import "Contacts.h" +#import "DatabaseAvailability.h" +#import "AppDelegate+MOC.h" + +@interface AppDelegate () +//setup BTLE +@property (strong, nonatomic) CBPeripheralManager *peripheralManager; +@property (strong, nonatomic) CBCentralManager *centralManager; +@property (strong, nonatomic) CBPeripheral *discoveredPeripheral; +@property (strong, nonatomic) CBPeripheral *connectingPeripheral; +//unused for now +@property (strong, nonatomic) NSMutableData *data; +@property (strong, nonatomic) CBMutableCharacteristic *transferCharacteristic; +@property (strong, nonatomic) NSData *dataToSend; +@property (nonatomic, readwrite) NSInteger sendDataIndex; +@property (strong, nonatomic) IBOutlet UITextView *central_textview; +@property (strong, nonatomic) IBOutlet UITextView *textView; +@property (strong, nonatomic) IBOutlet UISwitch *advertisingSwitch; +//CLLocation +@property (strong, nonatomic) CLLocationManager *locationManager; +@property (strong, nonatomic) CLLocation *currentLocation; + +@end + + +#define NOTIFY_MTU 20 +#define DISCOVER_USER_LIMIT 3 + + +@implementation AppDelegate //------------------------------------------------------------------------------------------------------------------------------------------------- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions @@ -49,15 +82,17 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( self.messagesView = [[MessagesView alloc] init]; self.profileView = [[ProfileView alloc] init]; self.discoversView = [[DiscoversView alloc] init]; + self.contactsView = [[ContactsView alloc] init]; NavigationController *navController1 = [[NavigationController alloc] initWithRootViewController:self.groupsView]; NavigationController *navController2 = [[NavigationController alloc] initWithRootViewController:self.messagesView]; NavigationController *navController3 = [[NavigationController alloc] initWithRootViewController:self.profileView]; NavigationController *navController4 = [[NavigationController alloc] initWithRootViewController:self.discoversView]; + NavigationController *navController5 = [[NavigationController alloc] initWithRootViewController:self.contactsView]; self.tabBarController = [[UITabBarController alloc] init]; - self.tabBarController.viewControllers = [NSArray arrayWithObjects:navController1, navController2, navController3, navController4, nil]; + self.tabBarController.viewControllers = [NSArray arrayWithObjects:navController1, navController2, navController3, navController4, navController5, nil]; self.tabBarController.tabBar.translucent = NO; self.tabBarController.selectedIndex = DEFAULT_TAB; @@ -65,12 +100,60 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [self.window makeKeyAndVisible]; //--------------------------------------------------------------------------------------------------------------------------------------------- + //create database + self.DiscoverDatabaseContext = [self createMainQueueManagedObjectContext]; + + + // Start up the CBPeripheralManager + _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil]; + + + // Start up the CBCentralManager + _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; + + // And somewhere to store the incoming data + _data = [[NSMutableData alloc] init]; + + //_locationManager = [[CLLocationManager alloc] init]; + [self CurrentLocationIdentifier]; // call this method + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(post_context) name:DiscoverViewReady object:nil]; + + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stop_scan) name:PFUSER_LOGOUT object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(start_scan) name:PFUSER_READY object:nil]; return YES; } +-(void)stop_scan +{ + [self.centralManager stopScan]; +} + +-(void)start_scan +{ + if (self.centralManager.state != CBCentralManagerStatePoweredOn) { + // In a real app, you'd deal with all the states correctly + return; + } + [self scan]; +} + +//setup discover database +-(void)setDiscoverDatabaseContext:(NSManagedObjectContext *)DiscoverDatabaseContext +{ + _DiscoverDatabaseContext = DiscoverDatabaseContext; + + //setup notification to other view controller that the context is avaiable. + NSDictionary *userInfo = self.DiscoverDatabaseContext ? @{DatabaseAvailabilityContext : self.DiscoverDatabaseContext } : nil; + [[NSNotificationCenter defaultCenter] postNotificationName:DatabaseAvailabilityNotification object:self userInfo:userInfo]; + + NSLog(@"Post database notification!"); + +} + //------------------------------------------------------------------------------------------------------------------------------------------------- - (void)applicationWillResignActive:(UIApplication *)application //------------------------------------------------------------------------------------------------------------------------------------------------- @@ -152,4 +235,760 @@ - (void)refreshMessagesView [self.messagesView loadMessages]; } + +#pragma Discover Scheme + +#pragma mark - BTLE +/** centralManagerDidUpdateState is a required protocol method. + * Usually, you'd check for other states to make sure the current device supports LE, is powered on, etc. + * In this instance, we're just using it to wait for CBCentralManagerStatePoweredOn, which indicates + * the Central is ready to be used. + */ +- (void)centralManagerDidUpdateState:(CBCentralManager *)central +{ + if (central.state != CBCentralManagerStatePoweredOn) { + // In a real app, you'd deal with all the states correctly + return; + } + + // The state must be CBCentralManagerStatePoweredOn... + + // ... so start scanning + //[self scan]; + +} + + +/** Scan for peripherals - specifically for our service's 128bit CBUUID + */ +- (void)scan +{ + [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] + options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @NO }]; + + NSLog(@"Scanning started"); +} + +//------------ Current Location Address----- +-(void)CurrentLocationIdentifier +{ + //---- For getting current gps location + self.locationManager = [[CLLocationManager alloc] init]; + self.locationManager.delegate = self; + + // Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7. + if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) { + [self.locationManager requestWhenInUseAuthorization]; + } + + + self.locationManager.distanceFilter = kCLDistanceFilterNone; + self.locationManager.desiredAccuracy = kCLLocationAccuracyBest; + self.locationManager.distanceFilter = 500; //500 meter filter + // [self.locationManager requestAlwaysAuthorization]; + // NSLog(@"CurrentLocationIdentifier is called\n"); + + [self.locationManager startUpdatingLocation]; + NSLog(@"Location Services enabled = %d", [CLLocationManager locationServicesEnabled]); + NSLog(@"Authorization Status = %d", [CLLocationManager authorizationStatus]); + NSLog(@"CurrentLocationIdentifier is called\n"); + //------ +} +- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations +{ + self.currentLocation = [locations lastObject]; + //[locationManager stopUpdatingLocation]; + //eventDate = currentLocation.timestamp; + NSLog(@"Update Location is called\n"); + + /* + NSTimeInterval howRecent = [eventDate timeIntervalSinceNow]; + if (abs(howRecent) < 15.0) { + // If the event is recent, do something with it. + NSLog(@"latitude %+.6f, longitude %+.6f\n", + currentLocation.coordinate.latitude, + currentLocation.coordinate.longitude); + } + */ + + /* + CLGeocoder *geocoder = [[CLGeocoder alloc] init] ; + [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) + { + if (!(error)) + { + CLPlacemark *placemark = [placemarks objectAtIndex:0]; + NSLog(@"\nCurrent Location Detected\n"); + NSLog(@"placemark %@",placemark); + NSString *locatedAt = [[placemark.addressDictionary valueForKey:@"FormattedAddressLines"] componentsJoinedByString:@", "]; + NSString *Address = [[NSString alloc]initWithString:locatedAt]; + NSString *Area = [[NSString alloc]initWithString:placemark.locality]; + NSString *Country = [[NSString alloc]initWithString:placemark.country]; + NSString *CountryArea = [NSString stringWithFormat:@"%@, %@", Area,Country]; + NSLog(@"%@",CountryArea); + } + else + { + NSLog(@"Geocode failed with error %@", error); + NSLog(@"\nCurrent Location Not Detected\n"); + //return; + //CountryArea = NULL; + } + ---- For more results + placemark.region); + placemark.country); + placemark.locality); + placemark.name); + placemark.ocean); + placemark.postalCode); + placemark.subLocality); + placemark.location); + ------ + + }]; + */ + + +} + +/* + -(NSString *)geocoder:(CLGeocoder *)geocoder location:(CLLocation *)location; + { + NSLog(@"Resolving the Address"); + NSString *address; + [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) { + NSLog(@"Found placemarks: %@, error: %@", placemarks, error); + if (error == nil && [placemarks count] > 0) { + placemark = [placemarks lastObject]; + address = [NSString stringWithFormat:@"%@ %@\n%@ %@\n%@\n%@", + placemark.subThoroughfare, placemark.thoroughfare, + placemark.postalCode, placemark.locality, + placemark.administrativeArea, + placemark.country]; + } else { + NSLog(@"%@", error.debugDescription); + } + } ]; + + } + + */ +-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { + NSLog(@"%@", error.localizedDescription); +} + +- (void)locationManager:(CLLocationManager *)manager +didChangeAuthorizationStatus:(CLAuthorizationStatus)status +{ + NSLog(@"Authorization status changed to %d\n", status ); +} + + +/** This callback comes whenever a peripheral that is advertising the TRANSFER_SERVICE_UUID is discovered. + * We check the RSSI, to make sure it's close enough that we're interested in it, and if it is, + * we start the connection process + */ +- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI +{ + //NSLog(@"enter call back"); + // Reject any where the value is above reasonable range + /* + if (RSSI.integerValue > -15) { + return; + } + + // Reject if the signal strength is too low to be close enough (Close is around -22dB) + if (RSSI.integerValue < -35) { + return; + } + */ + + NSString *userName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; + NSLog(@"Discovered %@ at %@", userName, RSSI); + + if (userName!=NULL && userName.length > 0 ) { + [self get_info:userName]; + } + else { //if null, it is in back gorund, need ot connect + //NSUUID *nsUUID = [[NSUUID UUID] initWithUUIDString:@"DD2468AB-1865-B926-7FA4-AE3755D479D8"]; + NSArray *known_peripherals = [self.centralManager retrievePeripheralsWithIdentifiers:[NSArray arrayWithObject:peripheral.identifier]]; + NSLog(@"peripeheral is %@", peripheral); + NSLog(@"known_periperal is %@", known_peripherals); + if ([known_peripherals count] == 0) { + NSLog(@"peripheral is in background, try to connect"); + if (peripheral.state == CBPeripheralStateDisconnected) { + NSLog(@"try to connect"); + [self.centralManager connectPeripheral:peripheral options:nil]; + self.connectingPeripheral = peripheral; + } + } + } +} + + +-(void) get_info:(NSString *)userName +{ + NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"DiscoverUser"]; + request.predicate = [NSPredicate predicateWithFormat:@"userName = %@", userName]; + + NSError *error; + NSArray *matches = [self.DiscoverDatabaseContext executeFetchRequest:request error:&error]; + + if (error) { + //handle error + NSLog(@"request Error!"); + } else if ([matches count]==1) { + //maybe need to update the location or time + NSLog(@"already matched"); + DiscoverUser *discoverUser = [matches firstObject]; + NSLog(@"already discover user is %@, %@, %@, %@", discoverUser.userName, discoverUser.timeMeet, discoverUser.latitude, discoverUser.longitude); + //caculate time difference + NSTimeInterval distanceBetweeenDates = [[NSDate date] timeIntervalSinceDate:discoverUser.timeMeet]; + double secondsInMin = 60; + NSInteger minsBetweenDates = distanceBetweeenDates / secondsInMin; + if (minsBetweenDates > 2 ) + { + NSLog(@"time meet for the same discover user is more than 2 mins, update location and time"); + discoverUser.timeMeet = [NSDate date]; + double latitude = (double)[self.currentLocation coordinate].latitude; + discoverUser.latitude = [NSNumber numberWithDouble:latitude]; + double longitude = (double)[self.currentLocation coordinate].longitude; + discoverUser.longitude = [NSNumber numberWithDouble:longitude]; + + //find the actual full name + PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME]; + [query whereKey:PF_USER_USERNAME equalTo:discoverUser.userName]; + [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) + { + if ([objects count] != 0) + { + NSLog(@"find pf user full name and thumbnail"); + PFUser *user = [objects firstObject]; + discoverUser.userFullName = user[PF_USER_FULLNAME]; + NSLog(@"found user %@, thumbnail is %@", discoverUser.userFullName, user[PF_USER_THUMBNAIL]); + /* + PFFile *discoverThumbnail = user[PF_USER_THUMBNAIL]; + [discoverThumbnail getDataInBackgroundWithBlock:^(NSData *data, NSError *error) { + NSLog(@"in the block"); + if(!error) { + NSLog(@"no error!"); + discoverUser.thumbnail = data; + [self save_and_post]; + NSLog(@"thumbnail is %@", discoverUser.thumbnail); + } + }]; + */ + //NSLog(@"save thumbnail %@", discoverUser.thumbnail); + [self save_and_post]; + NSLog(@"save and post finished!"); + + } + }]; + + [self save_and_post]; + } + else { + NSLog(@"time meet for the same discover user is too soon to change"); + } + + } else { + NSLog(@"create new core data"); + + NSFetchRequest *add_request = [NSFetchRequest fetchRequestWithEntityName:@"DiscoverUser"]; + add_request.predicate = nil; + add_request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"timeMeet" + ascending:NO]]; + + NSError *add_error; + NSArray *add_matches = [self.DiscoverDatabaseContext executeFetchRequest:add_request error:&add_error]; + + if ([add_matches count] == DISCOVER_USER_LIMIT) { + NSLog(@"discover user reaching limit, remove the earliest discover user"); + [self.DiscoverDatabaseContext deleteObject:[add_matches lastObject]]; + } + + NSManagedObjectContext *context = [self DiscoverDatabaseContext]; + DiscoverUser *discoverUser = [NSEntityDescription insertNewObjectForEntityForName:@"DiscoverUser" inManagedObjectContext:context]; + discoverUser.userName = userName; + discoverUser.timeMeet = [NSDate date]; + double latitude = (double)[self.currentLocation coordinate].latitude; + discoverUser.latitude = [NSNumber numberWithDouble:latitude]; + double longitude = (double)[self.currentLocation coordinate].longitude; + discoverUser.longitude = [NSNumber numberWithDouble:longitude]; + NSLog(@"using parse query"); + //find the actual full name + PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME]; + [query whereKey:PF_USER_USERNAME equalTo:discoverUser.userName]; + [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) + { + if ([objects count] != 0) + { + NSLog(@"find pf user full name and thumbnail"); + PFUser *user = [objects firstObject]; + discoverUser.userFullName = user[PF_USER_FULLNAME]; + NSLog(@"found user %@, thumbnail is %@", discoverUser.userFullName, user[PF_USER_THUMBNAIL]); + /* + PFFile *discoverThumbnail = user[PF_USER_THUMBNAIL]; + [discoverThumbnail getDataInBackgroundWithBlock:^(NSData *data, NSError *error) { + NSLog(@"in the block"); + if(!error) { + NSLog(@"no error!"); + discoverUser.thumbnail = data; + [self save_and_post]; + NSLog(@"thumbnail is %@", discoverUser.thumbnail); + } + }]; + */ + //NSLog(@"save thumbnail %@", discoverUser.thumbnail); + [self save_and_post]; + NSLog(@"save and post finished!"); + + } + }]; + + //[self save_and_post]; + + } +} + +-(void) save_and_post +{ + NSError *error=nil; + + if (![self.DiscoverDatabaseContext save:&error]) { + NSLog(@"Couldn't save %@", [error localizedDescription]); + } + + //NSLog(@"Discover add is %@, %@, %@, %@", discoverUser.userName, discoverUser.timeMeet, discoverUser.latitude, discoverUser.longitude); + + //setup notification to other view controller that the context is avaiable. + NSDictionary *userInfo = self.DiscoverDatabaseContext ? @{DatabaseAvailabilityContext : self.DiscoverDatabaseContext } : nil; + [[NSNotificationCenter defaultCenter] postNotificationName:DatabaseAvailabilityNotification object:self userInfo:userInfo]; + + NSLog(@"Post database notification!"); +} + +/** If the connection fails for whatever reason, we need to deal with it. + */ +- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error +{ + NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]); + [self cleanup]; +} + + +/** We've connected to the peripheral, now we need to discover the services and characteristics to find the 'transfer' characteristic. + */ +- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral +{ + NSLog(@"Peripheral Connected"); + + // Stop scanning + [self.centralManager stopScan]; + NSLog(@"Scanning stopped"); + + // Clear the data that we may already have + [self.data setLength:0]; + + // Make sure we get the discovery callbacks + peripheral.delegate = self; + + // Search only for services that match our UUID + [peripheral discoverServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]]; +} + + +/** The Transfer Service was discovered + */ +- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error +{ + if (error) { + NSLog(@"Error discovering services: %@", [error localizedDescription]); + [self cleanup]; + return; + } + + // Discover the characteristic we want... + + // Loop through the newly filled peripheral.services array, just in case there's more than one. + for (CBService *service in peripheral.services) { + NSLog(@"discover service %@", service); + [peripheral discoverCharacteristics:nil forService:service]; + } +} + + +/** The Transfer characteristic was discovered. + * Once this has been found, we want to subscribe to it, which lets the peripheral know we want the data it contains + */ +- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error +{ + // Deal with errors (if any) + if (error) { + NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); + [self cleanup]; + return; + } + + // Again, we loop through the array, just in case. + for (CBCharacteristic *characteristic in service.characteristics) { + NSLog(@"discover characteristic"); + // And check if it's the right one + if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]) { + NSLog(@"read characteristic!"); + [peripheral readValueForCharacteristic:characteristic]; + // If it is, subscribe to it + //[peripheral setNotifyValue:YES forCharacteristic:characteristic]; + } + } + + // Once this is complete, we just need to wait for the data to come in. +} + + +/** This callback lets us know more data has arrived via notification on the characteristic + */ +- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error +{ + if (error) { + NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); + return; + } + + NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]; + NSLog(@"characteristic is %@", stringFromData); + // Have we got everything we need? + if (stringFromData != nil) { + + // We have, so show the data, + [self get_info:stringFromData]; + + // Cancel our subscription to the characteristic + [peripheral setNotifyValue:NO forCharacteristic:characteristic]; + + // and disconnect from the peripehral + [self.centralManager cancelPeripheralConnection:peripheral]; + } + + // Otherwise, just add the data on to what we already have + //[self.data appendData:characteristic.value]; + + // Log it + NSLog(@"Received: %@", stringFromData); +} + + +/** The peripheral letting us know whether our subscribe/unsubscribe happened or not + */ +- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error +{ + if (error) { + NSLog(@"Error changing notification state: %@", error.localizedDescription); + } + + // Exit if it's not the transfer characteristic + if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { + return; + } + + // Notification has started + if (characteristic.isNotifying) { + NSLog(@"Notification began on %@", characteristic); + } + + // Notification has stopped + else { + // so disconnect from the peripheral + NSLog(@"Notification stopped on %@. Disconnecting", characteristic); + [self.centralManager cancelPeripheralConnection:peripheral]; + } +} + + +/** Once the disconnection happens, we need to clean up our local copy of the peripheral + */ +- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error +{ + NSLog(@"Peripheral Disconnected"); + self.discoveredPeripheral = nil; + + // We're disconnected, so start scanning again + [self scan]; +} + + +/** Call this when things either go wrong, or you're done with the connection. + * This cancels any subscriptions if there are any, or straight disconnects if not. + * (didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved) + */ +- (void)cleanup +{ + // Don't do anything if we're not connected + if (!self.discoveredPeripheral == CBPeripheralStateConnecting) { + return; + } + + // See if we are subscribed to a characteristic on the peripheral + if (self.discoveredPeripheral.services != nil) { + for (CBService *service in self.discoveredPeripheral.services) { + if (service.characteristics != nil) { + for (CBCharacteristic *characteristic in service.characteristics) { + if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { + if (characteristic.isNotifying) { + // It is notifying, so unsubscribe + [self.discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic]; + + // And we're done. + return; + } + } + } + } + } + } + + // If we've got this far, we're connected, but we're not subscribed, so we just disconnect + [self.centralManager cancelPeripheralConnection:self.discoveredPeripheral]; +} + + + + +#pragma mark - Peripheral Methods + + + +/** Required protocol method. A full app should take care of all the possible states, + * but we're just waiting for to know when the CBPeripheralManager is ready + */ +- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral +{ + // Opt out from any other state + if (peripheral.state != CBPeripheralManagerStatePoweredOn) { + return; + } + + // We're in CBPeripheralManagerStatePoweredOn state... + NSLog(@"self.peripheralManager powered on."); + + + // ... so build our service. + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(btle_seq) name:PFUSER_READY object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stop_ad) name:PFUSER_LOGOUT object:nil]; + /* + if ([PFUser currentUser] != nil) { + [self btle_seq]; + } else { + return; + }*/ + /* + // Start with the CBMutableCharacteristic + self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID] + properties:CBCharacteristicPropertyNotify + value:nil + permissions:CBAttributePermissionsReadable]; + + // Then the service + CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] + primary:YES]; + + // Add the characteristic to the service + transferService.characteristics = @[self.transferCharacteristic]; + + // And add it to the peripheral manager + [self.peripheralManager addService:transferService]; + */ +} + + +/** Catch when someone subscribes to our characteristic, then start sending them data + */ +- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic +{ + NSLog(@"Central subscribed to characteristic"); + + // Get the data + self.dataToSend = [self.textView.text dataUsingEncoding:NSUTF8StringEncoding]; + + // Reset the index + self.sendDataIndex = 0; + + // Start sending + [self sendData]; +} + + +/** Recognise when the central unsubscribes + */ +- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic +{ + NSLog(@"Central unsubscribed from characteristic"); +} + + +/** Sends the next amount of data to the connected central + */ +- (void)sendData +{ + // First up, check if we're meant to be sending an EOM + static BOOL sendingEOM = NO; + + if (sendingEOM) { + + // send it + BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; + + // Did it send? + if (didSend) { + + // It did, so mark it as sent + sendingEOM = NO; + + NSLog(@"Sent: EOM"); + } + + // It didn't send, so we'll exit and wait for peripheralManagerIsReadyToUpdateSubscribers to call sendData again + return; + } + + // We're not sending an EOM, so we're sending data + + // Is there any left to send? + + if (self.sendDataIndex >= self.dataToSend.length) { + + // No data left. Do nothing + return; + } + + // There's data left, so send until the callback fails, or we're done. + + BOOL didSend = YES; + + while (didSend) { + + // Make the next chunk + + // Work out how big it should be + NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex; + + // Can't be longer than 20 bytes + if (amountToSend > NOTIFY_MTU) amountToSend = NOTIFY_MTU; + + // Copy out the data we want + NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend]; + + // Send it + didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; + + // If it didn't work, drop out and wait for the callback + if (!didSend) { + return; + } + + NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding]; + NSLog(@"Sent: %@", stringFromData); + + // It did send, so update our index + self.sendDataIndex += amountToSend; + + // Was it the last one? + if (self.sendDataIndex >= self.dataToSend.length) { + + // It was - send an EOM + + // Set this so if the send fails, we'll send it next time + sendingEOM = YES; + + // Send it + BOOL eomSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; + + if (eomSent) { + // It sent, we're all done + sendingEOM = NO; + + NSLog(@"Sent: EOM"); + } + + return; + } + } +} + + +/** This callback comes in when the PeripheralManager is ready to send the next chunk of data. + * This is to ensure that packets will arrive in the order they are sent + */ +- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral +{ + // Start sending again + [self sendData]; +} + + +/** Start advertising + */ +- (IBAction)switchChanged:(id)sender +{ + if (self.advertisingSwitch.on) { + // All we advertise is our service's UUID + [self btle_seq]; + // [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }]; + } + + else { + [self.peripheralManager stopAdvertising]; + } +} + +-(void)btle_switch_mode:(NSTimer *)switchtimer +{ + // NSLog(@"Timer is fired off"); + + // if (self.peripheralManager.state == CBPeripheralManagerStatePoweredOn) { + // [self.peripheralManager stopAdvertising]; + // return; + // } + +} + +- (void)btle_seq +{ + PFUser *user = [PFUser currentUser]; + [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] , CBAdvertisementDataLocalNameKey : user.username }]; + NSLog(@"send out advertisment data, user name is %@", user.username); + // create our characteristics + CBMutableCharacteristic *characteristic = + [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] + properties:CBCharacteristicPropertyRead + value:[user.username dataUsingEncoding:NSUTF8StringEncoding] + permissions:CBAttributePermissionsReadable]; + + // create the service with the characteristics + CBMutableService *service = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] primary:YES]; + service.characteristics = @[characteristic]; + [self.peripheralManager addService:service]; + + + //self.switchTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(btle_switch_mode:) userInfo:nil repeats:YES]; +} + +-(void)stop_ad +{ + [self.peripheralManager stopAdvertising]; + NSLog(@"stop advertising"); +} + +-(void)post_context +{ + //setup notification to other view controller that the context is avaiable. + NSDictionary *userInfo = self.DiscoverDatabaseContext ? @{DatabaseAvailabilityContext : self.DiscoverDatabaseContext } : nil; + [[NSNotificationCenter defaultCenter] postNotificationName:DatabaseAvailabilityNotification object:self userInfo:userInfo]; + + NSLog(@"Post database notification in observer!"); + +} + + @end diff --git a/app/DatabaseAvailability.h b/app/DatabaseAvailability.h new file mode 100644 index 0000000..9ce08d6 --- /dev/null +++ b/app/DatabaseAvailability.h @@ -0,0 +1,19 @@ +// +// Header.h +// app +// +// Created by kiddjacky on 5/4/15. +// Copyright (c) 2015 KZ. All rights reserved. +// + +#ifndef app_Header_h +#define app_Header_h + +#define DatabaseAvailabilityNotification @"DatabaseAvailabilityNotification" +#define DatabaseAvailabilityContext @"Context" +#define DiscoverViewReady @"DiscoverViewReady" +#define PFUSER_READY @"PFUSER_READY" +#define PFUSER_LOGOUT @"PFUSER_LOGOUT" +#define ContactAvailabilityNotification @"ContactAvailabilityNotification" +#define ContactAvailabilityContext @"ContactContext" +#endif diff --git a/app/Images.xcassets/AppIcon.appiconset/0058.png b/app/Images.xcassets/AppIcon.appiconset/0058.png deleted file mode 100755 index 9823ef3..0000000 Binary files a/app/Images.xcassets/AppIcon.appiconset/0058.png and /dev/null differ diff --git a/app/Images.xcassets/AppIcon.appiconset/0080.png b/app/Images.xcassets/AppIcon.appiconset/0080.png deleted file mode 100755 index be5dedf..0000000 Binary files a/app/Images.xcassets/AppIcon.appiconset/0080.png and /dev/null differ diff --git a/app/Images.xcassets/AppIcon.appiconset/0087.png b/app/Images.xcassets/AppIcon.appiconset/0087.png deleted file mode 100755 index 39b8449..0000000 Binary files a/app/Images.xcassets/AppIcon.appiconset/0087.png and /dev/null differ diff --git a/app/Images.xcassets/AppIcon.appiconset/0120-1.png b/app/Images.xcassets/AppIcon.appiconset/0120-1.png deleted file mode 100755 index aa970a1..0000000 Binary files a/app/Images.xcassets/AppIcon.appiconset/0120-1.png and /dev/null differ diff --git a/app/Images.xcassets/AppIcon.appiconset/0120.png b/app/Images.xcassets/AppIcon.appiconset/0120.png deleted file mode 100755 index aa970a1..0000000 Binary files a/app/Images.xcassets/AppIcon.appiconset/0120.png and /dev/null differ diff --git a/app/Images.xcassets/AppIcon.appiconset/Contents.json b/app/Images.xcassets/AppIcon.appiconset/Contents.json index 7c5a47b..4b72981 100755 --- a/app/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/app/Images.xcassets/AppIcon.appiconset/Contents.json @@ -3,37 +3,37 @@ { "size" : "29x29", "idiom" : "iphone", - "filename" : "0058.png", + "filename" : "Whale_preview_120-1.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", - "filename" : "0087.png", + "filename" : "Whale_preview-1.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", - "filename" : "0080.png", + "filename" : "Whale_preview-2.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", - "filename" : "0120-1.png", + "filename" : "Whale_preview-3.png", "scale" : "3x" }, { "size" : "60x60", "idiom" : "iphone", - "filename" : "0120.png", + "filename" : "Whale_preview-4.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", - "filename" : "0180.png", + "filename" : "Whale_preview_180.png", "scale" : "3x" } ], diff --git a/app/Images.xcassets/AppIcon.appiconset/Whale_preview-1.png b/app/Images.xcassets/AppIcon.appiconset/Whale_preview-1.png new file mode 100644 index 0000000..721cd6f Binary files /dev/null and b/app/Images.xcassets/AppIcon.appiconset/Whale_preview-1.png differ diff --git a/app/Images.xcassets/AppIcon.appiconset/Whale_preview-2.png b/app/Images.xcassets/AppIcon.appiconset/Whale_preview-2.png new file mode 100644 index 0000000..721cd6f Binary files /dev/null and b/app/Images.xcassets/AppIcon.appiconset/Whale_preview-2.png differ diff --git a/app/Images.xcassets/AppIcon.appiconset/Whale_preview-3.png b/app/Images.xcassets/AppIcon.appiconset/Whale_preview-3.png new file mode 100644 index 0000000..b3501e0 Binary files /dev/null and b/app/Images.xcassets/AppIcon.appiconset/Whale_preview-3.png differ diff --git a/app/Images.xcassets/AppIcon.appiconset/Whale_preview-4.png b/app/Images.xcassets/AppIcon.appiconset/Whale_preview-4.png new file mode 100644 index 0000000..721cd6f Binary files /dev/null and b/app/Images.xcassets/AppIcon.appiconset/Whale_preview-4.png differ diff --git a/app/Images.xcassets/AppIcon.appiconset/Whale_preview-5.png b/app/Images.xcassets/AppIcon.appiconset/Whale_preview-5.png new file mode 100644 index 0000000..b3501e0 Binary files /dev/null and b/app/Images.xcassets/AppIcon.appiconset/Whale_preview-5.png differ diff --git a/app/Images.xcassets/AppIcon.appiconset/Whale_preview_120-1.png b/app/Images.xcassets/AppIcon.appiconset/Whale_preview_120-1.png new file mode 100644 index 0000000..dca3c5a Binary files /dev/null and b/app/Images.xcassets/AppIcon.appiconset/Whale_preview_120-1.png differ diff --git a/app/Images.xcassets/AppIcon.appiconset/Whale_preview_120.png b/app/Images.xcassets/AppIcon.appiconset/Whale_preview_120.png new file mode 100644 index 0000000..dca3c5a Binary files /dev/null and b/app/Images.xcassets/AppIcon.appiconset/Whale_preview_120.png differ diff --git a/app/Images.xcassets/AppIcon.appiconset/Whale_preview_180.png b/app/Images.xcassets/AppIcon.appiconset/Whale_preview_180.png new file mode 100644 index 0000000..dca3c5a Binary files /dev/null and b/app/Images.xcassets/AppIcon.appiconset/Whale_preview_180.png differ diff --git a/app/Images.xcassets/Image.imageset/Contents.json b/app/Images.xcassets/Image.imageset/Contents.json new file mode 100644 index 0000000..f8f827e --- /dev/null +++ b/app/Images.xcassets/Image.imageset/Contents.json @@ -0,0 +1,20 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file