DatePicker.m 10.4 KB
Newer Older
李晓兵's avatar
李晓兵 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
/*
 
 Phonegap DatePicker Plugin for using Cordova 3 and iOS 7
 https://github.com/sectore/phonegap3-ios-datepicker-plugin
 
 Based on a previous plugin version by Greg Allen and Sam de Freyssinet.
 
 Rewrite by Jens Krause (www.websector.de)
 
 MIT Licensed
 
 */

#import "DatePicker.h"
#import <Cordova/CDV.h>

@interface DatePicker ()

@property (nonatomic) UIPopoverController *datePickerPopover;

@property (nonatomic) IBOutlet UIView* datePickerContainer;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *datePickerComponentsContainerVSpace;
@property (nonatomic) IBOutlet UIView* datePickerComponentsContainer;
@property (nonatomic) IBOutlet UIButton *cancelButton;
@property (nonatomic) IBOutlet UIButton *doneButton;
@property (nonatomic) IBOutlet UIDatePicker *datePicker;

@end

@implementation DatePicker

#define isIPhone (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define ANIMATION_DURATION 0.3

#pragma mark - UIDatePicker

- (void)show:(CDVInvokedUrlCommand*)command {
  NSMutableDictionary *options = [command argumentAtIndex:0];
  //if (isIPhone) {
    [self showForPhone: options];
  //} else {
 //   [self showForPad: options];
 // }
}

- (BOOL)showForPhone:(NSMutableDictionary *)options {
  if(!self.datePickerContainer){
    [[NSBundle mainBundle] loadNibNamed:@"DatePicker" owner:self options:nil];
  } else {
      self.datePickerContainer.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
  }
  
  [self updateDatePicker:options];
  [self updateCancelButton:options];
  [self updateDoneButton:options];
  
  UIInterfaceOrientation deviceOrientation = [UIApplication sharedApplication].statusBarOrientation;
  
  CGFloat width;
  CGFloat height;
  
  [self.datePickerContainer removeFromSuperview];
  
  if(UIInterfaceOrientationIsLandscape(deviceOrientation)){
    width = self.webView.superview.frame.size.width;
    height= self.webView.superview.frame.size.height;
  } else {
    width = self.webView.superview.frame.size.width;
    height= self.webView.superview.frame.size.height;
  }

  NSLog(@"%.2f", width);
  NSLog(@"%.2f", height);

  self.datePickerContainer.frame = CGRectMake(0, 0, width, height);
  
  [self.webView.superview addSubview: self.datePickerContainer];
  [self.datePickerContainer layoutIfNeeded];

  CGRect frame = self.datePickerComponentsContainer.frame;
  self.datePickerComponentsContainer.frame = CGRectOffset(frame,
                                                          0,
                                                          frame.size.height );
  
  
  self.datePickerContainer.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0];
  
  [UIView animateWithDuration:ANIMATION_DURATION
                        delay:0
                      options:UIViewAnimationOptionCurveEaseOut
                   animations:^{
    self.datePickerComponentsContainer.frame = frame;
    self.datePickerContainer.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];

  } completion:^(BOOL finished) {
    
  }];
  
  return true;
}

- (BOOL)showForPad:(NSMutableDictionary *)options {
    self.datePickerPopover = [self createPopover:options];
    return true;
}

- (void)hide {
  //if (isIPhone) {
    CGRect frame = CGRectOffset(self.datePickerComponentsContainer.frame,
                                0,
                                self.datePickerComponentsContainer.frame.size.height);
    
    [UIView animateWithDuration:ANIMATION_DURATION
                          delay:0
                        options:UIViewAnimationOptionCurveEaseOut
                     animations:^{
                       self.datePickerComponentsContainer.frame = frame;
                       self.datePickerContainer.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0];
                       
                     } completion:^(BOOL finished) {
                       [self.datePickerContainer removeFromSuperview];
                     }];

 // } else {
 //   [self.datePickerPopover dismissPopoverAnimated:YES];
 // }
}

#pragma mark - Actions
- (IBAction)doneAction:(id)sender {
  [self jsDateSelected];
  [self hide];
}
  
- (IBAction)cancelAction:(id)sender {
  [self jsCancel];
  [self hide];
}


- (void)dateChangedAction:(id)sender {
  [self jsDateSelected];
}

#pragma mark - JS API

- (void)jsCancel {
  NSLog(@"JS Cancel is going to be executed");
  NSString *jsCallback = @"datePicker._dateSelectionCanceled();";
    
  [self.commandDelegate evalJs:jsCallback];
}

- (void)jsDateSelected {
  NSTimeInterval seconds = [self.datePicker.date timeIntervalSince1970];
  NSString *jsCallback = [NSString stringWithFormat:@"datePicker._dateSelected(\"%f\");", seconds];
    
  [self.commandDelegate evalJs:jsCallback];
}


#pragma mark - UIPopoverControllerDelegate methods

- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
  [self jsDateSelected];
}

#pragma mark - Factory methods

- (UIPopoverController *)createPopover:(NSMutableDictionary *)options {
  
  CGFloat pickerViewWidth = 320.0f;
  CGFloat pickerViewHeight = 216.0f;
  UIView *datePickerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, pickerViewWidth, pickerViewHeight)];
  
  CGRect frame = CGRectMake(0, 0, 0, 0);
  // in iOS8, UIDatePicker couldn't be shared in multi UIViews, it will cause crash. so   create new UIDatePicker instance every time
  if (! self.datePicker || [[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0){
      self.datePicker = [self createDatePicker:options frame:frame];
      [self.datePicker addTarget:self action:@selector(dateChangedAction:) forControlEvents:UIControlEventValueChanged];
  }
  [self updateDatePicker:options];
  [datePickerView addSubview:self.datePicker];
  
  UIViewController *datePickerViewController = [[UIViewController alloc]init];
  datePickerViewController.view = datePickerView;
  
  UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:datePickerViewController];
  popover.delegate = self;
  [popover setPopoverContentSize:CGSizeMake(pickerViewWidth, pickerViewHeight) animated:NO];
  
  CGFloat x = [[options objectForKey:@"x"] intValue];
  CGFloat y = [[options objectForKey:@"y"] intValue];
  UIPopoverArrowDirection arrowDirection = [[options objectForKey:@"popoverArrowDirection"] intValue];
  
  CGRect anchor = CGRectMake(x, y, 1, 1);
  [popover presentPopoverFromRect:anchor inView:self.webView.superview  permittedArrowDirections:arrowDirection animated:YES];
  
  return popover;
}

- (UIDatePicker *)createDatePicker:(NSMutableDictionary *)options frame:(CGRect)frame {
  UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:frame];
  return datePicker;
}

#define DATETIME_FORMAT @"yyyy-MM-dd'T'HH:mm:ss'Z'"

- (void)updateDatePicker:(NSMutableDictionary *)options {
  NSDateFormatter *formatter = [self createISODateFormatter: DATETIME_FORMAT timezone:[NSTimeZone defaultTimeZone]];
  NSString *mode = [options objectForKey:@"mode"];
  NSString *dateString = [options objectForKey:@"date"];
  BOOL allowOldDates = ([[options objectForKey:@"allowOldDates"] intValue] == 0) ? NO : YES;
  BOOL allowFutureDates = ([[options objectForKey:@"allowFutureDates"] intValue] == 0) ? NO : YES;
  NSString *minDateString = [options objectForKey:@"minDate"];
  NSString *maxDateString = [options objectForKey:@"maxDate"];
  NSString *minuteIntervalString = [options objectForKey:@"minuteInterval"];
  NSInteger minuteInterval = [minuteIntervalString integerValue];
  NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:[options objectForKey:@"locale"]];

  
  if (allowOldDates) {
    self.datePicker.minimumDate = nil;
  }
  else {
    self.datePicker.minimumDate = [NSDate date];
  }
  
  if(minDateString && minDateString.length > 0){
    self.datePicker.minimumDate = [formatter dateFromString:minDateString];
  }
  
  if (allowFutureDates) {
    self.datePicker.maximumDate = nil;
  }
  else {
    self.datePicker.maximumDate = [NSDate date];
  }
  
  if(maxDateString && maxDateString.length > 0){
    self.datePicker.maximumDate = [formatter dateFromString:maxDateString];
  }
  
  self.datePicker.date = [formatter dateFromString:dateString];
  
  if ([mode isEqualToString:@"date"]) {
    self.datePicker.datePickerMode = UIDatePickerModeDate;
  }
  else if ([mode isEqualToString:@"time"]) {
    self.datePicker.datePickerMode = UIDatePickerModeTime;
  } else {
    self.datePicker.datePickerMode = UIDatePickerModeDateAndTime;
  }

  if (minuteInterval) {
    self.datePicker.minuteInterval = minuteInterval;
  }

  if (locale) {
    [self.datePicker setLocale:locale];
  }
}

- (NSDateFormatter *)createISODateFormatter:(NSString *)format timezone:(NSTimeZone *)timezone {
  NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  // Locale needed to avoid formatter bug on phones set to 12-hour
  // time to avoid it adding AM/PM to the string we supply
  // See: http://stackoverflow.com/questions/6613110/what-is-the-best-way-to-deal-with-the-nsdateformatter-locale-feature
  NSLocale *loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
  [dateFormatter setLocale: loc];
  [dateFormatter setTimeZone:timezone];
  [dateFormatter setDateFormat:format];
  
  return dateFormatter;
}

- (void)updateCancelButton:(NSMutableDictionary *)options {

  NSString *label = [options objectForKey:@"cancelButtonLabel"];
  [self.cancelButton setTitle:label forState:UIControlStateNormal];
  
  NSString *tintColorHex = [options objectForKey:@"cancelButtonColor"];
  self.cancelButton.tintColor = [self colorFromHexString: tintColorHex];
  
}

- (void)updateDoneButton:(NSMutableDictionary *)options {
  
  NSString *label = [options objectForKey:@"doneButtonLabel"];
  [self.doneButton setTitle:label forState:UIControlStateNormal];
  
  NSString *tintColorHex = [options objectForKey:@"doneButtonColor"];
  [self.doneButton setTintColor: [self colorFromHexString: tintColorHex]];
  
}


#pragma mark - Utilities

/*! Converts a hex string into UIColor
 It based on http://stackoverflow.com/questions/1560081/how-can-i-create-a-uicolor-from-a-hex-string
 
  @param hexString The hex string which has to be converted
 */
- (UIColor *)colorFromHexString:(NSString *)hexString {
  unsigned rgbValue = 0;
  NSScanner *scanner = [NSScanner scannerWithString:hexString];
  [scanner setScanLocation:1]; // bypass '#' character
  [scanner scanHexInt:&rgbValue];
  return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0];
}

@end