diff --git a/THCalendarDatePicker/THDateDay.h b/THCalendarDatePicker/THDateDay.h index 72b922d..263ca6a 100755 --- a/THCalendarDatePicker/THDateDay.h +++ b/THCalendarDatePicker/THDateDay.h @@ -28,6 +28,7 @@ @property (strong, nonatomic) UIColor *selectedBackgroundColor; @property (strong, nonatomic) UIColor *currentDateColor; @property (strong, nonatomic) UIColor *currentDateColorSelected; +@property (nonatomic, getter=isRounded) BOOL rounded; - (IBAction)dateButtonTapped:(id)sender; diff --git a/THCalendarDatePicker/THDateDay.m b/THCalendarDatePicker/THDateDay.m index cd55b07..19ba9bd 100755 --- a/THCalendarDatePicker/THDateDay.m +++ b/THCalendarDatePicker/THDateDay.m @@ -17,15 +17,16 @@ @implementation THDateDay @synthesize selectedBackgroundColor = _selectedBackgroundColor; @synthesize currentDateColor = _currentDateColor; @synthesize currentDateColorSelected = _currentDateColorSelected; +@synthesize rounded = _rounded; -- (id)initWithFrame:(CGRect)frame -{ +- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code _selectedBackgroundColor = [UIColor colorWithRed:89/255.0 green:118/255.0 blue:169/255.0 alpha:1]; _currentDateColor = [UIColor colorWithRed:242/255.0 green:121/255.0 blue:53/255.0 alpha:1.0]; _currentDateColorSelected = [UIColor whiteColor]; + _rounded = NO; } return self; } @@ -38,8 +39,9 @@ - (void)drawRect:(CGRect)rect { - (void)layoutSubviews { [super layoutSubviews]; - //might be #37 - //[self addMaskToBounds:self.frame]; + if ([self isRounded]) { + [self addMaskToBounds:self.frame]; + } } #pragma mark - diff --git a/THCalendarDatePicker/THDatePickerViewController.h b/THCalendarDatePicker/THDatePickerViewController.h index ec46052..91125e5 100755 --- a/THCalendarDatePicker/THDatePickerViewController.h +++ b/THCalendarDatePicker/THDatePickerViewController.h @@ -38,7 +38,10 @@ @property (strong, nonatomic) UIColor *currentDateColorSelected; @property (nonatomic) float autoCloseCancelDelay; @property (strong, nonatomic) NSTimeZone *dateTimeZone; +@property (nonatomic, getter=isRounded) BOOL rounded; @property (weak, nonatomic) IBOutlet UIView *toolbarBackgroundView; +@property (nonatomic) float slideAnimationDuration; +@property (strong, nonatomic) NSArray * selectedDates; - (void)setDateHasItemsCallback:(BOOL (^)(NSDate * date))callback; @@ -47,6 +50,11 @@ */ - (void)setAllowClearDate:(BOOL)allow; +/*! Enable Multi Day Selection + * \param allow selection of multiple days + */ +- (void)setAllowMultiDaySelection:(BOOL)allow; + /*! Enable Ok Button when selected Date has already been selected * \param allow should show ok button */ diff --git a/THCalendarDatePicker/THDatePickerViewController.m b/THCalendarDatePicker/THDatePickerViewController.m index db59835..535163d 100755 --- a/THCalendarDatePicker/THDatePickerViewController.m +++ b/THCalendarDatePicker/THDatePickerViewController.m @@ -28,6 +28,12 @@ @interface THDatePickerViewController () { NSUInteger _daysInFuture; BOOL _disableYearSwitch; BOOL (^_dateHasItemsCallback)(NSDate *); + float _slideAnimationDuration; + NSMutableArray * _selectedDates; + NSMutableArray * _selectedDateViews; + BOOL _allowMultiDaySelection; + BOOL _disableHistorySelection; + BOOL _disableFutureSelection; } @property (nonatomic, strong) NSDate * firstOfCurrentMonth; @property (nonatomic, strong) THDateDay * currentDay; @@ -62,6 +68,9 @@ @implementation THDatePickerViewController @synthesize currentDateColorSelected = _currentDateColorSelected; @synthesize autoCloseCancelDelay = _autoCloseCancelDelay; @synthesize dateTimeZone = _dateTimeZone; +@synthesize rounded = _rounded; +@synthesize slideAnimationDuration = _slideAnimationDuration; +@synthesize selectedDates = _selectedDates; - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; @@ -75,6 +84,12 @@ - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil _daysInHistory = NO; _autoCloseCancelDelay = 1.0; _dateTimeZone = [NSTimeZone defaultTimeZone]; + _slideAnimationDuration = .5; + _disableFutureSelection = NO; + _disableHistorySelection = NO; + _selectedDates = [[NSMutableArray alloc] init]; + _selectedDateViews = [[NSMutableArray alloc] init]; + _allowMultiDaySelection = NO; } return self; } @@ -83,6 +98,10 @@ +(THDatePickerViewController *)datePicker { return [[THDatePickerViewController alloc] initWithNibName:@"THDatePickerViewController" bundle:[NSBundle bundleForClass:self.class]]; } +-(void)setAllowMultiDaySelection:(BOOL)allow { + _allowMultiDaySelection = allow; +} + - (void)setAllowClearDate:(BOOL)allow { _allowClearDate = allow; } @@ -258,7 +277,13 @@ - (void)redrawDays { } THDateDay * day = [[[NSBundle bundleForClass:self.class] loadNibNamed:@"THDateDay" owner:self options:nil] objectAtIndex:0]; - day.frame = CGRectMake(curX, curY, cellWidth, cellHeight); + if ([self isRounded]) { + [day setRounded:YES]; + // #37 still need to move the x/y coordinates apropriately + day.frame = CGRectMake(curX, curY, MIN(cellWidth, cellHeight), MIN(cellWidth, cellHeight)); + } else { + day.frame = CGRectMake(curX, curY, cellWidth, cellHeight); + } day.delegate = self; day.date = [date dateByAddingTimeInterval:0]; if (self.currentDateColor) @@ -268,6 +293,25 @@ - (void)redrawDays { if (self.selectedBackgroundColor) [day setSelectedBackgroundColor:self.selectedBackgroundColor]; + if(!_allowMultiDaySelection) + { + if (_internalDate && ![[self dateWithOutTime:date] timeIntervalSinceDate:_internalDate]) { + self.currentDay = day; + [day setSelected:YES]; + } + } + else + { + if ([_selectedDates containsObject:date]) + { + [day setSelected:YES]; + } + else + { + [day setSelected:NO]; + } + } + [day setLightText:![self dateInCurrentMonth:date]]; [day setEnabled:![self dateInFutureAndShouldBeDisabled:date]]; [day indicateDayHasItems:(_dateHasItemsCallback && _dateHasItemsCallback(date))]; @@ -292,6 +336,7 @@ - (void)redrawWeekdays:(int)dayWidth { int curX = (fullSize.width - 7*dayWidth)/2; NSDateComponents * comps = [_calendar components:NSCalendarUnitDay fromDate:[NSDate date]]; NSCalendar *c = [NSCalendar currentCalendar]; + [c setFirstWeekday:2]; [comps setDay:[c firstWeekday]-1]; NSDateFormatter *df = [[NSDateFormatter alloc] init]; NSDateComponents *offsetComponents = [[NSDateComponents alloc] init]; @@ -313,6 +358,25 @@ - (void)redrawWeekdays:(int)dayWidth { #pragma mark - Date Set, etc. +- (NSArray *)selectedDates { + return [[NSArray alloc] initWithArray:_selectedDates]; +} + +- (void)setSelectedDates:(NSArray *)selectedDates { + + _selectedDates = [[NSMutableArray alloc] init]; + for (NSDate* selectedDate in selectedDates) { + [_selectedDates addObject:[self dateWithOutTime:selectedDate]]; + } + if ([_selectedDates count] > 0) + { + _date = (NSDate*)[_selectedDates objectAtIndex:0]; + _dateNoTime = !_date ? nil : [self dateWithOutTime:_date]; + self.internalDate = [_dateNoTime dateByAddingTimeInterval:0]; + } + [self redrawDays]; +} + - (void)setDate:(NSDate *)date { _date = date; _dateNoTime = !date ? nil : [date dateWithOutTime]; @@ -335,6 +399,18 @@ - (NSDate *)date { } - (BOOL)shouldOkBeEnabled { + if (!_allowMultiDaySelection) + { + if (_autoCloseOnSelectDate) + return YES; + return (self.internalDate && _dateNoTime && (_allowSelectionOfSelectedDate || [self.internalDate timeIntervalSinceDate:_dateNoTime])) + || (self.internalDate && !_dateNoTime) + || (!self.internalDate && _dateNoTime); + } + else + { + return ([_selectedDates count] > 0); + } if (_autoCloseOnSelectDate) return YES; return (self.internalDate && _dateNoTime && (_allowSelectionOfSelectedDate || [self.internalDate timeIntervalSinceDate:_dateNoTime])) @@ -370,6 +446,7 @@ - (void)setDisplayedMonthFromDate:(NSDate *)date{ - (void)storeDateInformation{ NSDateComponents *comps = [_calendar components:NSCalendarUnitWeekday | NSCalendarUnitDay fromDate:self.firstOfCurrentMonth]; NSCalendar *c = [NSCalendar currentCalendar]; + [c setFirstWeekday:2]; #ifdef DEBUG //[c setFirstWeekday:FIRST_WEEKDAY]; #endif @@ -410,21 +487,72 @@ - (BOOL)setDateTimeZoneWithName:(NSString *)name { #pragma mark - User Events - (void)dateDayTapped:(THDateDay *)dateDay { - if (!_internalDate || [_internalDate timeIntervalSinceDate:dateDay.date] || _allowSelectionOfSelectedDate) { // new date selected - [self.currentDay setSelected:NO]; - [dateDay setSelected:YES]; - BOOL dateInDifferentMonth = ![self dateInCurrentMonth:dateDay.date]; - [self setInternalDate:dateDay.date]; - [self setCurrentDay:dateDay]; - if (dateInDifferentMonth) { - [self slideTransitionViewInDirection:[dateDay.date timeIntervalSinceDate:self.firstOfCurrentMonth]>0 ? UISwipeGestureRecognizerDirectionRight : UISwipeGestureRecognizerDirectionLeft]; + if (!_allowMultiDaySelection) + { + if (!_internalDate || [_internalDate timeIntervalSinceDate:dateDay.date] || _allowSelectionOfSelectedDate) { // new date selected + [self.currentDay setSelected:NO]; + [dateDay setSelected:YES]; + BOOL dateInDifferentMonth = ![self dateInCurrentMonth:dateDay.date]; + [self setInternalDate:dateDay.date]; + [self setCurrentDay:dateDay]; + if (dateInDifferentMonth) { + [self slideTransitionViewInDirection:[dateDay.date timeIntervalSinceDate:self.firstOfCurrentMonth]>0 ? UISwipeGestureRecognizerDirectionRight : UISwipeGestureRecognizerDirectionLeft]; + } + if ([self.delegate respondsToSelector:@selector(datePicker:selectedDate:)]) { + [self.delegate datePicker:self selectedDate:dateDay.date]; + } + if (_autoCloseOnSelectDate) { + [self.delegate datePickerDonePressed:self]; + } } - if ([self.delegate respondsToSelector:@selector(datePicker:selectedDate:)]) { - [self.delegate datePicker:self selectedDate:dateDay.date]; + if (!_internalDate || [_internalDate timeIntervalSinceDate:dateDay.date] || _allowSelectionOfSelectedDate) { // new date selected + [self.currentDay setSelected:NO]; + [self.currentDay setLightText:![self dateInCurrentMonth:self.currentDay.date]]; + [dateDay setSelected:YES]; + BOOL dateInDifferentMonth = ![self dateInCurrentMonth:dateDay.date]; + NSDate *firstOfCurrentMonth = self.firstOfCurrentMonth; + [self setInternalDate:dateDay.date]; + [self setCurrentDay:dateDay]; + if (dateInDifferentMonth) { + [self slideTransitionViewInDirection:[dateDay.date timeIntervalSinceDate:firstOfCurrentMonth]<0 ? UISwipeGestureRecognizerDirectionRight : UISwipeGestureRecognizerDirectionLeft]; + } + if ([self.delegate respondsToSelector:@selector(datePicker:selectedDate:)]) { + [self.delegate datePicker:self selectedDate:dateDay.date]; + } + if (_autoCloseOnSelectDate) { + [self.delegate datePickerDonePressed:self]; + } } - if (_autoCloseOnSelectDate) { - [self.delegate datePickerDonePressed:self]; + } + else { + THDateDay* tapDay = dateDay; + if (![_selectedDates containsObject:[self dateWithOutTime:tapDay.date]]) + { + [_selectedDates addObject:[self dateWithOutTime:tapDay.date]]; + [_selectedDateViews addObject:tapDay]; + + BOOL dateInDifferentMonth = ![self dateInCurrentMonth:dateDay.date]; + [self setInternalDate:dateDay.date]; + [self setCurrentDay:dateDay]; + if (dateInDifferentMonth) { + [self slideTransitionViewInDirection:[dateDay.date timeIntervalSinceDate:self.firstOfCurrentMonth]>0 ? UISwipeGestureRecognizerDirectionRight : UISwipeGestureRecognizerDirectionLeft]; + } + if ([self.delegate respondsToSelector:@selector(datePicker:selectedDate:)]) { + [self.delegate datePicker:self selectedDate:dateDay.date]; + } + } + else + { + [tapDay setSelected:NO]; + [_selectedDates removeObject:tapDay.date]; + [_selectedDateViews removeObject:tapDay]; } + + for (THDateDay* selectedDate in _selectedDateViews) + { + [selectedDate setSelected:YES]; + } + self.okBtn.enabled = [self shouldOkBeEnabled]; } } @@ -457,7 +585,7 @@ - (void)slideTransitionViewInDirection:(UISwipeGestureRecognizerDirection)dir { newView.alpha = 0; [self redraw]; [oldView.superview layoutSubviews]; - [UIView animateWithDuration:.5 animations:^{ + [UIView animateWithDuration:self.slideAnimationDuration animations:^{ newView.frame = origFrame; newView.alpha = 1; oldView.frame = outDestFrame; @@ -570,6 +698,14 @@ - (BOOL)dateInCurrentMonth:(NSDate *)date{ return [comp1 year] == [comp2 year] && [comp1 month] == [comp2 month]; } +- (NSDate *)dateWithOutTime:(NSDate *)datDate { + if(!datDate) { + datDate = [NSDate date]; + } + NSDateComponents* comps = [[NSCalendar currentCalendar] components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:datDate]; + return [[NSCalendar currentCalendar] dateFromComponents:comps]; +} + #pragma mark - Cleanup - (void)didReceiveMemoryWarning {