/** * Copyright (c) 2015-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #import "RNDatePickerManager.h" #import #import "RCTConvert.h" #import "DatePicker.h" @implementation RCTConvert(UIDatePicker) RCT_ENUM_CONVERTER(UIDatePickerMode, (@{ @"time": @(UIDatePickerModeTime), @"date": @(UIDatePickerModeDate), @"datetime": @(UIDatePickerModeDateAndTime), @"countdown": @(UIDatePickerModeCountDownTimer), // not supported yet }), UIDatePickerModeTime, integerValue) @end @implementation RNDatePickerManager RCT_EXPORT_MODULE() RCT_EXPORT_METHOD(addListener : (NSString *)eventName) { // Keep: Required for RN built in Event Emitter Calls. } RCT_EXPORT_METHOD(removeListeners : (NSInteger)count) { // Keep: Required for RN built in Event Emitter Calls. } - (UIView *)view { return [DatePicker new]; } RCT_EXPORT_VIEW_PROPERTY(date, NSDate) RCT_EXPORT_VIEW_PROPERTY(locale, NSLocale) RCT_EXPORT_VIEW_PROPERTY(minimumDate, NSDate) RCT_EXPORT_VIEW_PROPERTY(maximumDate, NSDate) RCT_EXPORT_VIEW_PROPERTY(minuteInterval, NSInteger) RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock) RCT_REMAP_VIEW_PROPERTY(mode, datePickerMode, UIDatePickerMode) RCT_REMAP_VIEW_PROPERTY(timeZoneOffsetInMinutes, timeZone, NSTimeZone) RCT_CUSTOM_VIEW_PROPERTY(textColor, NSString, DatePicker) { [view setTextColorProp:[RCTConvert NSString:json]]; } RCT_EXPORT_METHOD(openPicker:(NSDictionary *) props onConfirm:(RCTResponseSenderBlock) onConfirm onCancel:(RCTResponseSenderBlock) onCancel) { dispatch_async(dispatch_get_main_queue(), ^{ bool iPad = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad; UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController; CGRect rootBounds = rootViewController.view.bounds; NSString * title = [RCTConvert NSString:[props objectForKey:@"title"]]; title = [title isEqualToString:@""] ? nil : title; NSString * confirmText = [RCTConvert NSString:[props objectForKey:@"confirmText"]]; NSString * cancelText = [RCTConvert NSString:[props objectForKey:@"cancelText"]]; DatePicker* picker = [[DatePicker alloc] init]; UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet]; UIView * alertView = alertController.view; // height int heightPx = iPad ? (title ? 300 : 260) : (title ? 370 : 340); NSLayoutConstraint *heigth = [NSLayoutConstraint constraintWithItem:alertView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:heightPx]; [alertView addConstraint:heigth]; CGRect bounds = picker.bounds; // picker width int widthPx = iPad ? 320 : alertController.view.bounds.size.width - 15; bounds.size.width = widthPx; // top padding bounds.origin.y += iPad ? (title ? 20: 5) : (title ? 30 : 10); [picker setFrame: bounds]; NSDate * _Nonnull date = [RCTConvert NSDate:[props objectForKey:@"date"]]; [picker setDate:date]; NSDate * minimumDate = [RCTConvert NSDate:[props objectForKey:@"minimumDate"]]; if(minimumDate) [picker setMinimumDate:minimumDate]; NSDate * maximumDate = [RCTConvert NSDate:[props objectForKey:@"maximumDate"]]; if(maximumDate) [picker setMaximumDate:maximumDate]; NSString * textColor = [RCTConvert NSString:[props objectForKey:@"textColor"]]; if(textColor) [picker setTextColorProp:textColor]; UIDatePickerMode mode = [RCTConvert UIDatePickerMode:[props objectForKey:@"mode"]]; [picker setDatePickerMode:mode]; NSLocale * locale = [RCTConvert NSLocale:[props objectForKey:@"locale"]]; if(locale) [picker setLocale:locale]; int minuteInterval = [RCTConvert int:[props objectForKey:@"minuteInterval"]]; [picker setMinuteInterval:minuteInterval]; NSString * timeZoneProp = [props valueForKey:@"timeZoneOffsetInMinutes"]; if(timeZoneProp){ [picker setTimeZone:[RCTConvert NSTimeZone:timeZoneProp]]; } if(@available(iOS 13, *)) { NSString * _Nonnull theme = [RCTConvert NSString:[props objectForKey:@"theme"]]; if ([theme isEqualToString:@"light"]) { alertController.overrideUserInterfaceStyle = UIUserInterfaceStyleLight; } else if ([theme isEqualToString:@"dark"]) { alertController.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; } else { alertController.overrideUserInterfaceStyle = UIUserInterfaceStyleUnspecified; } } [alertView addSubview:picker]; UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:confirmText style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { onConfirm(@[@{ @"timestamp": @(picker.date.timeIntervalSince1970 * 1000.0) }]); }]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelText style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { onCancel(@[]); }]; [alertController addAction:cancelAction]; [alertController addAction:confirmAction]; if (@available(iOS 9.0, *)) { alertController.preferredAction = confirmAction; } // ipad needs to display the picker in a popover if (iPad) { UIPopoverPresentationController *popPresenter = [alertController popoverPresentationController]; popPresenter.sourceRect = CGRectMake(CGRectGetMidX(rootBounds), CGRectGetMidY(rootBounds),0,0); popPresenter.sourceView = rootViewController.view; popPresenter.presentingViewController.preferredContentSize = CGSizeMake(widthPx, heightPx); [popPresenter setPermittedArrowDirections: (UIPopoverArrowDirection) 0]; } // Finding the top view controller which is neccessary to be able to show the picker from within modal UIViewController *topViewController = rootViewController; while (topViewController.presentedViewController){ topViewController = topViewController.presentedViewController; } [topViewController presentViewController:alertController animated:YES completion:nil]; }); } @end