// // FlipSideViewController.m // Geopher // // Created by Jeremy on 3/8/11. // Copyright 2011 Stone Software. All rights reserved. // #import "FlipSideViewController.h" #import "Calculations.h" #import "LocatorModel.h" #import "textConverter.h" #import "MapViewController.h" #import "IASKSpecifier.h" #import "GeopherAppDelegate.h" @implementation FlipSideViewController @synthesize latitudeTextView; @synthesize longitudeTextView; @synthesize webView; @synthesize longitudeTextLabel; @synthesize latitudeTextLabel; @synthesize infoButton; @synthesize backButton; @synthesize helpButton; @synthesize stopButton; @synthesize settingsButton; @synthesize updateWaypointString; @synthesize cacheIDTextView; @synthesize waypointLabel; @synthesize logButton; @synthesize mapController; @synthesize appSettingsViewController; #pragma mark - #pragma mark IASKAppSettingsViewControllerDelegate protocol - (void)settingsViewControllerDidEnd:(IASKAppSettingsViewController*)sender { [self dismissModalViewControllerAnimated:YES]; // your code here to reconfigure the app for changed settings [(GeopherAppDelegate*)[[UIApplication sharedApplication] delegate] loadPersistentData]; } - (IASKAppSettingsViewController*)appSettingsViewController { if (!appSettingsViewController) { appSettingsViewController = [[IASKAppSettingsViewController alloc] initWithNibName:@"IASKAppSettingsView" bundle:nil]; appSettingsViewController.delegate = self; } return appSettingsViewController; } #pragma mark - #pragma mark TE Field handling - (IBAction)editWaypointText { cacheIDTextView.text = [NSString stringWithString:@"GC"]; } - (IBAction)waypointEditingDidEnd { if ([[cacheIDTextView text] length] > 5) [logButton setEnabled:YES]; else [logButton setEnabled:NO]; } - (void)textFieldDidBeginEditing:(UITextField *)textField { if (textField == latitudeTextView) { NSString* tempStr = [Calculations degreesToHourMinuteDecimal:[LocatorModel sharedInstance].currentLocation.coordinate.latitude isLatitude:YES]; NSCharacterSet* set = [NSCharacterSet whitespaceCharacterSet]; NSRange range = [tempStr rangeOfCharacterFromSet:set options:NSBackwardsSearch]; textField.text = [tempStr substringToIndex: range.location + 1]; } else if (textField == longitudeTextView) { NSString* tempStr = [Calculations degreesToHourMinuteDecimal:[LocatorModel sharedInstance].currentLocation.coordinate.longitude isLatitude:NO]; NSCharacterSet* set = [NSCharacterSet whitespaceCharacterSet]; NSRange range = [tempStr rangeOfCharacterFromSet:set options:NSBackwardsSearch]; textField.text = [tempStr substringToIndex: range.location + 1]; } } - (BOOL)textFieldDidEndEditing:(UITextField *)theTextField { textConverter* converter = [[[textConverter alloc] initWithString:[theTextField text]] autorelease]; double lon = [LocatorModel sharedInstance].targetLocation.coordinate.longitude; double lat = [LocatorModel sharedInstance].targetLocation.coordinate.latitude; double conv = 0.0; BOOL newVal = [converter decimalFromString:&conv]; // make sure conv is initialized to a good value if we are going forward. if (theTextField == latitudeTextView) { if (newVal) lat = conv; // use the new val else conv = lat; // keep the old val newVal = YES; } else if(theTextField == longitudeTextView) { if (newVal) lon = conv; // use new val else conv = lon; // use old val newVal = YES; } else { newVal = NO; } // if we have something to fill in from lat/lon if (newVal) { // bounds check to make sure we are ok. If not, don't change the values and show the user the current value. if (lat > 90 || lat < -90) { conv = [LocatorModel sharedInstance].targetLocation.coordinate.latitude; } else if (lon > 180 || lon < -180) { conv = [LocatorModel sharedInstance].targetLocation.coordinate.longitude; } else // we are good, change the values { // keep the obtained value. CLLocation* loc = [[CLLocation alloc] initWithLatitude:lat longitude:lon]; [[LocatorModel sharedInstance] setTargetLocation: loc]; [[LocatorModel sharedInstance] update]; [loc release]; } // revamp the target fields with the parsed value. [self updateTargetFields]; } // Set the target values to valid or invalid. NSString* latText = [NSString stringWithString:latitudeTextView.text]; NSString* lonText = [NSString stringWithString:longitudeTextView.text]; if ([latText length] < 1 && [lonText length] < 1 ) [[LocatorModel sharedInstance] setHasValidTarget:NO]; else if ( [latText length] > 0 && [lonText length] > 0 ) [[LocatorModel sharedInstance] setHasValidTarget:YES]; return YES; } - (BOOL)textFieldShouldReturn:(UITextField *)theTextField { // When the user presses return, take focus away from the text field so that the keyboard is dismissed. [theTextField resignFirstResponder]; return YES; } #pragma mark - #pragma mark URL/web Handling - (IBAction)doFAQButton { NSString* path = [[NSBundle mainBundle] pathForResource:@"FAQ" ofType:@"html"]; if (path != nil) [self loadURL:[NSURL URLWithString:[path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; // #define kGeopherLiteFAQString @"http://geopherlite.blogspot.com/2008/07/geopher-lite-faq.html" // [[UIApplication sharedApplication] openURL:[NSURL URLWithString:kGeopherLiteFAQString]]; } - (IBAction) logCache:(id)sender { if ([[cacheIDTextView text] length] > 2) { NSString *webLink = [NSString stringWithFormat:@"http://www.geocaching.com/seek/%@wp=%@", kLogString, [NSString stringWithString:[cacheIDTextView text]]]; // [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:webLink]]]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:webLink]]; } } - (void) loadURL:(NSURL*)url { webView.dataDetectorTypes = UIDataDetectorTypeLink; [webView loadRequest:[NSURLRequest requestWithURL:url]]; } - (IBAction) loadInternalURL:(id)sender { webView.scalesPageToFit = YES; if (NetworkIsReachable() == YES) { double lat = [LocatorModel sharedInstance].currentLocation.coordinate.latitude; double lon = [LocatorModel sharedInstance].currentLocation.coordinate.longitude; NSString* str = kEmptyText; if (YES == [[NSUserDefaults standardUserDefaults] boolForKey:kHideFoundCaches]) str = kExcludeFoundCaches; NSString *webLink = [NSString stringWithFormat:@"http://www.geocaching.com/seek/nearest.aspx?%@%f&%@%f%@", @"lat=", lat, @"lon=", lon, str]; // CFLocaleRef userLocaleRef = CFLocaleCopyCurrent(); // CFStringRef stringRef = CFLocaleGetValue(userLocaleRef, kCFLocaleCountryCode); // str = (NSString*)stringRef; // toll-free bridged // looks like geocaching.hu is not an affiliate of geocaching.com and may have different URL schemes and rules. Sent them an email about // using their site with Geopher Lite. Sounds like they may be interested in helping out, but haven't heard any details back from them. [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:webLink]]]; } else { NSString* path = [[NSBundle mainBundle] pathForResource:@"SearchInternetError" ofType:@"html"]; if (path != nil) [self loadURL:[NSURL URLWithString:[path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; } } #pragma mark - //- (void) goToLogin //{ // [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.geocaching.com/login/default.aspx?RESETCOMPLETE=Y"]]]; //} // // //- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType //{ // if (navigationType == UIWebViewNavigationTypeFormSubmitted) // && //// [[[request URL] resourceSpecifier] rangeOfString:@""]) // { // NSLog(@"URL is: %@", [[request URL] absoluteURL]); // // https://www.geocaching.com/login/default.aspx?RESET=Y&redir=%2fseek%2flog.aspx%3fID%3d1224192 // // // https://www.geocaching.com/login/default.aspx?RESETCOMPLETE=Y // [self goToLogin]; // // return NO; // } // // return YES; //} - (void)webViewDidStartLoad:(UIWebView *)webView { [chasingArrows startAnimating]; [stopButton setEnabled:YES]; } - (void)webViewDidFinishLoad:(UIWebView *)inWebView { [stopButton setEnabled:NO]; if ([inWebView canGoBack] == YES) [backButton setEnabled:YES]; else [backButton setEnabled:NO]; [chasingArrows stopAnimating]; } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { // trying to download the GPX or LOC files gives this error: WebKitErrorFrameLoadInterruptedByPolicyChange Is there anything that can be done about it? NSLog(@"%@", error); [chasingArrows stopAnimating]; } - (BOOL) ArchiveWebView { // static BOOL initialized = NO; BOOL retVal = NO; // CURL *curl; // CURLcode res; // // if (!initialized) // { // curl = curl_easy_init(); // initialized = YES; // } // return retVal; } - (BOOL) LoadArchivedWebpage { BOOL retVal = NO; // NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // NSString *documentsDirectory = [paths objectAtIndex:0]; // NSString* webArchive = [documentsDirectory stringByAppendingPathComponent:kAppWebArchiveFilename]; // // // web archive, if it exists // UIWebView* webView = nil; // webView = [NSKeyedUnarchiver unarchiveObjectWithFile:webArchive]; // // if (webView != nil) // { //// webView.delegate = ((FlipsideView*)self.view).webView.delegate; // ((FlipsideView*)self.view).webView = webView; // [((FlipsideView*)self.view).webView setDelegate:self]; // retVal = YES; // } return retVal; } #pragma mark - #pragma mark UI rearranging - (void) updateTargetFields { // revamp the changed text field with the parsed value. latitudeTextView.text = [Calculations degreesToHourMinuteDecimal:[LocatorModel sharedInstance].targetLocation.coordinate.latitude isLatitude:YES]; longitudeTextView.text = [Calculations degreesToHourMinuteDecimal:[LocatorModel sharedInstance].targetLocation.coordinate.longitude isLatitude:NO]; } - (void) hideLatLon:(BOOL)yesOrNo { if (yesOrNo == YES) { latitudeTextView.frame = CGRectMake(-100, -100, latitudeTextView.frame.size.width, latitudeTextView.frame.size.height); longitudeTextView.frame = CGRectMake(-100, -100, latitudeTextView.frame.size.width, latitudeTextView.frame.size.height); latitudeTextLabel.frame = CGRectMake(-100, -100, latitudeTextView.frame.size.width, latitudeTextView.frame.size.height); longitudeTextLabel.frame = CGRectMake(-100, -100, latitudeTextView.frame.size.width, latitudeTextView.frame.size.height); } else { latitudeTextView.frame = CGRectMake(47, 49, latitudeTextView.frame.size.width, latitudeTextView.frame.size.height); longitudeTextView.frame = CGRectMake(209, 49, latitudeTextView.frame.size.width, latitudeTextView.frame.size.height); latitudeTextLabel.frame = CGRectMake(7, 49, latitudeTextView.frame.size.width, latitudeTextView.frame.size.height); longitudeTextLabel.frame = CGRectMake(157, 49, latitudeTextView.frame.size.width, latitudeTextView.frame.size.height); } } - (void) hideControlsExcept:(int) stage { static BOOL initialized = NO; // this really should be done elsewhere, but I don't have time now to track down exactly where and I know this will work. if (NO == initialized) { [logButton setTitleColor:[UIColor grayColor] forState:UIControlStateDisabled]; [stopButton setTitleColor:[UIColor grayColor] forState:UIControlStateDisabled]; [backButton setTitleColor:[UIColor grayColor] forState:UIControlStateDisabled]; initialized = YES; } if (stage == latLonStage) [self hideLatLon:NO]; else [self hideLatLon:YES]; if (stage == waypointStage) { int one = 320 - 9 - logButton.frame.size.width - 33; int two = one - 15 - cacheIDTextView.frame.size.width; int three = two - 10 - waypointLabel.frame.size.width; logButton.frame = CGRectMake(one, 49, logButton.frame.size.width, logButton.frame.size.height); waypointLabel.frame = CGRectMake(three, 54, waypointLabel.frame.size.width, waypointLabel.frame.size.height); cacheIDTextView.frame = CGRectMake(two, 49, cacheIDTextView.frame.size.width, cacheIDTextView.frame.size.height); } else { logButton.frame = CGRectMake(-100, -100, logButton.frame.size.width, logButton.frame.size.height); waypointLabel.frame = CGRectMake(-100, -100, waypointLabel.frame.size.width, waypointLabel.frame.size.height); cacheIDTextView.frame = CGRectMake(-100, -100, cacheIDTextView.frame.size.width, cacheIDTextView.frame.size.height); } if (stage == browseButtonStage) { float margin = [[UIScreen mainScreen] bounds].size.width - stopButton.frame.size.width - backButton.frame.size.width; float halfMargin = margin / 2.0f; stopButton.frame = CGRectMake(halfMargin - 9, 49, stopButton.frame.size.width, stopButton.frame.size.height); backButton.frame = CGRectMake(halfMargin + stopButton.frame.size.width + 9, 49, backButton.frame.size.width, backButton.frame.size.height); } else { stopButton.frame = CGRectMake(-100, -100, stopButton.frame.size.width, stopButton.frame.size.height); backButton.frame = CGRectMake(-100, -100, backButton.frame.size.width, backButton.frame.size.height); } if (stage == settingsStage) { float margin = [[UIScreen mainScreen] bounds].size.width - settingsButton.frame.size.width - helpButton.frame.size.width; float halfMargin = margin / 2.0f; helpButton.frame = CGRectMake(halfMargin - 9, 49, helpButton.frame.size.width, helpButton.frame.size.height); settingsButton.frame = CGRectMake(halfMargin + helpButton.frame.size.width + 9, 49, settingsButton.frame.size.width, settingsButton.frame.size.height); } else { helpButton.frame = CGRectMake(-100, -100, helpButton.frame.size.width, helpButton.frame.size.height); settingsButton.frame = CGRectMake(-100, -100, settingsButton.frame.size.width, settingsButton.frame.size.height); } // additional stages can go here as needed. } #pragma mark - #pragma mark Misc Actions - (void) rotateActions { // auto-increment the which button stage is showing and then display them below. mButtonStage++; if (mButtonStage >= totalStages) mButtonStage = mButtonStage % totalStages; [self hideControlsExcept:mButtonStage]; } - (void) goBack { [self dismissModalViewControllerAnimated:YES]; } - (IBAction)displaySettings { UINavigationController *aNavController = [[UINavigationController alloc] initWithRootViewController:self.appSettingsViewController]; //[viewController setShowCreditsFooter:NO]; // Uncomment to not display InAppSettingsKit credits for creators. // But we encourage you not to uncomment. Thank you! self.appSettingsViewController.showDoneButton = YES; [self presentModalViewController:aNavController animated:YES]; [aNavController release]; } - (IBAction)doGoogleMaps { if (NetworkIsReachable() == YES) { BOOL useInternalMaps = [[NSUserDefaults standardUserDefaults] boolForKey:kUseInternalMapsKey]; if (NO == useInternalMaps) { // example URL that works: NSMutableString* url = [NSMutableString stringWithFormat: @"http://maps.google.com/maps?q=%@+%@", [[LocatorModel sharedInstance] targetLatitudeText:NO], [[LocatorModel sharedInstance] targetLongitudeText:NO]]; // http://maps.google.com/maps?saddr=N+40+5.457+W+111+37.008&daddr=N+40+5.332+W+111+35.918 // change the spaces to be + signs. [url replaceOccurrencesOfString:@" " withString:@"+" options:NSBackwardsSearch range:NSMakeRange(0, [url length])]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]]; } else { // load our own map view mapController = [[MapViewController alloc] initWithNibName:@"MapView" bundle:nil]; [self presentModalViewController:mapController animated:YES]; } } else { NSString* path = [[NSBundle mainBundle] pathForResource:@"MapInternetError" ofType:@"html"]; if (path != nil) [self loadURL:[NSURL URLWithString:[path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; } } #pragma mark - // The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad. /* - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization. } return self; } */ - (void)viewDidLoad { mButtonStage = 0; self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor]; if (NO == [self LoadArchivedWebpage]) { if ([[NSUserDefaults standardUserDefaults] boolForKey:kAutoLoadSearchKey] == YES) { [self loadInternalURL:self.view]; } else { NSString* path = [[NSBundle mainBundle] pathForResource:@"Search" ofType:@"html"]; if (path != nil) [self loadURL:[NSURL URLWithString:[path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; } } // disable back and stop buttons [backButton setEnabled:NO]; [stopButton setEnabled:NO]; if ([LocatorModel sharedInstance].hasValidTarget == YES) [self updateTargetFields]; if (updateWaypointString != nil) { cacheIDTextView.text = updateWaypointString; [updateWaypointString release]; updateWaypointString = nil; } // disable log button as needed. Needs to happen after we re-set the log text. [self waypointEditingDidEnd]; lastURL = nil; } - (void)dealloc { if (updateWaypointString != nil) [updateWaypointString release], updateWaypointString = nil; [latitudeTextView dealloc]; [longitudeTextView dealloc]; [latitudeTextLabel dealloc]; [longitudeTextLabel dealloc]; [webView dealloc]; [infoButton release]; [backButton release]; [helpButton release]; [stopButton release]; [settingsButton release]; [updateWaypointString release]; [cacheIDTextView release]; [waypointLabel release]; [logButton release]; [mapController release]; [appSettingsViewController release], appSettingsViewController = nil; [super dealloc]; } @end