| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "content/browser/date_time_chooser/ios/date_time_chooser_view_controller.h" |
| |
| #import "base/notreached.h" |
| #import "content/browser/date_time_chooser/ios/date_time_chooser_util.h" |
| #import "third_party/blink/public/mojom/choosers/date_time_chooser.mojom.h" |
| #import "ui/base/ime/text_input_type.h" |
| |
| const CGFloat kToolBarHeight = 44; |
| |
| @interface DateTimeChooserViewController () |
| // The type to set the date picker mode |
| @property(nonatomic, assign) ui::TextInputType type; |
| // Initalized time for the date picker. For TEXT_INPUT_TYPE_MONTH, it is the |
| // number of month. Otherwise, it's in milliseconds. |
| @property(nonatomic, assign) NSInteger initTime; |
| // Updated with the selected date in the date picker |
| @property(nonatomic, assign) NSDate* selectedDate; |
| @end |
| |
| @implementation DateTimeChooserViewController |
| |
| - (instancetype)initWithConfigs:(DateTimeDialogValuePtr)configs { |
| if (!(self = [super init])) { |
| return nil; |
| } |
| _delegate = nil; |
| _type = configs->dialog_type; |
| _initTime = configs->dialog_value; |
| // TODO(crbug.com/1461947): Handle other values in `configs` such as minimum |
| // or maximum. |
| return self; |
| } |
| |
| - (UIDatePicker*)createUIDatePicker { |
| UIDatePicker* datePicker = [[UIDatePicker alloc] init]; |
| UIDatePickerMode mode = UIDatePickerModeDate; |
| UIDatePickerStyle style = UIDatePickerStyleAutomatic; |
| NSDate* initValue; |
| switch (self.type) { |
| case ui::TextInputType::TEXT_INPUT_TYPE_DATE: |
| initValue = [NSDate dateWithTimeIntervalSince1970:self.initTime / 1000]; |
| mode = UIDatePickerModeDate; |
| style = UIDatePickerStyleInline; |
| break; |
| case ui::TextInputType::TEXT_INPUT_TYPE_TIME: |
| initValue = [NSDate dateWithTimeIntervalSince1970:self.initTime / 1000]; |
| mode = UIDatePickerModeTime; |
| style = UIDatePickerStyleWheels; |
| break; |
| case ui::TextInputType::TEXT_INPUT_TYPE_DATE_TIME: |
| case ui::TextInputType::TEXT_INPUT_TYPE_DATE_TIME_LOCAL: |
| initValue = [NSDate dateWithTimeIntervalSince1970:self.initTime / 1000]; |
| mode = UIDatePickerModeDateAndTime; |
| style = UIDatePickerStyleInline; |
| break; |
| case ui::TextInputType::TEXT_INPUT_TYPE_MONTH: |
| initValue = GetDateFromNumberOfMonths(self.initTime); |
| mode = UIDatePickerModeDate; |
| style = UIDatePickerStyleWheels; |
| break; |
| case ui::TextInputType::TEXT_INPUT_TYPE_WEEK: |
| initValue = [NSDate dateWithTimeIntervalSince1970:self.initTime / 1000]; |
| // UIDatePicker doesn't have a mode for the week number. So, it opens |
| // UIDatePicker with UIDatePickerModeDate and converts the selected |
| // to the week number. |
| mode = UIDatePickerModeDate; |
| style = UIDatePickerStyleInline; |
| break; |
| default: |
| NOTREACHED() << "Invalid type for a DateTimeChooser."; |
| break; |
| } |
| |
| datePicker.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; |
| datePicker.datePickerMode = mode; |
| datePicker.preferredDatePickerStyle = style; |
| |
| [datePicker setDate:initValue animated:FALSE]; |
| [datePicker addTarget:self |
| action:@selector(datePickerValueChanged:) |
| forControlEvents:UIControlEventValueChanged]; |
| return datePicker; |
| } |
| |
| - (void)cancelButtonTapped { |
| [[self presentingViewController] dismissViewControllerAnimated:YES |
| completion:nil]; |
| [self.delegate dateTimeChooser:self |
| didCloseSuccessfully:FALSE |
| withDate:self.selectedDate |
| forType:self.type]; |
| } |
| |
| - (void)doneButtonTapped { |
| [[self presentingViewController] dismissViewControllerAnimated:YES |
| completion:nil]; |
| // Convert seconds to miliseconds. |
| [self.delegate dateTimeChooser:self |
| didCloseSuccessfully:TRUE |
| withDate:self.selectedDate |
| forType:self.type]; |
| } |
| |
| - (void)datePickerValueChanged:(UIDatePicker*)datePicker { |
| self.selectedDate = datePicker.date; |
| } |
| |
| // Adds subviews for a UI component with UIDatePicker and buttons. |
| // |
| // ------------------------------------- |
| // |
| // |
| // UIDatePicker |
| // |
| // |
| // -------------------------------------- |
| // | Cancel | flexibleSpace | Done | |
| // -------------------------------------- |
| // |
| - (void)viewWillAppear:(BOOL)animated { |
| UIDatePicker* datePicker = [self createUIDatePicker]; |
| // Create a ToolBar for buttons. |
| UIToolbar* toolbar = [[UIToolbar alloc] |
| initWithFrame:CGRectMake(0, 0, datePicker.frame.size.width, |
| kToolBarHeight)]; |
| UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc] |
| initWithBarButtonSystemItem:UIBarButtonSystemItemCancel |
| target:self |
| action:@selector(cancelButtonTapped)]; |
| UIBarButtonItem* flexibleSpace = [[UIBarButtonItem alloc] |
| initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace |
| target:nil |
| action:nil]; |
| UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] |
| initWithBarButtonSystemItem:UIBarButtonSystemItemDone |
| target:self |
| action:@selector(doneButtonTapped)]; |
| |
| // Add the UIBarButtonItem to the UIToolbar |
| [toolbar setItems:@[ cancelButton, flexibleSpace, doneButton ]]; |
| |
| // Vertical stack view that holds UIDatePicker and buttons. |
| UIStackView* verticalStack = |
| [[UIStackView alloc] initWithArrangedSubviews:@[ datePicker, toolbar ]]; |
| verticalStack.axis = UILayoutConstraintAxisVertical; |
| verticalStack.spacing = 0; |
| verticalStack.distribution = UIStackViewDistributionFill; |
| verticalStack.layoutMarginsRelativeArrangement = YES; |
| verticalStack.layoutMargins = UIEdgeInsetsMake(0, 0, 0, 0); |
| verticalStack.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.view addSubview:verticalStack]; |
| [self.view setBounds:CGRectMake(CGRectGetMinX(datePicker.bounds), |
| CGRectGetMinY(datePicker.bounds), |
| CGRectGetWidth(datePicker.bounds), |
| CGRectGetHeight(datePicker.bounds) + |
| CGRectGetHeight(toolbar.bounds))]; |
| } |
| |
| @end |