diff --git a/.gitignore b/.gitignore index debc8a9..15335e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,16 @@ -.DS_Store -.svn/ -build/ +# Xcode +*.DS_Store +build/* *.pbxuser +!default.pbxuser *.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +*.xcworkspace +!default.xcworkspace +xcuserdata +profile +*.moved-aside diff --git a/Calendar.xcodeproj/project.pbxproj b/Calendar.xcodeproj/project.pbxproj index 1122282..09c065f 100755 --- a/Calendar.xcodeproj/project.pbxproj +++ b/Calendar.xcodeproj/project.pbxproj @@ -25,9 +25,9 @@ 3B96AA7D1139BC99003FF405 /* GCCalendar.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B96AA621139BC99003FF405 /* GCCalendar.m */; }; 3B96AA7E1139BC99003FF405 /* GCCalendarDayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B96AA641139BC99003FF405 /* GCCalendarDayView.m */; }; 3B96AA7F1139BC99003FF405 /* GCCalendarEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B96AA661139BC99003FF405 /* GCCalendarEvent.m */; }; - 3B96AA801139BC99003FF405 /* GCCalendarPortraitView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B96AA681139BC99003FF405 /* GCCalendarPortraitView.m */; }; - 3B96AA811139BC99003FF405 /* GCCalendarTile.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B96AA6B1139BC99003FF405 /* GCCalendarTile.m */; }; - 3B96AA821139BC99003FF405 /* GCCalendarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B96AA6D1139BC99003FF405 /* GCCalendarView.m */; }; + 3B96AA801139BC99003FF405 /* GCCalendarPortraitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B96AA681139BC99003FF405 /* GCCalendarPortraitViewController.m */; }; + 3B96AA811139BC99003FF405 /* GCCalendarTileView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B96AA6B1139BC99003FF405 /* GCCalendarTileView.m */; }; + 3B96AA821139BC99003FF405 /* GCCalendarViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B96AA6D1139BC99003FF405 /* GCCalendarViewController.m */; }; 3B96AA831139BC99003FF405 /* GCDatePickerControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B96AA6F1139BC99003FF405 /* GCDatePickerControl.m */; }; 3B96AA841139BC99003FF405 /* GCDatePickerControlBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B96AA701139BC99003FF405 /* GCDatePickerControlBackground.png */; }; 3B96AA851139BC99003FF405 /* GCDatePickerControlLeft.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B96AA711139BC99003FF405 /* GCDatePickerControlLeft.png */; }; @@ -59,13 +59,13 @@ 3B96AA641139BC99003FF405 /* GCCalendarDayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCCalendarDayView.m; sourceTree = ""; }; 3B96AA651139BC99003FF405 /* GCCalendarEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCCalendarEvent.h; sourceTree = ""; }; 3B96AA661139BC99003FF405 /* GCCalendarEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCCalendarEvent.m; sourceTree = ""; }; - 3B96AA671139BC99003FF405 /* GCCalendarPortraitView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCCalendarPortraitView.h; sourceTree = ""; }; - 3B96AA681139BC99003FF405 /* GCCalendarPortraitView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCCalendarPortraitView.m; sourceTree = ""; }; + 3B96AA671139BC99003FF405 /* GCCalendarPortraitViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCCalendarPortraitViewController.h; sourceTree = ""; }; + 3B96AA681139BC99003FF405 /* GCCalendarPortraitViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCCalendarPortraitViewController.m; sourceTree = ""; }; 3B96AA691139BC99003FF405 /* GCCalendarProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCCalendarProtocols.h; sourceTree = ""; }; - 3B96AA6A1139BC99003FF405 /* GCCalendarTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCCalendarTile.h; sourceTree = ""; }; - 3B96AA6B1139BC99003FF405 /* GCCalendarTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCCalendarTile.m; sourceTree = ""; }; - 3B96AA6C1139BC99003FF405 /* GCCalendarView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCCalendarView.h; sourceTree = ""; }; - 3B96AA6D1139BC99003FF405 /* GCCalendarView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCCalendarView.m; sourceTree = ""; }; + 3B96AA6A1139BC99003FF405 /* GCCalendarTileView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCCalendarTileView.h; sourceTree = ""; }; + 3B96AA6B1139BC99003FF405 /* GCCalendarTileView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCCalendarTileView.m; sourceTree = ""; }; + 3B96AA6C1139BC99003FF405 /* GCCalendarViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCCalendarViewController.h; sourceTree = ""; }; + 3B96AA6D1139BC99003FF405 /* GCCalendarViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCCalendarViewController.m; sourceTree = ""; }; 3B96AA6E1139BC99003FF405 /* GCDatePickerControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDatePickerControl.h; sourceTree = ""; }; 3B96AA6F1139BC99003FF405 /* GCDatePickerControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDatePickerControl.m; sourceTree = ""; }; 3B96AA701139BC99003FF405 /* GCDatePickerControlBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = GCDatePickerControlBackground.png; sourceTree = ""; }; @@ -165,13 +165,13 @@ 3B96AA641139BC99003FF405 /* GCCalendarDayView.m */, 3B96AA651139BC99003FF405 /* GCCalendarEvent.h */, 3B96AA661139BC99003FF405 /* GCCalendarEvent.m */, - 3B96AA671139BC99003FF405 /* GCCalendarPortraitView.h */, - 3B96AA681139BC99003FF405 /* GCCalendarPortraitView.m */, + 3B96AA671139BC99003FF405 /* GCCalendarPortraitViewController.h */, + 3B96AA681139BC99003FF405 /* GCCalendarPortraitViewController.m */, 3B96AA691139BC99003FF405 /* GCCalendarProtocols.h */, - 3B96AA6A1139BC99003FF405 /* GCCalendarTile.h */, - 3B96AA6B1139BC99003FF405 /* GCCalendarTile.m */, - 3B96AA6C1139BC99003FF405 /* GCCalendarView.h */, - 3B96AA6D1139BC99003FF405 /* GCCalendarView.m */, + 3B96AA6A1139BC99003FF405 /* GCCalendarTileView.h */, + 3B96AA6B1139BC99003FF405 /* GCCalendarTileView.m */, + 3B96AA6C1139BC99003FF405 /* GCCalendarViewController.h */, + 3B96AA6D1139BC99003FF405 /* GCCalendarViewController.m */, 3B96AA6E1139BC99003FF405 /* GCDatePickerControl.h */, 3B96AA6F1139BC99003FF405 /* GCDatePickerControl.m */, 3B96AA701139BC99003FF405 /* GCDatePickerControlBackground.png */, @@ -208,7 +208,11 @@ isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Calendar" */; compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; hasScannedForEncodings = 1; + knownRegions = ( + en, + ); mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; projectDirPath = ""; projectRoot = ""; @@ -251,9 +255,9 @@ 3B96AA7D1139BC99003FF405 /* GCCalendar.m in Sources */, 3B96AA7E1139BC99003FF405 /* GCCalendarDayView.m in Sources */, 3B96AA7F1139BC99003FF405 /* GCCalendarEvent.m in Sources */, - 3B96AA801139BC99003FF405 /* GCCalendarPortraitView.m in Sources */, - 3B96AA811139BC99003FF405 /* GCCalendarTile.m in Sources */, - 3B96AA821139BC99003FF405 /* GCCalendarView.m in Sources */, + 3B96AA801139BC99003FF405 /* GCCalendarPortraitViewController.m in Sources */, + 3B96AA811139BC99003FF405 /* GCCalendarTileView.m in Sources */, + 3B96AA821139BC99003FF405 /* GCCalendarViewController.m in Sources */, 3B96AA831139BC99003FF405 /* GCDatePickerControl.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -277,6 +281,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = YES; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -291,6 +296,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = YES; COPY_PHASE_STRIP = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = Calendar_Prefix.pch; @@ -308,7 +314,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; - SDKROOT = iphoneos3.1.2; + SDKROOT = iphoneos; }; name = Debug; }; @@ -321,7 +327,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; - SDKROOT = iphoneos3.1.2; + SDKROOT = iphoneos; }; name = Release; }; diff --git a/Classes/CalendarAppDelegate.m b/Classes/CalendarAppDelegate.m index a3eda47..6b382a7 100644 --- a/Classes/CalendarAppDelegate.m +++ b/Classes/CalendarAppDelegate.m @@ -12,17 +12,17 @@ @implementation CalendarAppDelegate - (void)applicationDidFinishLaunching:(UIApplication *)application { // create calendar view - GCCalendarPortraitView *calendar = [[[GCCalendarPortraitView alloc] init] autorelease]; + GCCalendarPortraitViewController *calendar = [[GCCalendarPortraitViewController alloc] init]; calendar.dataSource = self; calendar.delegate = self; calendar.hasAddButton = YES; // create navigation view - UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:calendar] autorelease]; + UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:calendar]; // create tab controller tabController = [[UITabBarController alloc] init]; - tabController.viewControllers = [NSArray arrayWithObject:nav]; + tabController.viewControllers = @[nav]; // setup window window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; @@ -32,13 +32,10 @@ - (void)applicationDidFinishLaunching:(UIApplication *)application { - (void)dealloc { - [window release]; window = nil; - [tabController release]; tabController = nil; - [super dealloc]; } #pragma mark GCCalendarDataSource @@ -68,7 +65,6 @@ - (NSArray *)calendarEventsForDate:(NSDate *)date { event.endDate = [[NSCalendar currentCalendar] dateFromComponents:components]; [events addObject:event]; - [event release]; } @@ -83,23 +79,41 @@ - (NSArray *)calendarEventsForDate:(NSDate *)date { [components setHour:20]; evt.endDate = [[NSCalendar currentCalendar] dateFromComponents:components]; [events addObject:evt]; - [evt release]; + + evt = [[GCCalendarEvent alloc] init]; + evt.eventName = @"Test event"; + evt.eventDescription = @"Description for test event. This is intentionnaly too long to stay on a single line."; + [components setHour:17]; + [components setMinute:0]; + evt.startDate = [[NSCalendar currentCalendar] dateFromComponents:components]; + [components setHour:20]; + evt.endDate = [[NSCalendar currentCalendar] dateFromComponents:components]; + [events addObject:evt]; + evt = [[GCCalendarEvent alloc] init]; + evt.eventName = @"Test event"; + [components setHour:19]; + [components setMinute:0]; + evt.startDate = [[NSCalendar currentCalendar] dateFromComponents:components]; + [components setHour:20]; + [components setMinute:30]; + evt.endDate = [[NSCalendar currentCalendar] dateFromComponents:components]; + [events addObject:evt]; + // create an all day event GCCalendarEvent *event = [[GCCalendarEvent alloc] init]; event.allDayEvent = YES; event.eventName = @"All Day Event"; [events addObject:event]; - [event release]; return events; } #pragma mark GCCalendarDelegate -- (void)calendarTileTouchedInView:(GCCalendarView *)view withEvent:(GCCalendarEvent *)event { +- (void)calendarTileTouchedInView:(GCCalendarViewController *)view withEvent:(GCCalendarEvent *)event { NSLog(@"Touch event %@", event.eventName); } -- (void)calendarViewAddButtonPressed:(GCCalendarView *)view { +- (void)calendarViewAddButtonPressed:(GCCalendarViewController *)view { NSLog(@"%s", __PRETTY_FUNCTION__); } diff --git a/GCCalendar/Calendar-Tile-Base.png b/GCCalendar/Calendar-Tile-Base.png new file mode 100644 index 0000000..4202b19 Binary files /dev/null and b/GCCalendar/Calendar-Tile-Base.png differ diff --git a/GCCalendar/Calendar-Tile-Base@2x.png b/GCCalendar/Calendar-Tile-Base@2x.png new file mode 100644 index 0000000..cf8c683 Binary files /dev/null and b/GCCalendar/Calendar-Tile-Base@2x.png differ diff --git a/GCCalendar/CalendarBubbleBlue.png b/GCCalendar/CalendarBubbleBlue.png deleted file mode 100644 index c62ce21..0000000 Binary files a/GCCalendar/CalendarBubbleBlue.png and /dev/null differ diff --git a/GCCalendar/CalendarBubbleGreen.png b/GCCalendar/CalendarBubbleGreen.png deleted file mode 100644 index 5208efe..0000000 Binary files a/GCCalendar/CalendarBubbleGreen.png and /dev/null differ diff --git a/GCCalendar/CalendarBubbleGrey.png b/GCCalendar/CalendarBubbleGrey.png deleted file mode 100644 index 8816666..0000000 Binary files a/GCCalendar/CalendarBubbleGrey.png and /dev/null differ diff --git a/GCCalendar/CalendarBubbleMagenta.png b/GCCalendar/CalendarBubbleMagenta.png deleted file mode 100644 index deef8e3..0000000 Binary files a/GCCalendar/CalendarBubbleMagenta.png and /dev/null differ diff --git a/GCCalendar/CalendarBubbleOrange.png b/GCCalendar/CalendarBubbleOrange.png deleted file mode 100644 index 5f8af52..0000000 Binary files a/GCCalendar/CalendarBubbleOrange.png and /dev/null differ diff --git a/GCCalendar/CalendarBubblePurple.png b/GCCalendar/CalendarBubblePurple.png deleted file mode 100644 index 9140e5a..0000000 Binary files a/GCCalendar/CalendarBubblePurple.png and /dev/null differ diff --git a/GCCalendar/CalendarBubbleRed.png b/GCCalendar/CalendarBubbleRed.png deleted file mode 100644 index 4621e60..0000000 Binary files a/GCCalendar/CalendarBubbleRed.png and /dev/null differ diff --git a/GCCalendar/CalendarBubbleYellow.png b/GCCalendar/CalendarBubbleYellow.png deleted file mode 100644 index 0a2f14f..0000000 Binary files a/GCCalendar/CalendarBubbleYellow.png and /dev/null differ diff --git a/GCCalendar/EAGlossyBox.h b/GCCalendar/EAGlossyBox.h new file mode 100644 index 0000000..f50daf7 --- /dev/null +++ b/GCCalendar/EAGlossyBox.h @@ -0,0 +1,17 @@ +// +// EAGlossyBox.h +// EventApp +// +// Created by Jon Manning on 29/08/12. +// Copyright (c) 2012 Secret Lab. All rights reserved. +// + +#import + +@interface EAGlossyBox : UIView + +@property (assign) CGFloat radius; + +- (void) setColor:(UIColor*)color; + +@end diff --git a/GCCalendar/EAGlossyBox.m b/GCCalendar/EAGlossyBox.m new file mode 100644 index 0000000..5cf60af --- /dev/null +++ b/GCCalendar/EAGlossyBox.m @@ -0,0 +1,62 @@ +// +// EAGlossyBox.m +// EventApp +// +// Created by Jon Manning on 29/08/12. +// Copyright (c) 2012 Secret Lab. All rights reserved. +// + +#import "EAGlossyBox.h" +#import + +@interface EAGlossyBox () { + UIImageView* _glossImage; +} + +@end + +@implementation EAGlossyBox + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + self.layer.cornerRadius = 5; + self.layer.borderColor = [UIColor colorWithWhite:0 alpha:0.2].CGColor; + self.layer.borderWidth = 1; + + + _glossImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Calendar-Tile-Gloss-Pattern"]]; + [self addSubview:_glossImage]; + self.clipsToBounds = YES; + + } + return self; +} + +// If we're in a UITableViewCell, when selected we appear to receive +// a call to setBackgroundColor: that sets our color to clear. +// We only want to do this when the 'color' property is set, +// so ignore this call. +- (void)setBackgroundColor:(UIColor *)backgroundColor { + +} + +- (void)setColor:(UIColor *)color { + [super setBackgroundColor:color]; +} + +- (void)layoutSubviews { + _glossImage.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(_glossImage.bounds)); +} + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} +*/ + +@end diff --git a/GCCalendar/EATintedImageView.h b/GCCalendar/EATintedImageView.h new file mode 100644 index 0000000..eb93492 --- /dev/null +++ b/GCCalendar/EATintedImageView.h @@ -0,0 +1,16 @@ +// +// EATintedImageView.h +// EventApp +// +// Created by Jon Manning on 28/08/12. +// Copyright (c) 2012 Secret Lab. All rights reserved. +// + +#import + +@interface EATintedImageView : UIView + +@property (strong) UIImage* image; +@property (strong) UIColor* overlayColor; + +@end diff --git a/GCCalendar/EATintedImageView.m b/GCCalendar/EATintedImageView.m new file mode 100644 index 0000000..8b8bc8e --- /dev/null +++ b/GCCalendar/EATintedImageView.m @@ -0,0 +1,46 @@ +// +// EATintedImageView.m +// EventApp +// +// Created by Jon Manning on 28/08/12. +// Copyright (c) 2012 Secret Lab. All rights reserved. +// + +#import "EATintedImageView.h" + +@implementation EATintedImageView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} + +- (void) drawRect:(CGRect)area +{ + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSaveGState(context); + + [self.image drawInRect:self.bounds]; + + if (self.overlayColor) { + CGContextSetBlendMode (context, kCGBlendModeHue); + CGContextSetFillColor(context, CGColorGetComponents(self.overlayColor.CGColor)); + CGContextFillRect (context, self.bounds); + } + CGContextRestoreGState(context); +} + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} +*/ + +@end diff --git a/GCCalendar/GCCalendar.h b/GCCalendar/GCCalendar.h index 7966955..15cbead 100644 --- a/GCCalendar/GCCalendar.h +++ b/GCCalendar/GCCalendar.h @@ -10,10 +10,10 @@ #import -#import "GCCalendarView.h" +#import "GCCalendarViewController.h" #import "GCCalendarEvent.h" #import "GCCalendarProtocols.h" -#import "GCCalendarPortraitView.h" +#import "GCCalendarPortraitViewController.h" // calendar notificaions static NSString * const GCCalendarShouldReloadNotification = @"GCCalendarShouldReload"; diff --git a/GCCalendar/GCCalendar.m b/GCCalendar/GCCalendar.m index 76a17ff..35f4d78 100644 --- a/GCCalendar/GCCalendar.m +++ b/GCCalendar/GCCalendar.m @@ -65,7 +65,7 @@ + (NSDateFormatter *)timeFormatter { #pragma mark color list + (NSArray *)colors { if (colors == nil) { - colors = [[NSArray arrayWithObjects:@"BLUE", @"GREEN", @"ORANGE", @"MAGENTA", @"PURPLE", @"RED", @"YELLOW", nil] retain]; + colors = @[@"BLUE", @"GREEN", @"ORANGE", @"MAGENTA", @"PURPLE", @"RED", @"YELLOW"]; } return colors; diff --git a/GCCalendar/GCCalendarDayView.h b/GCCalendar/GCCalendarDayView.h index 22155dd..0e98dae 100644 --- a/GCCalendar/GCCalendarDayView.h +++ b/GCCalendar/GCCalendarDayView.h @@ -33,7 +33,7 @@ id dataSource; } -@property (nonatomic, retain) NSDate *date; +@property (nonatomic, strong) NSDate *date; /* accessor methods for accessing the contentOffset of the scroll view. this is used to keep the scroll position the same from one day view @@ -41,7 +41,16 @@ */ @property (nonatomic) CGPoint contentOffset; -- (id)initWithCalendarView:(GCCalendarView *)view; +- (id)initWithCalendarView:(GCCalendarViewController *)view; - (void)reloadData; +@property (retain) UIColor* outsideHoursColor; +@property (retain) UIColor* officeHoursColor; +@property (retain) UIColor* hourMarkerColor; +@property (retain) UIColor* timeColor; +@property (retain) UIColor* AMPMColor; + +- (void) scrollToHour:(CGFloat)hour; +- (void) scrollToHour:(CGFloat)hour animated:(BOOL)animated; + @end diff --git a/GCCalendar/GCCalendarDayView.m b/GCCalendar/GCCalendarDayView.m index 7168abd..ad4a58a 100644 --- a/GCCalendar/GCCalendarDayView.m +++ b/GCCalendar/GCCalendarDayView.m @@ -9,8 +9,8 @@ // #import "GCCalendarDayView.h" -#import "GCCalendarTile.h" -#import "GCCalendarView.h" +#import "GCCalendarTileView.h" +#import "GCCalendarViewController.h" #import "GCCalendarEvent.h" #import "GCCalendar.h" @@ -19,7 +19,7 @@ #define kTopLineBuffer 11.0 #define kSideLineBuffer 50.0 -#define kHalfHourDiff 22.0 +#define kHalfHourDiff 44.0 static NSArray *timeStrings; @@ -36,15 +36,14 @@ @implementation GCCalendarAllDayView - (id)initWithEvents:(NSArray *)a { if (self = [super init]) { NSPredicate *pred = [NSPredicate predicateWithFormat:@"allDayEvent == YES"]; - events = [[a filteredArrayUsingPredicate:pred] retain]; + events = [a filteredArrayUsingPredicate:pred]; NSInteger eventCount = 0; for (GCCalendarEvent *e in events) { if (eventCount < 5) { - GCCalendarTile *tile = [[GCCalendarTile alloc] init]; + GCCalendarTileView *tile = [[GCCalendarTileView alloc] init]; tile.event = e; [self addSubview:tile]; - [tile release]; eventCount++; } @@ -54,10 +53,8 @@ - (id)initWithEvents:(NSArray *)a { return self; } - (void)dealloc { - [events release]; events = nil; - [super dealloc]; } - (BOOL)hasEvents { return ([events count] != 0); @@ -78,7 +75,7 @@ - (void)layoutSubviews { for (UIView *view in self.subviews) { // get calendar tile and associated event - GCCalendarTile *tile = (GCCalendarTile *)view; + GCCalendarTileView *tile = (GCCalendarTileView *)view; tile.frame = CGRectMake(kTileLeftSide, start_y, @@ -114,26 +111,31 @@ - (void)drawRect:(CGRect)rect { @interface GCCalendarTodayView : UIView { NSArray *events; + __weak GCCalendarDayView *_dayView; } -- (id)initWithEvents:(NSArray *)a; +- (id)initWithEvents:(NSArray *)a dayView:(GCCalendarDayView*)dayView; - (BOOL)hasEvents; + (CGFloat)yValueForTime:(CGFloat)time; @end @implementation GCCalendarTodayView -- (id)initWithEvents:(NSArray *)a { +- (id)initWithEvents:(NSArray *)a dayView:(GCCalendarDayView *)dayView { if (self = [super init]) { + + _dayView = dayView; + NSPredicate *pred = [NSPredicate predicateWithFormat:@"allDayEvent == NO"]; - events = [[a filteredArrayUsingPredicate:pred] retain]; + events = [a filteredArrayUsingPredicate:pred]; for (GCCalendarEvent *e in events) { - GCCalendarTile *tile = [[GCCalendarTile alloc] init]; + GCCalendarTileView *tile = [[GCCalendarTileView alloc] init]; tile.event = e; [self addSubview:tile]; - [tile release]; } + + self.backgroundColor = [UIColor clearColor]; } return self; @@ -142,26 +144,20 @@ - (BOOL)hasEvents { return ([events count] != 0); } - (void)dealloc { - [events release]; events = nil; - [super dealloc]; } - (void)layoutSubviews { for (UIView *view in self.subviews) { // get calendar tile and associated event - GCCalendarTile *tile = (GCCalendarTile *)view; + GCCalendarTileView *tile = (GCCalendarTileView *)view; - NSDateComponents *components; - components = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | - NSMinuteCalendarUnit) - fromDate:tile.event.startDate]; + NSDateComponents *components; + components = tile.event.startDateComponents; NSInteger startHour = [components hour]; NSInteger startMinute = [components minute]; - components = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | - NSMinuteCalendarUnit) - fromDate:tile.event.endDate]; + components = tile.event.endDateComponents; NSInteger endHour = [components hour]; NSInteger endMinute = [components minute]; @@ -172,18 +168,21 @@ - (void)layoutSubviews { CGFloat endPos = kTopLineBuffer + endHour * 2 * kHalfHourDiff + 3; endPos += (endMinute / 60.0) * (kHalfHourDiff * 2.0); endPos = floor(endPos); + + NSInteger columnWidth = (self.bounds.size.width - kTileLeftSide - kTileRightSide) / tile.event.intersectingEvents.count; + NSInteger columnNumber = tile.event.column; - tile.frame = CGRectMake(kTileLeftSide, + tile.frame = CGRectMake(kTileLeftSide + (columnWidth * columnNumber), startPos, - self.bounds.size.width - kTileLeftSide - kTileRightSide, + columnWidth, endPos - startPos); } } - (void)drawRect:(CGRect)rect { // grab current graphics context CGContextRef g = UIGraphicsGetCurrentContext(); - - CGContextSetRGBFillColor(g, (242.0 / 255.0), (242.0 / 255.0), (242.0 / 255.0), 1.0); + + CGContextSetFillColorWithColor(g, _dayView.outsideHoursColor.CGColor); // fill morning hours light grey CGFloat morningHourMax = [GCCalendarTodayView yValueForTime:(CGFloat)8]; @@ -196,14 +195,16 @@ - (void)drawRect:(CGRect)rect { CGContextFillRect(g, eveningHours); // fill day hours white - CGContextSetRGBFillColor(g, 1.0, 1.0, 1.0, 1.0); + + CGContextSetFillColorWithColor(g, _dayView.officeHoursColor.CGColor); + CGRect dayHours = CGRectMake(0, morningHourMax - 1, self.frame.size.width, eveningHourMax - morningHourMax); CGContextFillRect(g, dayHours); // draw hour lines CGContextSetShouldAntialias(g, NO); const CGFloat solidPattern[2] = {1.0, 0.0}; - CGContextSetRGBStrokeColor(g, 0.0, 0.0, 0.0, .3); + CGContextSetStrokeColorWithColor(g, _dayView.hourMarkerColor.CGColor); CGContextSetLineDash(g, 0, solidPattern, 2); for (NSInteger i = 0; i < 25; i++) { CGFloat yVal = [GCCalendarTodayView yValueForTime:(CGFloat)i]; @@ -215,8 +216,10 @@ - (void)drawRect:(CGRect)rect { // draw half hour lines CGContextSetShouldAntialias(g, NO); const CGFloat dashPattern[2] = {1.0, 1.0}; - CGContextSetRGBStrokeColor(g, 0.0, 0.0, 0.0, .2); - CGContextSetLineDash(g, 0, dashPattern, 2); + + CGContextSetStrokeColorWithColor(g, _dayView.hourMarkerColor.CGColor); + + CGContextSetLineDash(g, 0, dashPattern, 2); for (NSInteger i = 0; i < 24; i++) { CGFloat time = (CGFloat)i + 0.5f; CGFloat yVal = [GCCalendarTodayView yValueForTime:time]; @@ -227,7 +230,7 @@ - (void)drawRect:(CGRect)rect { // draw hour numbers CGContextSetShouldAntialias(g, YES); - [[UIColor blackColor] set]; + [_dayView.timeColor set]; UIFont *numberFont = [UIFont boldSystemFontOfSize:14.0]; for (NSInteger i = 0; i < 25; i++) { CGFloat yVal = [GCCalendarTodayView yValueForTime:(CGFloat)i]; @@ -254,7 +257,7 @@ - (void)drawRect:(CGRect)rect { // draw am / pm text CGContextSetShouldAntialias(g, YES); - [[UIColor grayColor] set]; + [_dayView.AMPMColor set]; UIFont *textFont = [UIFont systemFontOfSize:12.0]; for (NSInteger i = 0; i < 25; i++) { NSString *text = nil; @@ -276,7 +279,7 @@ - (void)drawRect:(CGRect)rect { } } + (CGFloat)yValueForTime:(CGFloat)time { - return kTopLineBuffer + (44.0f * time);; + return kTopLineBuffer + (88.0f * time);; } @end @@ -287,34 +290,96 @@ @implementation GCCalendarDayView #pragma mark create and destroy view + (void)initialize { if(self == [GCCalendarDayView class]) { - timeStrings = [[NSArray arrayWithObjects:@"12", + timeStrings = @[@"12", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11", - [[NSBundle mainBundle] localizedStringForKey:@"NOON" value:@"" table:@"GCCalendar"], - @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11", @"12", nil] - retain]; + @"Noon", + @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11", @"12"]; } } -- (id)initWithCalendarView:(GCCalendarView *)view { +- (id)initWithCalendarView:(GCCalendarViewController *)view { if (self = [super init]) { dataSource = view.dataSource; + + self.outsideHoursColor = [UIColor colorWithRed:(242.0 / 255.0) green:(242.0 / 255.0) blue:(242.0 / 255.0) alpha:1.0]; + + self.officeHoursColor = [UIColor whiteColor]; + self.hourMarkerColor = [[UIColor blackColor] colorWithAlphaComponent:0.2]; + + self.timeColor = [UIColor blackColor]; + self.AMPMColor = [UIColor darkGrayColor]; + + self.backgroundColor = [UIColor clearColor]; + self.opaque = NO; } return self; } -- (void)dealloc { - self.date = nil; - - [super dealloc]; -} - (void)reloadData { // get new events for date events = [dataSource calendarEventsForDate:date]; - + + // sort the events by start date + events = [events sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"startDate" ascending:YES]]]; + + // figure out which events intersect (yay, O(n^2)) + for (GCCalendarEvent* event in events) { + + NSMutableArray* intersectingEvents = [NSMutableArray array]; + + for (GCCalendarEvent* otherEvent in events) { + if ([event intersectsEvent:otherEvent]) + [intersectingEvents addObject:otherEvent]; + } + + + event.intersectingEvents = intersectingEvents; + } + + // Remove intersecting events from the list if two events do not intersect with each other + for (GCCalendarEvent* event in events){ + NSMutableArray* intersectingEvents = [NSMutableArray arrayWithArray:event.intersectingEvents]; + NSMutableArray* intersectingEventsToRemove = [NSMutableArray array]; + + for (GCCalendarEvent* otherEvent in intersectingEvents) { + BOOL intersecting = YES; + for (GCCalendarEvent* intersectingOtherEvent in intersectingEvents) { + if ([otherEvent intersectsEvent:intersectingOtherEvent] == NO) { + intersecting = NO; + break; + } + } + if (intersecting == NO) { + [intersectingEventsToRemove addObject:otherEvent]; + break; + } + + } + + [intersectingEvents removeObjectsInArray:intersectingEventsToRemove]; + + event.intersectingEvents = intersectingEvents; + } + + // Reload theming info + if ([dataSource respondsToSelector:@selector(outsideHoursColor)]) + self.outsideHoursColor = [dataSource outsideHoursColor]; + + if ([dataSource respondsToSelector:@selector(hourMarkerColor)]) + self.hourMarkerColor = [dataSource hourMarkerColor]; + + if ([dataSource respondsToSelector:@selector(timeColor)]) + self.timeColor = [dataSource timeColor]; + + if ([dataSource respondsToSelector:@selector(hourMarkerColor)]) + self.AMPMColor = [dataSource AMPMColor]; + + if ([dataSource respondsToSelector:@selector(officeHoursColor)]) + self.officeHoursColor = [dataSource officeHoursColor]; + + + // drop all subviews [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; - [allDayView release]; - [todayView release]; - [scrollView release]; // create all day view allDayView = [[GCCalendarAllDayView alloc] initWithEvents:events]; @@ -325,24 +390,38 @@ - (void)reloadData { // create scroll view scrollView = [[UIScrollView alloc] init]; - scrollView.backgroundColor = [UIColor colorWithRed:(242.0 / 255.0) green:(242.0 / 255.0) blue:(242.0 / 255.0) alpha:1.0]; scrollView.frame = CGRectMake(0, allDayView.frame.size.height, self.frame.size.width, self.frame.size.height - allDayView.frame.size.height); - scrollView.contentSize = CGSizeMake(self.frame.size.width, 1078); + scrollView.contentSize = CGSizeMake(self.frame.size.width, 2156); scrollView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); [self addSubview:scrollView]; + scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite; + scrollView.backgroundColor = [UIColor clearColor]; + + + scrollView.contentInset = UIEdgeInsetsMake(-[GCCalendarTodayView yValueForTime:7.9], 0, -[GCCalendarTodayView yValueForTime:2], 0); // create today view - todayView = [[GCCalendarTodayView alloc] initWithEvents:events]; - todayView.frame = CGRectMake(0, 0, self.frame.size.width, 1078); + todayView = [[GCCalendarTodayView alloc] initWithEvents:events dayView:self]; + todayView.frame = CGRectMake(0, 0, self.frame.size.width, 2156); todayView.autoresizingMask = UIViewAutoresizingFlexibleWidth; [scrollView addSubview:todayView]; } -- (void)setContentOffset:(CGPoint)p { - scrollView.contentOffset = p; + +- (void)setContentOffset:(CGPoint)contentOffset { + scrollView.contentOffset = contentOffset; } + - (CGPoint)contentOffset { return scrollView.contentOffset; } +- (void) scrollToHour:(CGFloat)hour animated:(BOOL)animated { + [scrollView setContentOffset:CGPointMake(0, [GCCalendarTodayView yValueForTime:hour]) animated:animated]; +} + +-(void)scrollToHour:(CGFloat)hour { + [self scrollToHour:hour animated:NO]; +} + @end \ No newline at end of file diff --git a/GCCalendar/GCCalendarEvent.h b/GCCalendar/GCCalendarEvent.h index f970dc1..b85a4ea 100644 --- a/GCCalendar/GCCalendarEvent.h +++ b/GCCalendar/GCCalendarEvent.h @@ -22,32 +22,25 @@ represents. Ex. in CoreData based applications, userInfo could be the objectID of a managed object. */ -@interface GCCalendarEvent : NSObject { - // name of the event - NSString *eventName; - // event description - NSString *eventDescription; - - // start date - NSDate *startDate; - // end date - NSDate *endDate; - - // color - NSString *color; - // is this an all day event - BOOL allDayEvent; - - // contextual information - id userInfo; -} +@interface GCCalendarEvent : NSObject @property (nonatomic, copy) NSString *eventName; @property (nonatomic, copy) NSString *eventDescription; @property (nonatomic, copy) NSDate *startDate; @property (nonatomic, copy) NSDate *endDate; -@property (nonatomic, copy) NSString *color; -@property (nonatomic, retain) id userInfo; +@property (nonatomic, strong) id userInfo; @property (nonatomic) BOOL allDayEvent; +@property (readonly) NSDateComponents* startDateComponents; +@property (readonly) NSDateComponents* endDateComponents; + +// If set, this image will be displayed at the right of the title. +@property (nonatomic, strong) UIImage* image; + +@property (nonatomic, copy) NSArray* intersectingEvents; +@property (readonly) NSInteger column; +@property (nonatomic, strong) UIColor* color; + +- (BOOL) intersectsEvent:(GCCalendarEvent*)otherEvent; + @end diff --git a/GCCalendar/GCCalendarEvent.m b/GCCalendar/GCCalendarEvent.m index a40685b..a315c4b 100644 --- a/GCCalendar/GCCalendarEvent.m +++ b/GCCalendar/GCCalendarEvent.m @@ -12,30 +12,61 @@ @implementation GCCalendarEvent -@synthesize eventName; -@synthesize eventDescription; -@synthesize startDate; -@synthesize endDate; -@synthesize allDayEvent; -@synthesize color; -@synthesize userInfo; +@synthesize startDateComponents = _startDateComponents; +@synthesize endDateComponents = _endDateComponents; - (id)init { if (self = [super init]) { - self.color = @"GREY"; + } return self; } -- (void)dealloc { - self.eventName = nil; - self.eventDescription = nil; - self.startDate = nil; - self.endDate = nil; - self.color = nil; - - [super dealloc]; +- (BOOL) intersectsEvent:(GCCalendarEvent*)otherEvent { + + NSTimeInterval myStartDateTime = self.startDate.timeIntervalSinceReferenceDate; + NSTimeInterval myEndDateTime = self.endDate.timeIntervalSinceReferenceDate; + + NSTimeInterval theirStartDateTime = otherEvent.startDate.timeIntervalSinceReferenceDate; + NSTimeInterval theirEndDateTime = otherEvent.endDate.timeIntervalSinceReferenceDate; + + if (myEndDateTime == theirStartDateTime || myStartDateTime == theirEndDateTime) + return NO; + + return (myStartDateTime <= theirEndDateTime) && (myEndDateTime >= theirStartDateTime); +} + +- (NSInteger)column { + return [self.intersectingEvents indexOfObject:self]; +} + +- (void)setStartDate:(NSDate *)startDate { + _startDate = startDate; + _startDateComponents = nil; +} + +- (void)setEndDate:(NSDate *)endDate { + _endDate = endDate; + _endDateComponents = nil; +} + +- (NSDateComponents *)startDateComponents { + if (_startDateComponents == nil) { + _startDateComponents = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | + NSMinuteCalendarUnit) + fromDate:self.startDate]; + } + return _startDateComponents; +} + +- (NSDateComponents *)endDateComponents { + if (_endDateComponents == nil) { + _endDateComponents = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | + NSMinuteCalendarUnit) + fromDate:self.endDate]; + } + return _endDateComponents; } @end diff --git a/GCCalendar/GCCalendarPortraitView.h b/GCCalendar/GCCalendarPortraitViewController.h similarity index 87% rename from GCCalendar/GCCalendarPortraitView.h rename to GCCalendar/GCCalendarPortraitViewController.h index 1af3a18..ac60004 100644 --- a/GCCalendar/GCCalendarPortraitView.h +++ b/GCCalendar/GCCalendarPortraitViewController.h @@ -10,7 +10,8 @@ #import -#import "GCCalendarView.h" +#import "GCCalendarViewController.h" +#import "GCDatePickerControl.h" @class GCDatePickerControl; @class GCCalendarDayView; @@ -27,7 +28,7 @@ push a detailed view controller onto the stack with more information about the event (currently unimplemnted) */ -@interface GCCalendarPortraitView : GCCalendarView { +@interface GCCalendarPortraitViewController : GCCalendarViewController { // date the view will display NSDate *date; @@ -49,4 +50,6 @@ @property (nonatomic, assign) BOOL hasAddButton; +- (void) reloadData; + @end diff --git a/GCCalendar/GCCalendarPortraitView.m b/GCCalendar/GCCalendarPortraitViewController.m similarity index 57% rename from GCCalendar/GCCalendarPortraitView.m rename to GCCalendar/GCCalendarPortraitViewController.m index d3eaae1..208b924 100644 --- a/GCCalendar/GCCalendarPortraitView.m +++ b/GCCalendar/GCCalendarPortraitViewController.m @@ -8,64 +8,32 @@ // Copyright GUI Cocoa Software 2010. All rights reserved. // -#import "GCCalendarPortraitView.h" +#import "GCCalendarPortraitViewController.h" #import "GCCalendarDayView.h" -#import "GCCalendarTile.h" +#import "GCCalendarTileView.h" #import "GCDatePickerControl.h" #import "GCCalendar.h" #define kAnimationDuration 0.3f -@interface GCCalendarPortraitView () -@property (nonatomic, retain) NSDate *date; -@property (nonatomic, retain) GCCalendarDayView *dayView; +@interface GCCalendarPortraitViewController () +@property (nonatomic, strong) NSDate *date; +@property (nonatomic, strong) GCCalendarDayView *dayView; - (void)reloadDayAnimated:(BOOL)animated context:(void *)context; @end -@implementation GCCalendarPortraitView +@implementation GCCalendarPortraitViewController @synthesize date, dayView, hasAddButton; -#pragma mark create and destroy view -- (id)init { - if(self = [super init]) { - self.title = [[NSBundle mainBundle] localizedStringForKey:@"CALENDAR" value:@"" table:@"GCCalendar"]; - self.tabBarItem.image = [UIImage imageNamed:@"Calendar.png"]; - - viewDirty = YES; - viewVisible = NO; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(calendarTileTouch:) - name:__GCCalendarTileTouchNotification - object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(calendarShouldReload:) - name:GCCalendarShouldReloadNotification - object:nil]; - } - - return self; -} -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - self.date = nil; - self.dayView = nil; - - [dayPicker release]; - - [super dealloc]; -} - #pragma mark calendar actions - (void)calendarShouldReload:(NSNotification *)notif { viewDirty = YES; } - (void)calendarTileTouch:(NSNotification *)notif { if (delegate != nil) { - GCCalendarTile *tile = [notif object]; + GCCalendarTileView *tile = [notif object]; [delegate calendarTileTouchedInView:self withEvent:[tile event]]; } } @@ -78,18 +46,38 @@ - (void)datePickerDidChangeDate:(GCDatePickerControl *)picker { [[NSUserDefaults standardUserDefaults] setObject:date forKey:@"GCCalendarDate"]; - [self reloadDayAnimated:YES context:[NSNumber numberWithInt:interval]]; + [self reloadDayAnimated:YES context:(__bridge void *)([NSNumber numberWithInt:interval])]; } #pragma mark button actions - (void)today { - dayPicker.date = [NSDate date]; + + CGFloat hour; + + CGPoint currentContentOffset = self.dayView.contentOffset; + if (dayPicker.delegate && [dayPicker.delegate datePickerControl:dayPicker willChangeToDate:[NSDate date]] == NO) { + dayPicker.date = [[NSUserDefaults standardUserDefaults] objectForKey:@"start_date"]; + hour = 9; + } else { + dayPicker.date = [NSDate date]; + NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + NSDateComponents* components = [calendar components:NSHourCalendarUnit fromDate:[NSDate date]]; + hour = [components hour]; + + + } + self.date = dayPicker.date; - + [[NSUserDefaults standardUserDefaults] setObject:date forKey:@"GCCalendarDate"]; [self reloadDayAnimated:NO context:NULL]; + + [self.dayView setContentOffset:currentContentOffset]; + + [self.dayView scrollToHour:hour - 0.5 animated:YES]; + } - (void)add { if (delegate != nil) { @@ -106,7 +94,6 @@ - (void)setHasAddButton:(BOOL)b { target:self action:@selector(add)]; self.navigationItem.rightBarButtonItem = button; - [button release]; } else { self.navigationItem.rightBarButtonItem = nil; @@ -114,10 +101,13 @@ - (void)setHasAddButton:(BOOL)b { } #pragma mark view notifications -- (void)loadView { - [super loadView]; - - self.date = [[NSUserDefaults standardUserDefaults] objectForKey:@"GCCalendarDate"]; + +- (void)viewDidLoad { + + viewDirty = YES; + viewVisible = NO; + + self.date = [[NSUserDefaults standardUserDefaults] objectForKey:@"GCCalendarDate"]; if (date == nil) { self.date = [NSDate date]; } @@ -126,6 +116,7 @@ - (void)loadView { dayPicker = [[GCDatePickerControl alloc] init]; dayPicker.frame = CGRectMake(0, 0, self.view.frame.size.width, 0); dayPicker.autoresizingMask = UIViewAutoresizingNone; + dayPicker.delegate = self; dayPicker.date = date; [dayPicker addTarget:self action:@selector(datePickerDidChangeDate:) forControlEvents:UIControlEventValueChanged]; [self.view addSubview:dayPicker]; @@ -140,15 +131,49 @@ - (void)loadView { [self.view addSubview:dayView]; // setup today button - UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:[[NSBundle mainBundle] localizedStringForKey:@"TODAY" value:@"" table:@"GCCalendar"] + UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Now" style:UIBarButtonItemStylePlain - target:self + target:self action:@selector(today)]; self.navigationItem.leftBarButtonItem = button; - [button release]; + + if ([dataSource respondsToSelector:@selector(datePickerLeftButtonImage)]) + [dayPicker setLeftButtonImage:[dataSource datePickerLeftButtonImage]]; + + if ([dataSource respondsToSelector:@selector(datePickerLeftButtonImage)]) + [dayPicker setRightButtonImage:[dataSource datePickerRightButtonImage]]; + + if ([dataSource respondsToSelector:@selector(datePickerBackgroundImage)]) + [dayPicker setBackgroundImage:[dataSource datePickerBackgroundImage]]; + + if ([dataSource respondsToSelector:@selector(datePickerTextColor)]) + [dayPicker setTextColor:[dataSource datePickerTextColor]]; + + if ([dataSource respondsToSelector:@selector(datePickerTextShadowColor)]) + [dayPicker setTextShadowColor:[dataSource datePickerTextShadowColor]]; + + + + + +} + +- (void)loadView { + [super loadView]; + + } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(calendarTileTouch:) + name:__GCCalendarTileTouchNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(calendarShouldReload:) + name:GCCalendarShouldReloadNotification + object:nil]; if (viewDirty) { [self reloadDayAnimated:NO context:NULL]; @@ -156,17 +181,26 @@ - (void)viewWillAppear:(BOOL)animated { } viewVisible = YES; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + [self.dayView scrollToHour:[[NSUserDefaults standardUserDefaults] floatForKey:@"start_time"]]; + }); + } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; viewVisible = NO; + + [[NSNotificationCenter defaultCenter] removeObserver:self]; + } #pragma mark view animation functions - (void)reloadDayAnimated:(BOOL)animated context:(void *)context { if (animated) { - NSTimeInterval interval = [(NSNumber *)context doubleValue]; + NSTimeInterval interval = [(__bridge NSNumber *)context doubleValue]; // block user interaction dayPicker.userInteractionEnabled = NO; @@ -181,7 +215,6 @@ - (void)reloadDayAnimated:(BOOL)animated context:(void *)context { initialFrame.origin.x = 0 - initialFrame.size.width; } else { - [nextDayView release]; return; } nextDayView.frame = initialFrame; @@ -191,7 +224,7 @@ - (void)reloadDayAnimated:(BOOL)animated context:(void *)context { [self.view addSubview:nextDayView]; - [UIView beginAnimations:nil context:nextDayView]; + [UIView beginAnimations:nil context:(__bridge void *)(nextDayView)]; [UIView setAnimationDuration:kAnimationDuration]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; @@ -216,7 +249,7 @@ - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context { - GCCalendarDayView *nextDayView = (GCCalendarDayView *)context; + GCCalendarDayView *nextDayView = (__bridge GCCalendarDayView *)context; // cut variables [dayView removeFromSuperview]; @@ -225,10 +258,17 @@ - (void)animationDidStop:(NSString *)animationID self.dayView = nextDayView; // release pointers - [nextDayView release]; // reset pickers dayPicker.userInteractionEnabled = YES; } +- (void)reloadData { + [self reloadDayAnimated:NO context:NULL]; +} + +- (BOOL)datePickerControl:(GCDatePickerControl *)picker willChangeToDate:(NSDate *)date { + return YES; +} + @end diff --git a/GCCalendar/GCCalendarProtocols.h b/GCCalendar/GCCalendarProtocols.h index 1d60618..119dff1 100644 --- a/GCCalendar/GCCalendarProtocols.h +++ b/GCCalendar/GCCalendarProtocols.h @@ -12,11 +12,26 @@ @protocol GCCalendarDataSource @required - (NSArray *)calendarEventsForDate:(NSDate *)date; + +@optional + +@property (retain) UIColor* outsideHoursColor; +@property (retain) UIColor* officeHoursColor; +@property (retain) UIColor* hourMarkerColor; +@property (retain) UIColor* timeColor; +@property (retain) UIColor* AMPMColor; + +@property (strong) UIImage* datePickerLeftButtonImage; +@property (strong) UIImage* datePickerRightButtonImage; +@property (strong) UIImage* datePickerBackgroundImage; +@property (strong) UIColor* datePickerTextColor; +@property (strong) UIColor* datePickerTextShadowColor; + @end @class GCCalendarEvent; -@class GCCalendarView; +@class GCCalendarViewController; @protocol GCCalendarDelegate -- (void)calendarTileTouchedInView:(GCCalendarView *)view withEvent:(GCCalendarEvent *)event; -- (void)calendarViewAddButtonPressed:(GCCalendarView *)view; +- (void)calendarTileTouchedInView:(GCCalendarViewController *)view withEvent:(GCCalendarEvent *)event; +- (void)calendarViewAddButtonPressed:(GCCalendarViewController *)view; @end \ No newline at end of file diff --git a/GCCalendar/GCCalendarTile.h b/GCCalendar/GCCalendarTileView.h similarity index 72% rename from GCCalendar/GCCalendarTile.h rename to GCCalendar/GCCalendarTileView.h index f498f8a..57b92bc 100644 --- a/GCCalendar/GCCalendarTile.h +++ b/GCCalendar/GCCalendarTileView.h @@ -11,25 +11,29 @@ #import @class GCCalendarEvent; +@class EAGlossyBox; /* A GCCalendarTile draws itself using data in the event passed to it. Each tile posts a notification whenever a touch ends inside its frame. */ -@interface GCCalendarTile : UIView { +@interface GCCalendarTileView : UIView { // event title label UILabel *titleLabel; // event description label UILabel *descriptionLabel; // view containing stretchable image - UIImageView *backgroundView; + EAGlossyBox *backgroundView; + + // view containing the event's badge image + UIImageView* badgeImageView; // event from which to draw tile GCCalendarEvent *event; } -@property (nonatomic, retain) GCCalendarEvent *event; +@property (nonatomic, strong) GCCalendarEvent *event; @end diff --git a/GCCalendar/GCCalendarTile.m b/GCCalendar/GCCalendarTileView.m similarity index 53% rename from GCCalendar/GCCalendarTile.m rename to GCCalendar/GCCalendarTileView.m index 8371444..399260e 100644 --- a/GCCalendar/GCCalendarTile.m +++ b/GCCalendar/GCCalendarTileView.m @@ -8,11 +8,15 @@ // Copyright GUI Cocoa Software 2010. All rights reserved. // -#import "GCCalendarTile.h" +#import "GCCalendarTileView.h" #import "GCCalendarEvent.h" #import "GCCalendar.h" +#import "EAGlossyBox.h" +#import -@implementation GCCalendarTile +#define TILE_SIDE_PADDING 6 + +@implementation GCCalendarTileView @synthesize event; @@ -26,7 +30,8 @@ - (id)init { titleLabel.backgroundColor = [UIColor clearColor]; titleLabel.textColor = [UIColor whiteColor]; titleLabel.shadowColor = [UIColor colorWithWhite:0.0f alpha:0.5f]; - titleLabel.font = [UIFont boldSystemFontOfSize:14.0f]; + titleLabel.font = [UIFont systemFontOfSize:13.0f]; + titleLabel.numberOfLines = 0; descriptionLabel = [[UILabel alloc] init]; descriptionLabel.backgroundColor = [UIColor clearColor]; @@ -35,57 +40,84 @@ - (id)init { descriptionLabel.font = [UIFont systemFontOfSize:12.0f]; descriptionLabel.lineBreakMode = UILineBreakModeWordWrap; descriptionLabel.numberOfLines = 0; + + badgeImageView = [[UIImageView alloc] init]; - backgroundView = [[UIImageView alloc] init]; + backgroundView = [[EAGlossyBox alloc] initWithFrame:CGRectZero]; backgroundView.alpha = 0.90f; [self addSubview:backgroundView]; + [self addSubview:badgeImageView]; [self addSubview:titleLabel]; [self addSubview:descriptionLabel]; + + self.layer.shouldRasterize = YES; + self.layer.rasterizationScale = [UIScreen mainScreen].scale; } return self; } - (void)dealloc { self.event = nil; - - [super dealloc]; } + - (void)setEvent:(GCCalendarEvent *)e { - [event release]; event = e; - [event retain]; + // set bg image - NSString *colorString = [event.color capitalizedString]; - NSString *colorImageName = [NSString stringWithFormat:@"CalendarBubble%@.png", colorString]; - UIImage *bgImage = [UIImage imageNamed:colorImageName]; - backgroundView.image = [bgImage stretchableImageWithLeftCapWidth:6 topCapHeight:13]; + backgroundView.color = event.color; // set title - titleLabel.text = event.eventName; + titleLabel.text = event.eventName; + descriptionLabel.text = event.eventDescription; + + if (event.eventDescription == nil) + descriptionLabel.hidden = YES; + else + descriptionLabel.hidden = NO; + + if (event.image) { + badgeImageView.image = event.image; + } [self setNeedsDisplay]; } - (void)layoutSubviews { - CGRect myBounds = self.bounds; - - backgroundView.frame = myBounds; - - CGSize stringSize = [titleLabel.text sizeWithFont:titleLabel.font]; - titleLabel.frame = CGRectMake(6, - 3, - myBounds.size.width - 12, - stringSize.height); + CGRect myBounds = CGRectInset(self.bounds, 0, 3); + + + backgroundView.frame = CGRectInset(myBounds, 1, 1); + + [badgeImageView sizeToFit]; + badgeImageView.frame = CGRectMake(myBounds.size.width - badgeImageView.bounds.size.width - TILE_SIDE_PADDING, myBounds.origin.y+3, badgeImageView.bounds.size.width, badgeImageView.bounds.size.height); + + NSInteger titleWidth = myBounds.size.width - TILE_SIDE_PADDING * 2; + + CGSize stringSize = CGSizeZero; + + CGRect titleRect = CGRectMake(TILE_SIDE_PADDING, myBounds.origin.y+3, titleWidth, myBounds.size.height-10); + if (event.image) + titleRect.size.width -= (badgeImageView.bounds.size.width + 3); + + if (event.eventDescription) { + stringSize = [titleLabel.text sizeWithFont:titleLabel.font]; + } else { + stringSize = [titleLabel.text sizeWithFont:titleLabel.font constrainedToSize:titleRect.size]; + } + + titleRect.size = stringSize; + + titleLabel.frame = titleRect; if (event.allDayEvent) { descriptionLabel.frame = CGRectZero; } else { - descriptionLabel.frame = CGRectMake(6, + descriptionLabel.frame = CGRectMake(TILE_SIDE_PADDING, titleLabel.frame.size.height + 2, - myBounds.size.width - 12, + myBounds.size.width - TILE_SIDE_PADDING * 2, myBounds.size.height - 14 - titleLabel.frame.size.height); } } diff --git a/GCCalendar/GCCalendarView.h b/GCCalendar/GCCalendarView.h deleted file mode 100644 index d2840d3..0000000 --- a/GCCalendar/GCCalendarView.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// GCCalendarView.h -// iBeautify -// -// Created by Caleb Davenport on 2/27/10. -// Copyright 2010 GUI Cocoa Software. All rights reserved. -// - -#import - -#import "GCCalendarProtocols.h" - -@interface GCCalendarView : UIViewController { - // data source - id dataSource; - - // delegate - id delegate; -} - -@property (nonatomic, assign) id dataSource; -@property (nonatomic, assign) id delegate; - -@end diff --git a/GCCalendar/GCCalendarViewController.h b/GCCalendar/GCCalendarViewController.h new file mode 100644 index 0000000..6b423f9 --- /dev/null +++ b/GCCalendar/GCCalendarViewController.h @@ -0,0 +1,24 @@ +// +// GCCalendarView.h +// iBeautify +// +// Created by Caleb Davenport on 2/27/10. +// Copyright 2010 GUI Cocoa Software. All rights reserved. +// + +#import + +#import "GCCalendarProtocols.h" + +@interface GCCalendarViewController : UIViewController { + // data source + id __unsafe_unretained dataSource; + + // delegate + id __unsafe_unretained delegate; +} + +@property (nonatomic, unsafe_unretained) id dataSource; +@property (nonatomic, unsafe_unretained) id delegate; + +@end diff --git a/GCCalendar/GCCalendarView.m b/GCCalendar/GCCalendarViewController.m similarity index 70% rename from GCCalendar/GCCalendarView.m rename to GCCalendar/GCCalendarViewController.m index 53886de..57bb66f 100644 --- a/GCCalendar/GCCalendarView.m +++ b/GCCalendar/GCCalendarViewController.m @@ -6,9 +6,9 @@ // Copyright 2010 GUI Cocoa Software. All rights reserved. // -#import "GCCalendarView.h" +#import "GCCalendarViewController.h" -@implementation GCCalendarView +@implementation GCCalendarViewController @synthesize delegate, dataSource; diff --git a/GCCalendar/GCDatePickerControl.h b/GCCalendar/GCDatePickerControl.h index 56e5957..f09ae58 100644 --- a/GCCalendar/GCDatePickerControl.h +++ b/GCCalendar/GCDatePickerControl.h @@ -10,6 +10,14 @@ #import +@class GCDatePickerControl; + +@protocol GCDatePickerControlDelegate + +- (BOOL) datePickerControl:(GCDatePickerControl*)picker willChangeToDate:(NSDate*)date; + +@end + /* This UIControl subclass displays the mechanism for changing the currently displayed date. When the date is changed by the user, an action is posted @@ -30,6 +38,14 @@ BOOL today; } -@property (nonatomic, retain) NSDate *date; +@property (nonatomic, strong) NSDate *date; + +- (void) setLeftButtonImage:(UIImage*)image; +- (void) setRightButtonImage:(UIImage*)image; +- (void) setBackgroundImage:(UIImage*)image; +- (void) setTextColor:(UIColor*)color; +- (void) setTextShadowColor:(UIColor*)color; + +@property (weak) id delegate; @end diff --git a/GCCalendar/GCDatePickerControl.m b/GCCalendar/GCDatePickerControl.m index 49ce02f..3e92b89 100644 --- a/GCCalendar/GCDatePickerControl.m +++ b/GCCalendar/GCDatePickerControl.m @@ -11,6 +11,8 @@ #import "GCDatePickerControl.h" #import "GCCalendar.h" +#define kSecondsInDay (60 * 60 * 24) + @interface GCDatePickerControl () @property (nonatomic) BOOL today; @end @@ -20,6 +22,27 @@ @implementation GCDatePickerControl @synthesize date, today; #pragma mark create and destroy view + +- (void)setLeftButtonImage:(UIImage *)leftButtonImage { + [backButton setImage:leftButtonImage forState:UIControlStateNormal]; +} + +- (void)setRightButtonImage:(UIImage *)rightButtonImage { + [forwardButton setImage:rightButtonImage forState:UIControlStateNormal]; +} + +- (void)setTextColor:(UIColor *)color { + titleLabel.textColor = color; +} + +- (void)setTextShadowColor:(UIColor *)color{ + titleLabel.shadowColor = color; +} + +- (void)setBackgroundImage:(UIImage *)image { + self.backgroundColor = [UIColor colorWithPatternImage:image]; +} + - (id)init { if(self = [super init]) { self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"GCDatePickerControlBackground.png"]]; @@ -27,14 +50,14 @@ - (id)init { // left button backButton = [[UIButton alloc] init]; [backButton setImage:[UIImage imageNamed:@"GCDatePickerControlLeft.png"] forState:UIControlStateNormal]; - backButton.showsTouchWhenHighlighted = NO; + backButton.showsTouchWhenHighlighted = YES; backButton.adjustsImageWhenHighlighted = NO; [backButton addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; // right button forwardButton = [[UIButton alloc] init]; [forwardButton setImage:[UIImage imageNamed:@"GCDatePickerControlRight.png"] forState:UIControlStateNormal]; - forwardButton.showsTouchWhenHighlighted = NO; + forwardButton.showsTouchWhenHighlighted = YES; forwardButton.adjustsImageWhenHighlighted = NO; [forwardButton addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; @@ -57,18 +80,13 @@ - (id)init { return self; } - (void)dealloc { - [backButton release]; backButton = nil; - [forwardButton release]; forwardButton = nil; - [titleLabel release]; titleLabel = nil; - self.date = nil; - [super dealloc]; } #pragma mark view notifications @@ -93,9 +111,7 @@ - (void)layoutSubviews { #pragma mark setters - (void)setDate:(NSDate *)newDate { - [date release]; date = newDate; - [date retain]; self.today = [GCCalendar dateIsToday:date]; @@ -116,6 +132,23 @@ - (void)setDate:(NSDate *)newDate { [monthStrings objectAtIndex:month - 1], day, year]; titleLabel.text = toDisplay; + + NSDate *dayBefore = [[NSDate alloc] initWithTimeInterval:-kSecondsInDay sinceDate:date]; + NSDate *dayAfter = [[NSDate alloc] initWithTimeInterval:kSecondsInDay sinceDate:date]; + + if (self.delegate && [self.delegate datePickerControl:self willChangeToDate:dayBefore] == NO) { + [self setButton:backButton enabled:NO]; + } else { + [self setButton:backButton enabled:YES]; + } + + if (self.delegate && [self.delegate datePickerControl:self willChangeToDate:dayAfter] == NO) { + [self setButton:forwardButton enabled:NO]; + } else { + [self setButton:forwardButton enabled:YES]; + } + + } - (void)setFrame:(CGRect)newFrame { newFrame.size.height = 45; @@ -126,7 +159,7 @@ - (void)setFrame:(CGRect)newFrame { - (void)setToday:(BOOL)newToday { today = newToday; - if(today) { + /*if(today) { titleLabel.textColor = [UIColor colorWithRed:0 green:(88.0/255.0) blue:(238.0/255.0) @@ -136,20 +169,31 @@ - (void)setToday:(BOOL)newToday { green:(65.0/255.0) blue:(84.0/255.0) alpha:1.0]; - } + }*/ +} + +- (void) setButton:(UIButton*)button enabled:(BOOL)enabled { + if (enabled) { + button.enabled = YES; + button.alpha = 1.0; + } else { + button.enabled = NO; + button.alpha = 0.5; + } } #pragma mark button actions - (void)buttonPressed:(UIButton *)sender { -#define kSecondsInDay (60 * 60 * 24) if(sender == backButton) { NSDate *newDate = [[NSDate alloc] initWithTimeInterval:-kSecondsInDay sinceDate:date]; - self.date = newDate; - [newDate release]; + if (self.delegate && [self.delegate datePickerControl:self willChangeToDate:newDate] == NO) + return; + self.date = newDate; } else if(sender == forwardButton) { NSDate *newDate = [[NSDate alloc] initWithTimeInterval:kSecondsInDay sinceDate:date]; - self.date = newDate; - [newDate release]; + if (self.delegate && [self.delegate datePickerControl:self willChangeToDate:newDate] == NO) + return; + self.date = newDate; } [self sendActionsForControlEvents:UIControlEventValueChanged]; diff --git a/main.m b/main.m index 0415e1f..7491e2e 100644 --- a/main.m +++ b/main.m @@ -10,8 +10,8 @@ int main(int argc, char *argv[]) { - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - int retVal = UIApplicationMain(argc, argv, nil, @"CalendarAppDelegate"); - [pool release]; - return retVal; + @autoreleasepool { + int retVal = UIApplicationMain(argc, argv, nil, @"CalendarAppDelegate"); + return retVal; + } }