Developer Area

root/apps/iphone/superbook/trunk/Classes/LocateThem_ViewController.m @ 418

Revision 418, 17.4 kB (checked in by henri, 5 years ago)

Fixed behavior of cancel button in search bar.
Refactored search text filtering.

RevLine 
[357]1//
2//  LocateThem_AppDelegate.m
3//  LocateThem
4//
5//  Created by Henri Asseily on 8/13/08.
6/*
[363]7 Copyright (c) 2008-2009, Telnic Ltd. All rights reserved.
[357]8 
9 Redistribution and use in source and binary forms, with or without modification,
10 are permitted provided that the following conditions are met:
11 
12 Redistributions of source code must retain the above copyright notice, this list of conditions
13 and the following disclaimer. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the documentation and/or other
15 materials provided with the distribution.
16 Neither the name of the Telnic Ltd. nor the names of its contributors may be used to endorse or
17 promote products derived from this software without specific prior written permission.
18 THIS DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
19 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27//
28
29#import "LocateThem_ViewController.h"
30
31@implementation LocateThem_ViewController
32
33@synthesize friendsTableView;
34@synthesize loadingView;
[400]35@synthesize labelForLoadingView;
[357]36@synthesize telSearch;
[403]37@synthesize progressView;
38@synthesize progressLabel;
39@synthesize logo;
[357]40
41- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
42    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
43        // Custom initialization
44                [MyCLController sharedInstance].delegate = self;
45    }
[382]46        isFirstRun = YES;
[408]47        shouldUpdateLocation = YES;
[357]48    return self;
49}
50
51- (void)viewDidLoad {
52        [super viewDidLoad];
53        if (!self.title) {
54                self.title = @"Contacts";
55               
56                // NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];   
[382]57                FriendsData *sharedFriendsInstance = [FriendsData sharedInstance];
[357]58                sharedFriendsInstance.delegate = self;
59                friendsTableView.dataSource = sharedFriendsInstance;
60               
61                // Do the other setup tasks
62                [telSearch setKeyboardType:UIKeyboardTypeASCIICapable];
63                [telSearch setAutocorrectionType:UITextAutocorrectionTypeNo];
64                keyboardShown = NO;
65                [[NSNotificationCenter defaultCenter] addObserver:self
[414]66                                                                                                 selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil ];
[357]67                [[NSNotificationCenter defaultCenter] addObserver:self
[414]68                                                                                                 selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil ];
69                [[NSNotificationCenter defaultCenter] addObserver:self
[357]70                                                                                                 selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil ];
[382]71                isUpdatingLocation = FALSE;
72                needsFriendsTableRefresh = TRUE;
[357]73        }
74}
75
[403]76- (void)viewWillAppear:(BOOL)animated {
[404]77        [super viewWillAppear:animated];
[357]78        // become the delegate of MyCLController, which could have been taken by a .tel tableview
79        [MyCLController sharedInstance].delegate = self;
80}
81
[382]82- (void)viewDidAppear:(BOOL)animated {
[404]83        [super viewDidAppear:animated];
84        // Must animate the hiding of the navbar and put it in this method
85        // otherwise the frame of the view is reduced and pushed up by the size of the navbar
86        [self.navigationController setNavigationBarHidden:YES animated:YES];
[382]87        if (! isUpdatingLocation) {
88                [[MyCLController sharedInstance].locationManager startUpdatingLocation];
89                isUpdatingLocation = TRUE;
90        }
91
92        if (needsFriendsTableRefresh) {
93                // Now load our friends using a timer, so that the application can finish initializing
94                // and it can display the "loading..." information. Once the friend data has been loaded,
95                // friendsDataDidLoad() is called and we complete building the table.
96                // Don't use a background thread because the AddressBook framework may not be threadsafe
[400]97                [self.labelForLoadingView setText:LocStr(@"Loading AddressBook...")];
[382]98                [self.view addSubview:loadingView];
99                loadingView.center = self.view.center;
[408]100                [[FriendsData sharedInstance] refreshPreferences];
[386]101                [[FriendsData sharedInstance] performSelector:@selector(loadFriendsDataFromAB:) withObject:nil afterDelay:0.1];
[382]102                needsFriendsTableRefresh = FALSE;
103        }
104}
105
[357]106// Delegate for FriendsData that gets called when data has been loaded and we can update the tableview
107- (void)friendsDataDidLoad {
108
109        //[NSThread sleepForTimeInterval:5];    // for testing loadingView only
[382]110        [friendsTableView reloadData];
[357]111        [loadingView removeFromSuperview];
112        if ([friendsTableView numberOfRowsInSection:0] == 0) {
113                [friendsTableView setHidden:NO];
[382]114                instructionsView = [[[UILabel alloc] initWithFrame:friendsTableView.frame] autorelease];
[357]115                instructionsView.numberOfLines = 0;
116                instructionsView.text = LocStr(@"NoContactsWithTel");
117                instructionsView.textAlignment = UITextAlignmentCenter;
118                instructionsView.font = [instructionsView.font fontWithSize:18];
119                instructionsView.alpha = 0.8;
120                [self.view insertSubview:instructionsView aboveSubview:friendsTableView];
121                [instructionsView resignFirstResponder];
122        } else {
123                [friendsTableView setHidden:NO];
[382]124                if (instructionsView != nil) {
125                        [instructionsView removeFromSuperview];
126                }
[357]127        }
128
[382]129        if (isFirstRun) {
130                isFirstRun = NO;
131                // Check to see if the user has disabled location services altogether
132                // In that case, we show an alert and disable the find button and gps switch
133                // TODO: re-enable when find location button is brought back
134//              if ( ! [MyCLController sharedInstance].locationManager.locationServicesEnabled ) {
135//                      BOOL shouldQuit = NO;
136//                     
137//                      CustomAlertView *alertView = [[CustomAlertView alloc] initWithTitle:NSLocalizedString(@"LocationDenied", nil)
138//                                                                                                                              message:nil
139//                                                                                                                         delegate:nil
140//                                                                                                                       shouldQuit:shouldQuit
141//                                                                                                        cancelButtonTitle:nil
142//                                                                                                        otherButtonTitles:NSLocalizedString(@"OK", nil), nil];
143//                      [alertView show];
144//                      [alertView release];
145//              }
[357]146
147
[382]148                //register whenever a change to the underlying dataset happens, so we can update the friends list view
149                [[FriendsData sharedInstance] addObserver:self forKeyPath:@"lastFriendsUpdate"
150                                                                                  options:NSKeyValueObservingOptionNew context:NULL];
[408]151        }
152        if (shouldUpdateLocation) {
153                shouldUpdateLocation = FALSE;
[382]154                NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
155                if ([defaults boolForKey:@"startupLocatePreference"]) {
[403]156                        progressLabel.text = LocStr(@"Searching contact locations");
157                        logo.hidden = YES;
158                        progressLabel.hidden = NO;
159                        progressView.hidden = NO;                       
[382]160                        [self performSelectorInBackground:@selector(updateFriendsListInBackground) withObject:nil];
161                }
[357]162        }
163}
164
165- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
166        // Return YES for supported orientations
167
168        return (interfaceOrientation == UIInterfaceOrientationPortrait);
169}
170
171- (void)didReceiveMemoryWarning {
172    [super didReceiveMemoryWarning]; // Don't release the view
173}
174
175- (void)dealloc {
176        [mapViewController release];
[404]177        [locationRefreshButton release];
178        [locationRefreshingButton release];
[357]179        [super dealloc];
180}
181
182#pragma mark ---- Main Friend Update methods ----
183- (void)updateFriendsListInBackground {
184        // This method is to be called as a new thread and updates the friends list in the background
185        // As it updates, it will request the table view and maybe a status indicator to update in the main thread
186        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
187        mapViewController = [FriendsMapViewController sharedInstance];
188        [[MyCLController sharedInstance] findFriendsTel];
189        [pool release];
190}
191
192- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
193
194    if ([keyPath isEqual:@"lastFriendsUpdate"]) {
195                // Make sure we're in the main thread to update the UI
196                [self performSelectorOnMainThread:@selector(updateFriendsTableViewWithTimestamp:)
197                                                           withObject:[change objectForKey:NSKeyValueChangeNewKey] waitUntilDone:YES];
198                [mapViewController setMarkers:[FriendsData sharedInstance].peopleCurrentList];
[404]199                mapViewController.navigationItem.rightBarButtonItem = locationRefreshButton;
[357]200        }
201        else {
202                [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
203        }
204}
205
206- (void)updateFriendsTableViewWithTimestamp:(NSDate *)theStamp {
207        [[FriendsData sharedInstance] updateDataSet];   
208        [friendsTableView reloadData];
209}
210
211#pragma mark ---- Row and Accessory Click ----
212
213- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
214       
215        // Do the same as if the row is selected
216        [self tableView:tableView didSelectRowAtIndexPath:indexPath];
217
218        return;
219}
220
221- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
222       
[404]223        mapViewController.zoomLevel = 14.0;
[357]224        NSNumber *personId = [[FriendsData sharedInstance] getABRecordIdForIndexPath:indexPath];
225        [tableView deselectRowAtIndexPath:indexPath animated:YES];
226        [self launchNavControllerForTel:nil personId:personId];
227        return;
228}
229
230#pragma mark ---- Action methods ----
231
232- (void)launchNavControllerForTel:(NSString *)aTel personId:(NSNumber *)aPersonId {
[403]233        NaptrViewController *nVC = [[[NaptrViewController alloc] initWithNibName:@"TelView" bundle:[NSBundle mainBundle]] autorelease];
[357]234        if (aPersonId) {
235                [nVC setupWithPersonId:aPersonId];
236        } else if (aTel) {
237                [nVC setupWithTel:aTel];
238        } else {
239                return;
240        }
[404]241        [self.navigationController pushViewController:nVC animated:YES];
[357]242}       
243
[415]244#pragma mark ---- UISearchBar delegate and keyboard methods ----
[357]245
[414]246- (void)keyboardWillShow:(NSNotification*)aNotification {
[357]247        if (keyboardShown)
248                return;
249       
250        NSDictionary* info = [aNotification userInfo];
251    // Get the size of the keyboard.
252    NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
253    CGSize keyboardSize = [aValue CGRectValue].size;
254        // Move the search box up above the keyboard
255        CGRect tSFrame = telSearch.frame;
256        CGRect aboveKeyboard = CGRectMake(tSFrame.origin.x, tSFrame.origin.y - keyboardSize.height,
257                                                                          tSFrame.size.width, tSFrame.size.height);
258        telSearch.barStyle = UIBarStyleBlackOpaque;
259        self.friendsTableView.hidden = YES;
[414]260        [UIView beginAnimations:nil context:NULL];
261        [UIView setAnimationBeginsFromCurrentState:YES];
262        [UIView setAnimationDuration:0.3];      // TODO: Change this to UIKeyboardAnimationDurationUserInfoKey for 3.x
[357]263        telSearch.frame = aboveKeyboard;
[414]264        [UIView commitAnimations];
[357]265        keyboardShown = YES;
266}
267
[414]268- (void)keyboardDidShow:(NSNotification*)aNotification {
269        // If we show the cancel button in the WillShow notification, it is disabled (2.x at least)
270        telSearch.showsCancelButton = YES;
271}
272
[357]273- (void)keyboardWillHide:(NSNotification*)aNotification {
274        if (!keyboardShown)
275                return;
276       
277        NSDictionary* info = [aNotification userInfo];
278    // Get the size of the keyboard.
279    NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
280    CGSize keyboardSize = [aValue CGRectValue].size;
281        // Move the search box back down
282        CGRect tSFrame = telSearch.frame;
283        CGRect noKeyboard = CGRectMake(tSFrame.origin.x, tSFrame.origin.y + keyboardSize.height,
284                                                                          tSFrame.size.width, tSFrame.size.height);
285        telSearch.frame = noKeyboard;
286        telSearch.barStyle = UIBarStyleBlackTranslucent;
287        telSearch.text = @"";
288        telSearch.showsCancelButton = NO;
289        self.friendsTableView.hidden = NO;
290        keyboardShown = NO;
291}
292
293- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
[418]294}
295
296- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
297    [searchBar resignFirstResponder];
298}
299
300- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
301        NSMutableString *qry = [NSMutableString stringWithString:telSearch.text];
302    [searchBar resignFirstResponder];
303        if ([qry length] == 0)
[357]304                return;
[418]305        if ([qry hasPrefix:@"http://"]) {
306                [qry deleteCharactersInRange:NSMakeRange(0, [@"http://" length])];
307        } else if ([qry hasPrefix:@"https://"]) {
308                [qry deleteCharactersInRange:NSMakeRange(0, [@"https://" length])];
[357]309        }
[418]310        if ([qry hasPrefix:@"www."]) {
311                [qry deleteCharactersInRange:NSMakeRange(0, [@"www." length])];
[357]312        }
[418]313        if ([qry hasPrefix:@"+"]) {
[415]314                // Check if it's a phone number, try the sip version
315                BOOL isValidNumber = YES;
316                NSMutableString *enumStr = [NSMutableString stringWithCapacity:30];
317                NSRange prefixR = NSMakeRange(0, 0);
[418]318                for (int i = 1; i < [qry length]; i++) {
319                        unichar aChar = [qry characterAtIndex:i];
[415]320                        if ((aChar < 47) || (aChar > 58)) {     // Not in range of Unicode digits 0-9
321                                isValidNumber = NO;
322                                break;
323                        }
324                        [enumStr replaceCharactersInRange:prefixR withString:[NSString stringWithFormat:@"%c.", aChar]];
325                }
326                if (isValidNumber) {
327                        [enumStr appendString:@"e164.arpa"];
[418]328                        qry = enumStr;
[415]329                }
[418]330        } else if ([qry hasSuffix:@".tel"]) {
[357]331                // .tel domain, do nothing
[418]332        } else if ([qry hasSuffix:@".e164.arpa"]) {
[357]333                // ENUM domain, let's add support for it, why not!
334                // Superbook will be the best ENUM client too! :)
335        } else {
[418]336                qry = [NSString stringWithFormat:@"%@.tel", qry];
[357]337        }
[418]338        [self launchNavControllerForTel:qry personId:nil];
[357]339}
340
341#pragma mark ---- MyCLController delegate methods ----
342
343-(void)gpsUpdate:(CLLocation *)aLoc {
[403]344//      Enable this to display the GPS update info on this controller's view
345//      if (!aLoc) {
346//              [self.labelGpsLastUpdateDate setText:LocStr(@"LatLongUnavailable")];
347//              [self.labelGpsLastUpdateDate setNeedsDisplay];
348//              return;
349//      }
350//      NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
351//      [dateFormatter setDateStyle:NSDateFormatterShortStyle];
352//      [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
353//      [self.labelGpsLastUpdateDate setText:[dateFormatter stringFromDate:aLoc.timestamp]];
354//      [self.labelGpsLastUpdateDate setNeedsDisplay];
355//      [dateFormatter release];
[357]356        if (!mapViewController.view.superview) {
357                // the map view is not active, we can update my location there
358                // Let's not do it for now, it's debatable from a usability perspective
359                mapViewController.initialLoc = aLoc;
360        }
361        return;
362}
363
364-(void)statusUpdate:(NSString *)update {       
365        return;
366}
367
368- (void)updateProgressView:(NSNumber *)val {
369
370        // technique to ensure we're updating the UI in the main thread, otherwise it doesn't work
371        if (![NSThread isMainThread]) {
372                return([self performSelectorOnMainThread:_cmd withObject:val waitUntilDone:YES]);
373        }
374        progressView.progress = [val floatValue];
[403]375        if ([val floatValue] == 1.0f) {
376                progressView.hidden = YES;
377                progressLabel.hidden = YES;
378                logo.hidden = NO;
379        }
[357]380}
381
382-(void)newError:(NSString *)text shouldQuit:(BOOL)shouldQuit {
383
384        NSString *alertMessage;
385        if (shouldQuit) {
386                alertMessage = [NSString stringWithString:NSLocalizedString(@"AppWillQuit", nil)];
387        } else {
388                alertMessage = nil;
389        }
390       
391        CustomAlertView *alertView = [[CustomAlertView alloc] initWithTitle:text
392                                                                                                                                message:alertMessage
393                                                                                                                           delegate:nil
394                                                                                                                         shouldQuit:shouldQuit
395                                                                                                          cancelButtonTitle:nil
396                                                                                                          otherButtonTitles:NSLocalizedString(@"Quit", nil), nil];
397        [alertView show];
398        [alertView release];
399        if (alertMessage)
400                [alertMessage release];
401}       
402
[403]403#pragma mark ------ Buttons
[357]404
[403]405- (IBAction)didPressMapButton:(id)sender {
[404]406        // Load up the shared map view
[403]407        // Make the map view do a background update of the friends and display them
408        mapViewController = [FriendsMapViewController sharedInstance];
409        // Put in a dummy map navcontroller so it looks the same as when we navigate .tel domains
410        mapViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
411                                                                                                                                                                                 target:self
412                                                                                                                                                                                 action:@selector(closeMapNavController)];
[406]413        // Create the buttons to refresh the markers
[404]414        if (!locationRefreshButton) {
[411]415                UIImage *pinrefresh = [UIImage imageNamed:@"button-pin-refresh.png"];
416                locationRefreshButton = [[UIBarButtonItem alloc] initWithImage:pinrefresh style:UIBarButtonItemStyleBordered
417                                                                                                                                target:self
418                                                                                                                                action:@selector(didPressLocationRefreshButton:)];
[404]419        }
420        if (!locationRefreshingButton) {
421                UIActivityIndicatorView *aIV = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] autorelease];
422                [aIV startAnimating];
423                locationRefreshingButton = [[UIBarButtonItem alloc] initWithCustomView:aIV];
424        }
425        mapViewController.navigationItem.rightBarButtonItem = locationRefreshButton;
426       
[403]427        // Do data setup
428        [mapViewController didPressCenterGps:nil];
[404]429        mapViewController.zoomLevel = 6.0;
430        [self.navigationController pushViewController:mapViewController animated:YES];
[357]431}
432
[403]433- (IBAction)didPressSettingsButton:(id)sender {
434        SettingsViewController *sVC = [[[SettingsViewController alloc] initWithNibName:@"SettingsView" bundle:[NSBundle mainBundle]] autorelease];
435        sVC.delegate = self;
436        sVC.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave
437                                                                                                                                                                                 target:sVC
438                                                                                                                                                                                 action:@selector(didPressSave:)];
[404]439        sVC.navigationItem.backBarButtonItem.title = LocStr(@"Cancel");
440        [self.navigationController pushViewController:sVC animated:YES];
[357]441}
442
[404]443- (IBAction)didPressLocationRefreshButton:(id)sender {
444        mapViewController.navigationItem.rightBarButtonItem = locationRefreshingButton;
445        [self performSelectorInBackground:@selector(updateFriendsListInBackground) withObject:nil];
[403]446}
447
448#pragma mark ------ SettingsViewDelegate
[408]449- (void)settingsDidChange {
450        needsFriendsTableRefresh = TRUE;
451        shouldUpdateLocation = TRUE;
452}
453
[403]454- (void)launchTelUrl:(NSString *)url {
455        [self launchNavControllerForTel:url personId:nil];
456}
457
[357]458@end
Note: See TracBrowser for help on using the browser.
Telnic
Search This Site
Partners
Neustar
ICANN
Main site | WHOIS | Sell .tel | FAQ | Archived Site | About Telnic | Contact Us