From 14f20203aca59ef4fb40285f40c3783ccf2bb706 Mon Sep 17 00:00:00 2001 From: Matt Grayson Date: Tue, 23 Apr 2013 17:04:43 -0500 Subject: [PATCH 1/8] Support for selecting date ranges Range selection mimics Hipmunk. Also streamlines button creation. --- TimesSquare/TSQCalendarRowCell.h | 8 ++ TimesSquare/TSQCalendarRowCell.m | 144 ++++++++++++++----------------- TimesSquare/TSQCalendarView.h | 32 +++++++ TimesSquare/TSQCalendarView.m | 73 +++++++++++++++- 4 files changed, 176 insertions(+), 81 deletions(-) diff --git a/TimesSquare/TSQCalendarRowCell.h b/TimesSquare/TSQCalendarRowCell.h index 0fad589..c045d57 100644 --- a/TimesSquare/TSQCalendarRowCell.h +++ b/TimesSquare/TSQCalendarRowCell.h @@ -65,4 +65,12 @@ */ - (void)selectColumnForDate:(NSDate *)date; +/** Method to select a specific date within the week. + + This is funneled through and called by the calendar view, to facilitate deselection of other rows. + + @param date The date to select, or nil to deselect all columns. + */ +- (void)deselectColumnForDate:(NSDate *)date; + @end diff --git a/TimesSquare/TSQCalendarRowCell.m b/TimesSquare/TSQCalendarRowCell.m index 312a7f2..21a6f78 100644 --- a/TimesSquare/TSQCalendarRowCell.m +++ b/TimesSquare/TSQCalendarRowCell.m @@ -12,11 +12,12 @@ @interface TSQCalendarRowCell () +{ + int selectedButtonIndices[7]; +} @property (nonatomic, strong) NSArray *dayButtons; @property (nonatomic, strong) NSArray *notThisMonthButtons; -@property (nonatomic, strong) UIButton *todayButton; -@property (nonatomic, strong) UIButton *selectedButton; @property (nonatomic, assign) NSInteger indexOfTodayButton; @property (nonatomic, assign) NSInteger indexOfSelectedButton; @@ -82,37 +83,6 @@ - (void)createNotThisMonthButtons; self.notThisMonthButtons = notThisMonthButtons; } -- (void)createTodayButton; -{ - self.todayButton = [[UIButton alloc] initWithFrame:self.contentView.bounds]; - [self.contentView addSubview:self.todayButton]; - [self configureButton:self.todayButton]; - [self.todayButton addTarget:self action:@selector(todayButtonPressed:) forControlEvents:UIControlEventTouchDown]; - - [self.todayButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; - [self.todayButton setBackgroundImage:[self todayBackgroundImage] forState:UIControlStateNormal]; - [self.todayButton setTitleShadowColor:[UIColor colorWithWhite:0.0f alpha:0.75f] forState:UIControlStateNormal]; - - self.todayButton.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f / [UIScreen mainScreen].scale); -} - -- (void)createSelectedButton; -{ - self.selectedButton = [[UIButton alloc] initWithFrame:self.contentView.bounds]; - [self.contentView addSubview:self.selectedButton]; - [self configureButton:self.selectedButton]; - - [self.selectedButton setAccessibilityTraits:UIAccessibilityTraitSelected|self.selectedButton.accessibilityTraits]; - - self.selectedButton.enabled = NO; - [self.selectedButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; - [self.selectedButton setBackgroundImage:[self selectedBackgroundImage] forState:UIControlStateNormal]; - [self.selectedButton setTitleShadowColor:[UIColor colorWithWhite:0.0f alpha:0.75f] forState:UIControlStateNormal]; - - self.selectedButton.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f / [UIScreen mainScreen].scale); - self.indexOfSelectedButton = -1; -} - - (void)setBeginningDate:(NSDate *)date; { _beginningDate = date; @@ -120,10 +90,7 @@ - (void)setBeginningDate:(NSDate *)date; NSDateComponents *offset = [NSDateComponents new]; offset.day = 1; - self.todayButton.hidden = YES; self.indexOfTodayButton = -1; - self.selectedButton.hidden = YES; - self.indexOfSelectedButton = -1; for (NSUInteger index = 0; index < self.daysInWeek; index++) { NSString *title = [self.dayFormatter stringFromDate:date]; @@ -142,20 +109,16 @@ - (void)setBeginningDate:(NSDate *)date; if (self.monthOfBeginningDate != thisDayMonth) { [self.notThisMonthButtons[index] setHidden:NO]; } else { - if ([self.todayDateComponents isEqual:thisDateComponents]) { - self.todayButton.hidden = NO; - [self.todayButton setTitle:title forState:UIControlStateNormal]; - [self.todayButton setAccessibilityLabel:accessibilityLabel]; self.indexOfTodayButton = index; - } else { - UIButton *button = self.dayButtons[index]; - button.enabled = ![self.calendarView.delegate respondsToSelector:@selector(calendarView:shouldSelectDate:)] || [self.calendarView.delegate calendarView:self.calendarView shouldSelectDate:date]; - button.hidden = NO; } + UIButton *button = self.dayButtons[index]; + button.enabled = ![self.calendarView.delegate respondsToSelector:@selector(calendarView:shouldSelectDate:)] || [self.calendarView.delegate calendarView:self.calendarView shouldSelectDate:date]; + button.hidden = NO; } date = [self.calendar dateByAddingComponents:offset toDate:date options:0]; + selectedButtonIndices[index] = 0; } } @@ -178,15 +141,19 @@ - (IBAction)dateButtonPressed:(id)sender; NSDateComponents *offset = [NSDateComponents new]; offset.day = [self.dayButtons indexOfObject:sender]; NSDate *selectedDate = [self.calendar dateByAddingComponents:offset toDate:self.beginningDate options:0]; - self.calendarView.selectedDate = selectedDate; -} - -- (IBAction)todayButtonPressed:(id)sender; -{ - NSDateComponents *offset = [NSDateComponents new]; - offset.day = self.indexOfTodayButton; - NSDate *selectedDate = [self.calendar dateByAddingComponents:offset toDate:self.beginningDate options:0]; - self.calendarView.selectedDate = selectedDate; + + if (self.calendarView.selectionType == TSQCalendarSelectionDay) { + self.calendarView.selectedDate = selectedDate; + } else { + if (self.calendarView.selectedEndDate) { + self.calendarView.selectedStartDate = selectedDate; + } else if (self.calendarView.selectedStartDate && ([selectedDate compare:self.calendarView.selectedStartDate] == NSOrderedDescending)) { + self.calendarView.selectedEndDate = selectedDate; + } else { + self.calendarView.selectedStartDate = selectedDate; + } + NSLog(@"%@ - %@", self.calendarView.selectedStartDate, self.calendarView.selectedEndDate); + } } - (void)layoutSubviews; @@ -194,8 +161,6 @@ - (void)layoutSubviews; if (!self.dayButtons) { [self createDayButtons]; [self createNotThisMonthButtons]; - [self createTodayButton]; - [self createSelectedButton]; } if (!self.backgroundView) { @@ -215,39 +180,42 @@ - (void)layoutViewsForColumnAtIndex:(NSUInteger)index inRect:(CGRect)rect; dayButton.frame = rect; notThisMonthButton.frame = rect; - if (self.indexOfTodayButton == (NSInteger)index) { - self.todayButton.frame = rect; + if (selectedButtonIndices[index] == 1) { + [dayButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dayButton setBackgroundImage:[self selectedBackgroundImage] forState:UIControlStateNormal]; + [dayButton setTitleShadowColor:[UIColor colorWithWhite:0.0f alpha:0.75f] forState:UIControlStateNormal]; + dayButton.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f / [UIScreen mainScreen].scale); + } else if (self.indexOfTodayButton == (NSInteger)index) { + [self configureButton:dayButton]; + [dayButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dayButton setBackgroundImage:[self todayBackgroundImage] forState:UIControlStateNormal]; + [dayButton setTitleShadowColor:[UIColor colorWithWhite:0.0f alpha:0.75f] forState:UIControlStateNormal]; + dayButton.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f / [UIScreen mainScreen].scale); + } else { + [self configureButton:dayButton]; + [dayButton setBackgroundImage:nil forState:UIControlStateNormal]; } - if (self.indexOfSelectedButton == (NSInteger)index) { - self.selectedButton.frame = rect; +} + +- (void)deselectColumnForDate:(NSDate *)date; +{ + NSInteger indexOfButtonForDate = [self indexOfColumnForDate:date]; + if (indexOfButtonForDate >= 0) { + selectedButtonIndices[indexOfButtonForDate] = 0; } + + [self setNeedsLayout]; } - (void)selectColumnForDate:(NSDate *)date; { - if (!date && self.indexOfSelectedButton == -1) { + if (!date) { return; } - - NSInteger newIndexOfSelectedButton = -1; - if (date) { - NSInteger thisDayMonth = [self.calendar components:NSMonthCalendarUnit fromDate:date].month; - if (self.monthOfBeginningDate == thisDayMonth) { - newIndexOfSelectedButton = [self.calendar components:NSDayCalendarUnit fromDate:self.beginningDate toDate:date options:0].day; - if (newIndexOfSelectedButton >= (NSInteger)self.daysInWeek) { - newIndexOfSelectedButton = -1; - } - } - } - - self.indexOfSelectedButton = newIndexOfSelectedButton; - if (newIndexOfSelectedButton >= 0) { - self.selectedButton.hidden = NO; - [self.selectedButton setTitle:[self.dayButtons[newIndexOfSelectedButton] currentTitle] forState:UIControlStateNormal]; - [self.selectedButton setAccessibilityLabel:[self.dayButtons[newIndexOfSelectedButton] accessibilityLabel]]; - } else { - self.selectedButton.hidden = YES; + NSInteger indexOfButtonForDate = [self indexOfColumnForDate:date]; + if (indexOfButtonForDate >= 0) { + selectedButtonIndices[indexOfButtonForDate] = 1; } [self setNeedsLayout]; @@ -295,4 +263,22 @@ - (NSDateComponents *)todayDateComponents; return _todayDateComponents; } + +#pragma mark - Columns + +- (NSInteger *)indexOfColumnForDate:(NSDate *)date; +{ + NSInteger indexOfButtonForDate = -1; + if (date) { + NSInteger thisDayMonth = [self.calendar components:NSMonthCalendarUnit fromDate:date].month; + if (self.monthOfBeginningDate == thisDayMonth) { + indexOfButtonForDate = [self.calendar components:NSDayCalendarUnit fromDate:self.beginningDate toDate:date options:0].day; + if (indexOfButtonForDate >= (NSInteger)self.daysInWeek) { + indexOfButtonForDate = -1; + } + } + } + return indexOfButtonForDate; +} + @end diff --git a/TimesSquare/TSQCalendarView.h b/TimesSquare/TSQCalendarView.h index d6f0dab..3346f37 100644 --- a/TimesSquare/TSQCalendarView.h +++ b/TimesSquare/TSQCalendarView.h @@ -9,6 +9,11 @@ #import +typedef enum { + TSQCalendarSelectionDay = 0, + TSQCalendarSelectionDateRange +} TSQCalendarSelectionType; + @protocol TSQCalendarViewDelegate; @@ -42,6 +47,33 @@ */ @property (nonatomic, strong) NSDate *selectedDate; +/** The currently-selected dates on the calendar. + + This property is read-only. + */ +@property (nonatomic, readonly) NSArray *selectedDates; + +/** The selection mode used for the calendar. + + Defaults to `TSQCalendarSelectionDay`, which is the normal, single date selection. + Set to `TSQCalendarSelectionDateRange` to allow selecting a range of dates. + */ +@property (nonatomic, assign) TSQCalendarSelectionType selectionType; + +/** The start date of the currently-selected date range on the calendar. + + Set this property to any `NSDate`; `TSQCalendarView` will only look at the month, day, and year. + You can read and write this property. + */ +@property (nonatomic, strong) NSDate *selectedStartDate; + +/** The end date of the currently-selected date range on the calendar. + + Set this property to any `NSDate`; `TSQCalendarView` will only look at the month, day, and year. + You can read and write this property. + */ +@property (nonatomic, strong) NSDate *selectedEndDate; + /** @name Calendar Configuration */ /** The calendar type to use when displaying. diff --git a/TimesSquare/TSQCalendarView.m b/TimesSquare/TSQCalendarView.m index d89d7c2..1039809 100644 --- a/TimesSquare/TSQCalendarView.m +++ b/TimesSquare/TSQCalendarView.m @@ -52,6 +52,7 @@ - (void)_TSQCalendarView_commonInit; _tableView.delegate = self; _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; _tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth; + _selectionType = TSQCalendarSelectionDay; [self addSubview:_tableView]; } @@ -132,7 +133,7 @@ - (void)setSelectedDate:(NSDate *)newSelectedDate; return; } - [[self cellForRowAtDate:_selectedDate] selectColumnForDate:nil]; + [[self cellForRowAtDate:_selectedDate] deselectColumnForDate:_selectedDate]; [[self cellForRowAtDate:startOfDay] selectColumnForDate:startOfDay]; NSIndexPath *newIndexPath = [self indexPathForRowAtDate:startOfDay]; CGRect newIndexPathRect = [self.tableView rectForRowAtIndexPath:newIndexPath]; @@ -156,6 +157,54 @@ - (void)setSelectedDate:(NSDate *)newSelectedDate; } } +- (void)setSelectedStartDate:(NSDate *)newSelectedStartDate +{ + for (NSDate *date in self.selectedDates) { + [[self cellForRowAtDate:date] deselectColumnForDate:date]; + } + + _selectedDates = @[]; + _selectedStartDate = nil; + _selectedEndDate = nil; + + if (newSelectedStartDate == nil) return; + + NSDate *startOfDay = [self clampDate:newSelectedStartDate toComponents:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit]; + if ([self.delegate respondsToSelector:@selector(calendarView:shouldSelectDate:)] && ![self.delegate calendarView:self shouldSelectDate:startOfDay]) { + return; + } + + [[self cellForRowAtDate:startOfDay] selectColumnForDate:startOfDay]; + + _selectedStartDate = newSelectedStartDate; + _selectedDates = @[newSelectedStartDate]; +} + +- (void)setSelectedEndDate:(NSDate *)newSelectedEndDate +{ + for (NSDate *date in self.selectedDates) { + [[self cellForRowAtDate:date] deselectColumnForDate:date]; + } + + if (newSelectedEndDate == nil) { + _selectedEndDate = nil; + _selectedDates = @[_selectedStartDate]; + [[self cellForRowAtDate:_selectedStartDate] selectColumnForDate:_selectedStartDate]; + return; + } + + NSDate *startOfDay = [self clampDate:newSelectedEndDate toComponents:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit]; + if ([self.delegate respondsToSelector:@selector(calendarView:shouldSelectDate:)] && ![self.delegate calendarView:self shouldSelectDate:startOfDay]) { + return; + } + + _selectedEndDate = newSelectedEndDate; + _selectedDates = [self datesBetweenStart:_selectedStartDate AndEnd:newSelectedEndDate]; + for (NSDate *date in _selectedDates) { + [[self cellForRowAtDate:date] selectColumnForDate:date]; + } +} + - (void)scrollToDate:(NSDate *)date animated:(BOOL)animated { NSInteger section = [self sectionForDate:date]; @@ -205,6 +254,19 @@ - (NSIndexPath *)indexPathForRowAtDate:(NSDate *)date; return [NSIndexPath indexPathForRow:(self.pinsHeaderToTop ? 0 : 1) + targetWeek - firstWeek inSection:section]; } +- (NSArray *)datesBetweenStart:(NSDate *)start AndEnd:(NSDate *)end +{ + NSMutableArray *dates = [NSMutableArray array]; + NSDateComponents *components = [[NSDateComponents alloc] init]; + components.day = 1; + NSDate *current = start; + while ([end compare:current] != NSOrderedAscending) { + [dates addObject:current]; + current = [self.calendar dateByAddingComponents:components toDate:current options:0]; + } + return dates; +} + #pragma mark UIView - (void)layoutSubviews; @@ -293,7 +355,14 @@ - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)ce dateComponents.day = 1 - ordinalityOfFirstDay; dateComponents.week = indexPath.row - (self.pinsHeaderToTop ? 0 : 1); [(TSQCalendarRowCell *)cell setBeginningDate:[self.calendar dateByAddingComponents:dateComponents toDate:firstOfMonth options:0]]; - [(TSQCalendarRowCell *)cell selectColumnForDate:self.selectedDate]; + + if (self.selectionType == TSQCalendarSelectionDay) { + [(TSQCalendarRowCell *)cell selectColumnForDate:self.selectedDate]; + } else { + for (NSDate *date in self.selectedDates) { + [(TSQCalendarRowCell *)cell selectColumnForDate:date]; + } + } BOOL isBottomRow = (indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - (self.pinsHeaderToTop ? 0 : 1)); [(TSQCalendarRowCell *)cell setBottomRow:isBottomRow]; From f931fcb06a5811d3bab5c7dff6a9db67a24f9845 Mon Sep 17 00:00:00 2001 From: Matt Grayson Date: Wed, 24 Apr 2013 07:29:46 -0500 Subject: [PATCH 2/8] more consistency between date selection modes support for deselecting dates and ensure calendarView:shouldSelectDate: is respected when selecting date ranges --- TimesSquare/TSQCalendarRowCell.m | 50 ++++++++------ TimesSquare/TSQCalendarView.m | 113 ++++++++++++++++++++----------- 2 files changed, 102 insertions(+), 61 deletions(-) diff --git a/TimesSquare/TSQCalendarRowCell.m b/TimesSquare/TSQCalendarRowCell.m index 21a6f78..d3a64fb 100644 --- a/TimesSquare/TSQCalendarRowCell.m +++ b/TimesSquare/TSQCalendarRowCell.m @@ -13,7 +13,7 @@ @interface TSQCalendarRowCell () { - int selectedButtonIndices[7]; + int buttonStates[7]; } @property (nonatomic, strong) NSArray *dayButtons; @@ -50,6 +50,23 @@ - (void)configureButton:(UIButton *)button; button.adjustsImageWhenDisabled = NO; [button setTitleColor:self.textColor forState:UIControlStateNormal]; [button setTitleShadowColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [button setBackgroundImage:nil forState:UIControlStateNormal]; +} + +- (void)configureSelectedButton:(UIButton *)button; +{ + [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [button setBackgroundImage:[self selectedBackgroundImage] forState:UIControlStateNormal]; + [button setTitleShadowColor:[UIColor colorWithWhite:0.0f alpha:0.75f] forState:UIControlStateNormal]; + button.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f / [UIScreen mainScreen].scale); +} + +- (void)configureTodayButton:(UIButton *)button; +{ + [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [button setBackgroundImage:[self todayBackgroundImage] forState:UIControlStateNormal]; + [button setTitleShadowColor:[UIColor colorWithWhite:0.0f alpha:0.75f] forState:UIControlStateNormal]; + button.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f / [UIScreen mainScreen].scale); } - (void)createDayButtons; @@ -118,7 +135,7 @@ - (void)setBeginningDate:(NSDate *)date; } date = [self.calendar dateByAddingComponents:offset toDate:date options:0]; - selectedButtonIndices[index] = 0; + buttonStates[index] = 0; } } @@ -143,16 +160,17 @@ - (IBAction)dateButtonPressed:(id)sender; NSDate *selectedDate = [self.calendar dateByAddingComponents:offset toDate:self.beginningDate options:0]; if (self.calendarView.selectionType == TSQCalendarSelectionDay) { - self.calendarView.selectedDate = selectedDate; + self.calendarView.selectedDate = ([self.calendarView.selectedDate isEqual:selectedDate]) ? nil : selectedDate; } else { if (self.calendarView.selectedEndDate) { self.calendarView.selectedStartDate = selectedDate; } else if (self.calendarView.selectedStartDate && ([selectedDate compare:self.calendarView.selectedStartDate] == NSOrderedDescending)) { self.calendarView.selectedEndDate = selectedDate; + } else if ([self.calendarView.selectedStartDate isEqual:selectedDate]) { + self.calendarView.selectedStartDate = nil; } else { self.calendarView.selectedStartDate = selectedDate; } - NSLog(@"%@ - %@", self.calendarView.selectedStartDate, self.calendarView.selectedEndDate); } } @@ -180,28 +198,22 @@ - (void)layoutViewsForColumnAtIndex:(NSUInteger)index inRect:(CGRect)rect; dayButton.frame = rect; notThisMonthButton.frame = rect; - if (selectedButtonIndices[index] == 1) { - [dayButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; - [dayButton setBackgroundImage:[self selectedBackgroundImage] forState:UIControlStateNormal]; - [dayButton setTitleShadowColor:[UIColor colorWithWhite:0.0f alpha:0.75f] forState:UIControlStateNormal]; - dayButton.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f / [UIScreen mainScreen].scale); + if (buttonStates[index] == 1) { + [self configureSelectedButton:dayButton]; } else if (self.indexOfTodayButton == (NSInteger)index) { - [self configureButton:dayButton]; - [dayButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; - [dayButton setBackgroundImage:[self todayBackgroundImage] forState:UIControlStateNormal]; - [dayButton setTitleShadowColor:[UIColor colorWithWhite:0.0f alpha:0.75f] forState:UIControlStateNormal]; - dayButton.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f / [UIScreen mainScreen].scale); + [self configureTodayButton:dayButton]; } else { [self configureButton:dayButton]; - [dayButton setBackgroundImage:nil forState:UIControlStateNormal]; } } - (void)deselectColumnForDate:(NSDate *)date; { + if (!date) return; + NSInteger indexOfButtonForDate = [self indexOfColumnForDate:date]; if (indexOfButtonForDate >= 0) { - selectedButtonIndices[indexOfButtonForDate] = 0; + buttonStates[indexOfButtonForDate] = 0; } [self setNeedsLayout]; @@ -209,13 +221,11 @@ - (void)deselectColumnForDate:(NSDate *)date; - (void)selectColumnForDate:(NSDate *)date; { - if (!date) { - return; - } + if (!date) return; NSInteger indexOfButtonForDate = [self indexOfColumnForDate:date]; if (indexOfButtonForDate >= 0) { - selectedButtonIndices[indexOfButtonForDate] = 1; + buttonStates[indexOfButtonForDate] = 1; } [self setNeedsLayout]; diff --git a/TimesSquare/TSQCalendarView.m b/TimesSquare/TSQCalendarView.m index 1039809..c021f8d 100644 --- a/TimesSquare/TSQCalendarView.m +++ b/TimesSquare/TSQCalendarView.m @@ -124,21 +124,59 @@ - (void)setLastDate:(NSDate *)lastDate; _lastDate = [self.calendar dateByAddingComponents:offsetComponents toDate:firstOfMonth options:0]; } +- (void)scrollToDate:(NSDate *)date animated:(BOOL)animated +{ + NSInteger section = [self sectionForDate:date]; + [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UITableViewScrollPositionTop animated:animated]; +} + +- (TSQCalendarMonthHeaderCell *)makeHeaderCellWithIdentifier:(NSString *)identifier; +{ + TSQCalendarMonthHeaderCell *cell = [[[self headerCellClass] alloc] initWithCalendar:self.calendar reuseIdentifier:identifier]; + cell.backgroundColor = self.backgroundColor; + cell.calendarView = self; + return cell; +} + +#pragma mark Date selections + +- (void)resetSelectedDates +{ + for (NSDate *date in _selectedDates) { + [[self cellForRowAtDate:date] deselectColumnForDate:date]; + } + _selectedDates = @[]; + _selectedDate = nil; + _selectedStartDate = nil; + _selectedEndDate = nil; +} + +- (void)resetSelectedDateRange +{ + for (NSDate *date in _selectedDates) { + [[self cellForRowAtDate:date] deselectColumnForDate:date]; + } + _selectedEndDate = nil; + _selectedDates = @[_selectedStartDate]; + [[self cellForRowAtDate:_selectedStartDate] selectColumnForDate:_selectedStartDate]; +} + - (void)setSelectedDate:(NSDate *)newSelectedDate; { + if (newSelectedDate == nil) { + [self resetSelectedDates]; + return; + } + // clamp to beginning of its day NSDate *startOfDay = [self clampDate:newSelectedDate toComponents:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit]; - if ([self.delegate respondsToSelector:@selector(calendarView:shouldSelectDate:)] && ![self.delegate calendarView:self shouldSelectDate:startOfDay]) { return; } - - [[self cellForRowAtDate:_selectedDate] deselectColumnForDate:_selectedDate]; - [[self cellForRowAtDate:startOfDay] selectColumnForDate:startOfDay]; + NSIndexPath *newIndexPath = [self indexPathForRowAtDate:startOfDay]; CGRect newIndexPathRect = [self.tableView rectForRowAtIndexPath:newIndexPath]; - CGRect scrollBounds = self.tableView.bounds; - + CGRect scrollBounds = self.tableView.bounds; if (self.pagingEnabled) { CGRect sectionRect = [self.tableView rectForSection:newIndexPath.section]; [self.tableView setContentOffset:sectionRect.origin animated:YES]; @@ -150,7 +188,10 @@ - (void)setSelectedDate:(NSDate *)newSelectedDate; } } + [self resetSelectedDates]; _selectedDate = startOfDay; + _selectedDates = @[_selectedDate]; + [self updateSelectedDates]; if ([self.delegate respondsToSelector:@selector(calendarView:didSelectDate:)]) { [self.delegate calendarView:self didSelectDate:startOfDay]; @@ -159,37 +200,30 @@ - (void)setSelectedDate:(NSDate *)newSelectedDate; - (void)setSelectedStartDate:(NSDate *)newSelectedStartDate { - for (NSDate *date in self.selectedDates) { - [[self cellForRowAtDate:date] deselectColumnForDate:date]; + if (newSelectedStartDate == nil) { + [self resetSelectedDates]; + return; } - _selectedDates = @[]; - _selectedStartDate = nil; - _selectedEndDate = nil; - - if (newSelectedStartDate == nil) return; - NSDate *startOfDay = [self clampDate:newSelectedStartDate toComponents:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit]; if ([self.delegate respondsToSelector:@selector(calendarView:shouldSelectDate:)] && ![self.delegate calendarView:self shouldSelectDate:startOfDay]) { return; } - [[self cellForRowAtDate:startOfDay] selectColumnForDate:startOfDay]; + [self resetSelectedDates]; + _selectedStartDate = startOfDay; + _selectedDates = @[startOfDay]; + [self updateSelectedDates]; - _selectedStartDate = newSelectedStartDate; - _selectedDates = @[newSelectedStartDate]; + if ([self.delegate respondsToSelector:@selector(calendarView:didSelectDate:)]) { + [self.delegate calendarView:self didSelectDate:startOfDay]; + } } - (void)setSelectedEndDate:(NSDate *)newSelectedEndDate { - for (NSDate *date in self.selectedDates) { - [[self cellForRowAtDate:date] deselectColumnForDate:date]; - } - if (newSelectedEndDate == nil) { - _selectedEndDate = nil; - _selectedDates = @[_selectedStartDate]; - [[self cellForRowAtDate:_selectedStartDate] selectColumnForDate:_selectedStartDate]; + [self resetSelectedDateRange]; return; } @@ -198,25 +232,21 @@ - (void)setSelectedEndDate:(NSDate *)newSelectedEndDate return; } - _selectedEndDate = newSelectedEndDate; - _selectedDates = [self datesBetweenStart:_selectedStartDate AndEnd:newSelectedEndDate]; - for (NSDate *date in _selectedDates) { - [[self cellForRowAtDate:date] selectColumnForDate:date]; + [self resetSelectedDateRange]; + _selectedEndDate = startOfDay; + _selectedDates = [self datesBetweenStart:_selectedStartDate AndEnd:startOfDay]; + [self updateSelectedDates]; + + if ([self.delegate respondsToSelector:@selector(calendarView:didSelectDate:)]) { + [self.delegate calendarView:self didSelectDate:startOfDay]; } } -- (void)scrollToDate:(NSDate *)date animated:(BOOL)animated +- (void)updateSelectedDates { - NSInteger section = [self sectionForDate:date]; - [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UITableViewScrollPositionTop animated:animated]; -} - -- (TSQCalendarMonthHeaderCell *)makeHeaderCellWithIdentifier:(NSString *)identifier; -{ - TSQCalendarMonthHeaderCell *cell = [[[self headerCellClass] alloc] initWithCalendar:self.calendar reuseIdentifier:identifier]; - cell.backgroundColor = self.backgroundColor; - cell.calendarView = self; - return cell; + for (NSDate *date in _selectedDates) { + [[self cellForRowAtDate:date] selectColumnForDate:date]; + } } #pragma mark Calendar calculations @@ -262,7 +292,8 @@ - (NSArray *)datesBetweenStart:(NSDate *)start AndEnd:(NSDate *)end NSDate *current = start; while ([end compare:current] != NSOrderedAscending) { [dates addObject:current]; - current = [self.calendar dateByAddingComponents:components toDate:current options:0]; + NSDate *nextDay = [self.calendar dateByAddingComponents:components toDate:current options:0]; + current = [self clampDate:nextDay toComponents:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit]; } return dates; } @@ -359,7 +390,7 @@ - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)ce if (self.selectionType == TSQCalendarSelectionDay) { [(TSQCalendarRowCell *)cell selectColumnForDate:self.selectedDate]; } else { - for (NSDate *date in self.selectedDates) { + for (NSDate *date in _selectedDates) { [(TSQCalendarRowCell *)cell selectColumnForDate:date]; } } From 9030c2159bd1018444f6db0f437434c885534bff Mon Sep 17 00:00:00 2001 From: Matt Grayson Date: Wed, 24 Apr 2013 16:59:36 -0500 Subject: [PATCH 3/8] Additional delegate methods for start and end date selection --- TimesSquare/TSQCalendarRowCell.m | 14 ++++++++------ TimesSquare/TSQCalendarView.h | 26 ++++++++++++++++++++++++++ TimesSquare/TSQCalendarView.m | 14 ++++++++++---- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/TimesSquare/TSQCalendarRowCell.m b/TimesSquare/TSQCalendarRowCell.m index d3a64fb..7639b80 100644 --- a/TimesSquare/TSQCalendarRowCell.m +++ b/TimesSquare/TSQCalendarRowCell.m @@ -49,6 +49,7 @@ - (void)configureButton:(UIButton *)button; button.titleLabel.shadowOffset = self.shadowOffset; button.adjustsImageWhenDisabled = NO; [button setTitleColor:self.textColor forState:UIControlStateNormal]; + [button setTitleColor:[self.textColor colorWithAlphaComponent:0.5f] forState:UIControlStateDisabled]; [button setTitleShadowColor:[UIColor whiteColor] forState:UIControlStateNormal]; [button setBackgroundImage:nil forState:UIControlStateNormal]; } @@ -56,6 +57,7 @@ - (void)configureButton:(UIButton *)button; - (void)configureSelectedButton:(UIButton *)button; { [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [button setTitleColor:[UIColor whiteColor] forState:UIControlStateDisabled]; [button setBackgroundImage:[self selectedBackgroundImage] forState:UIControlStateNormal]; [button setTitleShadowColor:[UIColor colorWithWhite:0.0f alpha:0.75f] forState:UIControlStateNormal]; button.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f / [UIScreen mainScreen].scale); @@ -77,8 +79,7 @@ - (void)createDayButtons; [button addTarget:self action:@selector(dateButtonPressed:) forControlEvents:UIControlEventTouchDown]; [dayButtons addObject:button]; [self.contentView addSubview:button]; - [self configureButton:button]; - [button setTitleColor:[self.textColor colorWithAlphaComponent:0.5f] forState:UIControlStateDisabled]; + [self configureButton:button]; } self.dayButtons = dayButtons; } @@ -118,8 +119,7 @@ - (void)setBeginningDate:(NSDate *)date; [self.notThisMonthButtons[index] setAccessibilityLabel:accessibilityLabel]; NSDateComponents *thisDateComponents = [self.calendar components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:date]; - - [self.dayButtons[index] setHidden:YES]; + [self.notThisMonthButtons[index] setHidden:YES]; NSInteger thisDayMonth = thisDateComponents.month; @@ -131,7 +131,6 @@ - (void)setBeginningDate:(NSDate *)date; } UIButton *button = self.dayButtons[index]; button.enabled = ![self.calendarView.delegate respondsToSelector:@selector(calendarView:shouldSelectDate:)] || [self.calendarView.delegate calendarView:self.calendarView shouldSelectDate:date]; - button.hidden = NO; } date = [self.calendar dateByAddingComponents:offset toDate:date options:0]; @@ -163,7 +162,7 @@ - (IBAction)dateButtonPressed:(id)sender; self.calendarView.selectedDate = ([self.calendarView.selectedDate isEqual:selectedDate]) ? nil : selectedDate; } else { if (self.calendarView.selectedEndDate) { - self.calendarView.selectedStartDate = selectedDate; + self.calendarView.selectedStartDate = nil; } else if (self.calendarView.selectedStartDate && ([selectedDate compare:self.calendarView.selectedStartDate] == NSOrderedDescending)) { self.calendarView.selectedEndDate = selectedDate; } else if ([self.calendarView.selectedStartDate isEqual:selectedDate]) { @@ -204,6 +203,9 @@ - (void)layoutViewsForColumnAtIndex:(NSUInteger)index inRect:(CGRect)rect; [self configureTodayButton:dayButton]; } else { [self configureButton:dayButton]; + if (!dayButton.enabled) { + [dayButton setTitleColor:[self.textColor colorWithAlphaComponent:0.5f] forState:UIControlStateNormal]; + } } } diff --git a/TimesSquare/TSQCalendarView.h b/TimesSquare/TSQCalendarView.h index 3346f37..24787cf 100644 --- a/TimesSquare/TSQCalendarView.h +++ b/TimesSquare/TSQCalendarView.h @@ -163,4 +163,30 @@ typedef enum { */ - (void)calendarView:(TSQCalendarView *)calendarView didSelectDate:(NSDate *)date; +/** Tells the delegate that a start date was selected for a range of dates. + + @param calendarView The calendar view that is selecting a date. + @param date Midnight on the date being selected. + */ +- (void)calendarView:(TSQCalendarView *)calendarView didSelectStartDate:(NSDate *)date; + +/** Tells the delegate that an end date was deselected for a range of dates. + + @param calendarView The calendar view that is deselecting a date. + */ +- (void)calendarViewDidDeselectStartDate:(TSQCalendarView *)calendarView; + +/** Tells the delegate that an end date was selected for a range of dates. + + @param calendarView The calendar view that is selecting a date. + @param date Midnight on the date being selected. + */ +- (void)calendarView:(TSQCalendarView *)calendarView didSelectEndDate:(NSDate *)date; + +/** Tells the delegate that an end date was deselected for a range of dates. + + @param calendarView The calendar view that is deselecting a date. + */ +- (void)calendarViewDidDeselectEndDate:(TSQCalendarView *)calendarView; + @end diff --git a/TimesSquare/TSQCalendarView.m b/TimesSquare/TSQCalendarView.m index c021f8d..32ccb44 100644 --- a/TimesSquare/TSQCalendarView.m +++ b/TimesSquare/TSQCalendarView.m @@ -202,6 +202,9 @@ - (void)setSelectedStartDate:(NSDate *)newSelectedStartDate { if (newSelectedStartDate == nil) { [self resetSelectedDates]; + if ([self.delegate respondsToSelector:@selector(calendarViewDidDeselectStartDate:)]) { + [self.delegate calendarViewDidDeselectStartDate:self]; + } return; } @@ -215,8 +218,8 @@ - (void)setSelectedStartDate:(NSDate *)newSelectedStartDate _selectedDates = @[startOfDay]; [self updateSelectedDates]; - if ([self.delegate respondsToSelector:@selector(calendarView:didSelectDate:)]) { - [self.delegate calendarView:self didSelectDate:startOfDay]; + if ([self.delegate respondsToSelector:@selector(calendarView:didSelectStartDate:)]) { + [self.delegate calendarView:self didSelectStartDate:startOfDay]; } } @@ -224,6 +227,9 @@ - (void)setSelectedEndDate:(NSDate *)newSelectedEndDate { if (newSelectedEndDate == nil) { [self resetSelectedDateRange]; + if ([self.delegate respondsToSelector:@selector(calendarViewDidDeselectEndDate:)]) { + [self.delegate calendarViewDidDeselectEndDate:self]; + } return; } @@ -237,8 +243,8 @@ - (void)setSelectedEndDate:(NSDate *)newSelectedEndDate _selectedDates = [self datesBetweenStart:_selectedStartDate AndEnd:startOfDay]; [self updateSelectedDates]; - if ([self.delegate respondsToSelector:@selector(calendarView:didSelectDate:)]) { - [self.delegate calendarView:self didSelectDate:startOfDay]; + if ([self.delegate respondsToSelector:@selector(calendarView:didSelectEndDate:)]) { + [self.delegate calendarView:self didSelectEndDate:startOfDay]; } } From 062efee493dc66fcd1401f0536405610dbfc90f0 Mon Sep 17 00:00:00 2001 From: Matt Grayson Date: Thu, 25 Apr 2013 09:33:43 -0500 Subject: [PATCH 4/8] Fixed scrollToDate:animated: to actually scroll to the date Was only scrolling to the month of the given date. Also added secondary method to allow customizing the scroll position. --- TimesSquare/TSQCalendarView.h | 10 +++++++++- TimesSquare/TSQCalendarView.m | 13 ++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/TimesSquare/TSQCalendarView.h b/TimesSquare/TSQCalendarView.h index 24787cf..aa86b54 100644 --- a/TimesSquare/TSQCalendarView.h +++ b/TimesSquare/TSQCalendarView.h @@ -129,13 +129,21 @@ typedef enum { */ @property (nonatomic, strong) Class rowCellClass; -/** Scrolls the receiver until the specified date month is completely visible. +/** Scrolls the receiver until the specified date month is completely visible at the top of the view. @param date A date that identifies the month that will be visible. @param animated YES if you want to animate the change in position, NO if it should be immediate. */ - (void)scrollToDate:(NSDate *)date animated:(BOOL)animated; +/** Scrolls the receiver until the specified date month is completely visible. + + @param date A date that identifies the month that will be visible. + @param animated YES if you want to animate the change in position, NO if it should be immediate. + @param scrollPosition The scroll position you want the view to use. + */ +- (void)scrollToDate:(NSDate *)date animated:(BOOL)animated atScrollPosition:(UITableViewScrollPosition)scrollPosition; + @end /** The methods in the `TSQCalendarViewDelegate` protocol allow the adopting delegate to either prevent a day from being selected or respond to it. diff --git a/TimesSquare/TSQCalendarView.m b/TimesSquare/TSQCalendarView.m index 32ccb44..4fd7e64 100644 --- a/TimesSquare/TSQCalendarView.m +++ b/TimesSquare/TSQCalendarView.m @@ -124,10 +124,17 @@ - (void)setLastDate:(NSDate *)lastDate; _lastDate = [self.calendar dateByAddingComponents:offsetComponents toDate:firstOfMonth options:0]; } -- (void)scrollToDate:(NSDate *)date animated:(BOOL)animated +- (void)scrollToDate:(NSDate *)date animated:(BOOL)animated; { - NSInteger section = [self sectionForDate:date]; - [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UITableViewScrollPositionTop animated:animated]; + [self scrollToDate:date animated:animated atScrollPosition:UITableViewScrollPositionTop]; +} + +- (void)scrollToDate:(NSDate *)date animated:(BOOL)animated atScrollPosition:(UITableViewScrollPosition)scrollPosition; +{ + NSIndexPath *path = [self indexPathForRowAtDate:date]; + if (path) { + [self.tableView scrollToRowAtIndexPath:path atScrollPosition:scrollPosition animated:animated]; + } } - (TSQCalendarMonthHeaderCell *)makeHeaderCellWithIdentifier:(NSString *)identifier; From 3ff0520a9ffd0eeefca5782a24476fffacd92f6a Mon Sep 17 00:00:00 2001 From: Matt Grayson Date: Thu, 25 Apr 2013 10:09:26 -0500 Subject: [PATCH 5/8] Tweaked scrollToDate:animated: to preserve @randomstep's change to take into account self.pinsHeaderToTop Also added date range selection demo to test app --- TimesSquare/TSQCalendarView.m | 8 +++++++- TimesSquareTestApp/TSQTAAppDelegate.m | 7 ++++++- TimesSquareTestApp/TSQTAViewController.h | 2 ++ TimesSquareTestApp/TSQTAViewController.m | 8 +++++++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/TimesSquare/TSQCalendarView.m b/TimesSquare/TSQCalendarView.m index 4fd7e64..6feb3a0 100644 --- a/TimesSquare/TSQCalendarView.m +++ b/TimesSquare/TSQCalendarView.m @@ -131,7 +131,13 @@ - (void)scrollToDate:(NSDate *)date animated:(BOOL)animated; - (void)scrollToDate:(NSDate *)date animated:(BOOL)animated atScrollPosition:(UITableViewScrollPosition)scrollPosition; { - NSIndexPath *path = [self indexPathForRowAtDate:date]; + NSIndexPath *path; + if (self.pinsHeaderToTop) { + NSInteger section = [self sectionForDate:date]; + path = [NSIndexPath indexPathForRow:0 inSection:section]; + } else { + path = [self indexPathForRowAtDate:date]; + } if (path) { [self.tableView scrollToRowAtIndexPath:path atScrollPosition:scrollPosition animated:animated]; } diff --git a/TimesSquareTestApp/TSQTAAppDelegate.m b/TimesSquareTestApp/TSQTAAppDelegate.m index e1972e8..af8c2c2 100644 --- a/TimesSquareTestApp/TSQTAAppDelegate.m +++ b/TimesSquareTestApp/TSQTAAppDelegate.m @@ -36,8 +36,13 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( persian.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSPersianCalendar]; persian.calendar.locale = [NSLocale currentLocale]; + TSQTAViewController *dateRange = [[TSQTAViewController alloc] init]; + dateRange.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + dateRange.calendar.locale = [NSLocale currentLocale]; + dateRange.selectionType = TSQCalendarSelectionDateRange; + UITabBarController *tabController = [[UITabBarController alloc] init]; - tabController.viewControllers = @[gregorian, hebrew, islamic, indian, persian]; + tabController.viewControllers = @[gregorian, hebrew, islamic, indian, persian, dateRange]; self.window.rootViewController = tabController; [self.window makeKeyAndVisible]; diff --git a/TimesSquareTestApp/TSQTAViewController.h b/TimesSquareTestApp/TSQTAViewController.h index be8d30e..0fcf9ac 100644 --- a/TimesSquareTestApp/TSQTAViewController.h +++ b/TimesSquareTestApp/TSQTAViewController.h @@ -8,9 +8,11 @@ // which Square, Inc. licenses this file to you. #import +#import @interface TSQTAViewController : UIViewController @property (nonatomic, strong) NSCalendar *calendar; +@property (nonatomic, assign) TSQCalendarSelectionType selectionType; @end diff --git a/TimesSquareTestApp/TSQTAViewController.m b/TimesSquareTestApp/TSQTAViewController.m index 170e8bc..1e69f04 100644 --- a/TimesSquareTestApp/TSQTAViewController.m +++ b/TimesSquareTestApp/TSQTAViewController.m @@ -9,7 +9,6 @@ #import "TSQTAViewController.h" #import "TSQTACalendarRowCell.h" -#import @interface TSQTAViewController () @@ -28,6 +27,12 @@ @interface TSQCalendarView (AccessingPrivateStuff) @implementation TSQTAViewController +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.selectionType = TSQCalendarSelectionDay; +} + - (void)loadView; { TSQCalendarView *calendarView = [[TSQCalendarView alloc] init]; @@ -37,6 +42,7 @@ - (void)loadView; calendarView.lastDate = [NSDate dateWithTimeIntervalSinceNow:60 * 60 * 24 * 365 * 5]; calendarView.backgroundColor = [UIColor colorWithRed:0.84f green:0.85f blue:0.86f alpha:1.0f]; calendarView.pagingEnabled = YES; + calendarView.selectionType = self.selectionType; CGFloat onePixel = 1.0f / [UIScreen mainScreen].scale; calendarView.contentInset = UIEdgeInsetsMake(0.0f, onePixel, 0.0f, onePixel); From 347e38698800b65061f7e29a8cfb45c444821b2a Mon Sep 17 00:00:00 2001 From: Matt Grayson Date: Thu, 2 May 2013 09:37:05 -0500 Subject: [PATCH 6/8] More calendar cell customization Added public properties for text shadow color, today's text color, today's shadow color. Also added public property to toggle display of dates that fall outside of the current month. --- TimesSquare/TSQCalendarCell.h | 24 ++++++++++++++++++++++++ TimesSquare/TSQCalendarCell.m | 6 +++++- TimesSquare/TSQCalendarRowCell.m | 13 +++++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/TimesSquare/TSQCalendarCell.h b/TimesSquare/TSQCalendarCell.h index 0f27f27..98e5724 100644 --- a/TimesSquare/TSQCalendarCell.h +++ b/TimesSquare/TSQCalendarCell.h @@ -59,18 +59,42 @@ */ @property (nonatomic, strong) UIColor *textColor; +/** The text shadow color. + + This is used for all text the cell draws; default is white. + */ +@property (nonatomic, strong) UIColor *shadowColor; + /** The text shadow offset. This is as you would set on `UILabel`. */ @property (nonatomic) CGSize shadowOffset; +/** The text color for today's date. + + White by default. + */ +@property (nonatomic, strong) UIColor *todayTextColor; + +/** The text shadow color for today's date. + + Black by default. + */ +@property (nonatomic, strong) UIColor *todayShadowColor; + /** The spacing between columns. This defaults to one pixel or `1.0 / [UIScreen mainScreen].scale`. */ @property (nonatomic) CGFloat columnSpacing; +/** Whether or not to display days that occur outside of the current month. + + Defaults to YES. + */ +@property (nonatomic) BOOL showsNotThisMonth; + /** @name Initialization */ /** Initializes the cell. diff --git a/TimesSquare/TSQCalendarCell.m b/TimesSquare/TSQCalendarCell.m index 99276c9..65fa9dc 100644 --- a/TimesSquare/TSQCalendarCell.m +++ b/TimesSquare/TSQCalendarCell.m @@ -42,7 +42,11 @@ - (id)initWithCalendar:(NSCalendar *)calendar reuseIdentifier:(NSString *)reuseI self.shadowOffset = shadowOffset; self.columnSpacing = onePixel; self.textColor = [UIColor colorWithRed:0.47f green:0.5f blue:0.53f alpha:1.0f]; - + self.shadowColor = [UIColor whiteColor]; + self.todayTextColor = [UIColor whiteColor]; + self.todayShadowColor = [UIColor colorWithWhite:0.0f alpha:0.75f]; + self.showsNotThisMonth = YES; + return self; } diff --git a/TimesSquare/TSQCalendarRowCell.m b/TimesSquare/TSQCalendarRowCell.m index 7639b80..2a528d0 100644 --- a/TimesSquare/TSQCalendarRowCell.m +++ b/TimesSquare/TSQCalendarRowCell.m @@ -65,9 +65,9 @@ - (void)configureSelectedButton:(UIButton *)button; - (void)configureTodayButton:(UIButton *)button; { - [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [button setTitleColor:self.todayTextColor forState:UIControlStateNormal]; [button setBackgroundImage:[self todayBackgroundImage] forState:UIControlStateNormal]; - [button setTitleShadowColor:[UIColor colorWithWhite:0.0f alpha:0.75f] forState:UIControlStateNormal]; + [button setTitleShadowColor:self.todayShadowColor forState:UIControlStateNormal]; button.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f / [UIScreen mainScreen].scale); } @@ -121,10 +121,15 @@ - (void)setBeginningDate:(NSDate *)date; NSDateComponents *thisDateComponents = [self.calendar components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:date]; [self.notThisMonthButtons[index] setHidden:YES]; - + [self.dayButtons[index] setHidden:NO]; + NSInteger thisDayMonth = thisDateComponents.month; if (self.monthOfBeginningDate != thisDayMonth) { - [self.notThisMonthButtons[index] setHidden:NO]; + if (self.showsNotThisMonth) { + [self.notThisMonthButtons[index] setHidden:NO]; + } else { + [self.dayButtons[index] setHidden:YES]; + } } else { if ([self.todayDateComponents isEqual:thisDateComponents]) { self.indexOfTodayButton = index; From f350cca0d538ef3308f9b30ae12f6197f1a0858c Mon Sep 17 00:00:00 2001 From: Matt Grayson Date: Thu, 2 May 2013 09:40:33 -0500 Subject: [PATCH 7/8] fix for archive fail The copy headers build phase wasn't making the headers available to the parent project (and breaking the ability to Archive the parent project). Moving headers to copy files build phase resolved the problem. Not sure this is the correct fix ... --- TimesSquare.xcodeproj/project.pbxproj | 24 ++++++++++--------- .../TimesSquare Documentation.xcscheme | 2 +- .../xcschemes/TimesSquare.xcscheme | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/TimesSquare.xcodeproj/project.pbxproj b/TimesSquare.xcodeproj/project.pbxproj index bb0983a..c627d27 100644 --- a/TimesSquare.xcodeproj/project.pbxproj +++ b/TimesSquare.xcodeproj/project.pbxproj @@ -13,11 +13,11 @@ A8068092167010030071C71E /* TSQCalendarRowCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A806808B167010030071C71E /* TSQCalendarRowCell.m */; }; A8068094167010030071C71E /* TSQCalendarView.m in Sources */ = {isa = PBXBuildFile; fileRef = A806808D167010030071C71E /* TSQCalendarView.m */; }; A80B62AB1672720C00792DFE /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A806809E167012980071C71E /* CoreGraphics.framework */; }; - EFD8DE6D167AF77B00F87FBE /* TimesSquare.h in Headers */ = {isa = PBXBuildFile; fileRef = A806806316700FD70071C71E /* TimesSquare.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EFD8DE6E167AF78100F87FBE /* TSQCalendarCell.h in Headers */ = {isa = PBXBuildFile; fileRef = A8068086167010030071C71E /* TSQCalendarCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EFD8DE6F167AF78600F87FBE /* TSQCalendarMonthHeaderCell.h in Headers */ = {isa = PBXBuildFile; fileRef = A8068088167010030071C71E /* TSQCalendarMonthHeaderCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EFD8DE70167AF78C00F87FBE /* TSQCalendarRowCell.h in Headers */ = {isa = PBXBuildFile; fileRef = A806808A167010030071C71E /* TSQCalendarRowCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EFD8DE71167AF79000F87FBE /* TSQCalendarView.h in Headers */ = {isa = PBXBuildFile; fileRef = A806808C167010030071C71E /* TSQCalendarView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AC0A147617314AEE0080B096 /* TSQCalendarCell.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = A8068086167010030071C71E /* TSQCalendarCell.h */; }; + AC0A147717314AEE0080B096 /* TSQCalendarMonthHeaderCell.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = A8068088167010030071C71E /* TSQCalendarMonthHeaderCell.h */; }; + AC0A147817314AEE0080B096 /* TSQCalendarRowCell.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = A806808A167010030071C71E /* TSQCalendarRowCell.h */; }; + AC0A147917314AEE0080B096 /* TSQCalendarView.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = A806808C167010030071C71E /* TSQCalendarView.h */; }; + AC0A147A173164B30080B096 /* TimesSquare.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = A806806316700FD70071C71E /* TimesSquare.h */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -27,6 +27,11 @@ dstPath = "include/${PRODUCT_NAME}"; dstSubfolderSpec = 16; files = ( + AC0A147A173164B30080B096 /* TimesSquare.h in CopyFiles */, + AC0A147617314AEE0080B096 /* TSQCalendarCell.h in CopyFiles */, + AC0A147717314AEE0080B096 /* TSQCalendarMonthHeaderCell.h in CopyFiles */, + AC0A147817314AEE0080B096 /* TSQCalendarRowCell.h in CopyFiles */, + AC0A147917314AEE0080B096 /* TSQCalendarView.h in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -123,11 +128,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - EFD8DE6D167AF77B00F87FBE /* TimesSquare.h in Headers */, - EFD8DE6E167AF78100F87FBE /* TSQCalendarCell.h in Headers */, - EFD8DE6F167AF78600F87FBE /* TSQCalendarMonthHeaderCell.h in Headers */, - EFD8DE70167AF78C00F87FBE /* TSQCalendarRowCell.h in Headers */, - EFD8DE71167AF79000F87FBE /* TSQCalendarView.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -175,7 +175,7 @@ A806805216700FD70071C71E /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0450; + LastUpgradeCheck = 0460; ORGANIZATIONNAME = Square; }; buildConfigurationList = A806805516700FD70071C71E /* Build configuration list for PBXProject "TimesSquare" */; @@ -293,6 +293,7 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COMBINE_HIDPI_IMAGES = YES; DEBUGGING_SYMBOLS = YES; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; @@ -310,6 +311,7 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/TimesSquare.xcodeproj/xcshareddata/xcschemes/TimesSquare Documentation.xcscheme b/TimesSquare.xcodeproj/xcshareddata/xcschemes/TimesSquare Documentation.xcscheme index 8790bd2..367fcc1 100644 --- a/TimesSquare.xcodeproj/xcshareddata/xcschemes/TimesSquare Documentation.xcscheme +++ b/TimesSquare.xcodeproj/xcshareddata/xcschemes/TimesSquare Documentation.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 9 May 2013 13:44:06 -0500 Subject: [PATCH 8/8] expose buttons on calendar row cell to allow further customization --- TimesSquare/TSQCalendarRowCell.h | 3 +++ TimesSquare/TSQCalendarRowCell.m | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TimesSquare/TSQCalendarRowCell.h b/TimesSquare/TSQCalendarRowCell.h index c045d57..e3bbaf1 100644 --- a/TimesSquare/TSQCalendarRowCell.h +++ b/TimesSquare/TSQCalendarRowCell.h @@ -73,4 +73,7 @@ */ - (void)deselectColumnForDate:(NSDate *)date; +@property (nonatomic, strong) NSArray *dayButtons; +@property (nonatomic, strong) NSArray *notThisMonthButtons; + @end diff --git a/TimesSquare/TSQCalendarRowCell.m b/TimesSquare/TSQCalendarRowCell.m index 2a528d0..3dc248d 100644 --- a/TimesSquare/TSQCalendarRowCell.m +++ b/TimesSquare/TSQCalendarRowCell.m @@ -16,9 +16,6 @@ @interface TSQCalendarRowCell () int buttonStates[7]; } -@property (nonatomic, strong) NSArray *dayButtons; -@property (nonatomic, strong) NSArray *notThisMonthButtons; - @property (nonatomic, assign) NSInteger indexOfTodayButton; @property (nonatomic, assign) NSInteger indexOfSelectedButton;