OverridingDefaultActions Document

Overriding Default Actions

Overview

The CalendarStore framework provides UI classes and low-level model classes. The UI classes provide a rich and complete store experience to the user, while the model classes allows apps to build their own UI.

However, often apps only want to change some small part of the UI. It wouldn’t make much sense to re-implement the whole UI from scratch to accomplish that. For that, all UI classes implement the pageItemHandlerDelegate, to allow apps to override specific behavior only.

Default PageItem actions

The UI classes (CalStoreCalendarStoreViewController, CalStoreStyledPageViewController, etc) all perform specific actions when the user interact when a CalStorePageItem object via their UI.

For example, CalStoreCalendarViewController will start installing a calendar via EventKit when the user taps on an already purchases item. CalStoreStyledPageViewController does the same, only presenting different UI.

Overriding PageItem actions

Every UI class that interacts with CalStorePageItem’s, does have a pageItemHandlerDelegate. Delegates should conform to the formal protocol CalStorePageItemHandlerDelegate. This delegate object will receive various callbacks when a user interacts with a page-item and allows the delegate to override and stop the default behavior of the action, dynamically by returning NO for the should* methods. Returning YES or not implementing it, will ensure the default action will be performed.

Example: Overriding installation behavior

If you have an app that doesn’t want to use EventKit for installing calendars, you can still use the provided UI classes and override the installation process. The following sample code will show how to accomplish this:

@class SomeViewController () CalStorePageItemHandlerDelegate
@end

@implementation SomeViewController

-(void)launchCalendarStore
{
    CalStoreCalendarViewController* vc = [CalStoreCalendarStoreViewController calendarStoreViewController];
    vc.pageItemHandlerDelegate = self;
    [self presentViewController:vc animated:YES completion:nil];
}

-(BOOL)shouldInstallCalendarForItem:(CalStorePageItemCalendar*)pageItem
                       withCallback:(CalStorePageItemHandlerDelegateCallback)showViewControllerCallback
{
    // NOTE: in general, it's a good idea to provide some 'progress' feedback UI
    // to the user, either with the help of showViewControllerCallback() our other means.

    // let the framework create a unique url for our subscription
    [pageItem createUrlWithCompletionHandler:^(NSURL* url, NSError* error){

        // if we got an url, let our internal engine subscribe to the calendar
        if[(url != nil)
           [[OurInternalICSEngine sharedEngine] addSubscribedCalendarWithUrl:url];
        else
            NSLog(@"Error when requesting url for pageItem (%@): %@", pageItem, url); // we should also show the error to the user
    }];


    // we override this behavior, so return NO to indicate the default behavior should not be performed
    return NO;
}

@end

Presenting Custom ViewControllers

Each method of the CalStorePageItemHandlerDelegate protocol has a showViewControllerCallback parameter. This parameter is a block that takes one UIViewController* object. If you want to show a custom view controller for some action, you should call this block with your view controller as parameter: presentViewController(vc).

Be aware that, one calling showViewControllerCallback, the delegate method shouldShowViewController:forItem:withCallback: won’t be invoked; it will only be invoked by default actions, not overriden behavior.

The following sample code will show how to let the UI classes show custom view controllers.

@class SomeViewController () CalStorePageItemHandlerDelegate
@end

@implementation SomeViewController

-(void)launchCalendarStore
{
    CalStoreCalendarViewController* vc = [CalStoreCalendarStoreViewController calendarStoreViewController];
    vc.pageItemHandlerDelegate = self;
    [self presentViewController:vc animated:YES completion:nil];
}

-(BOOL)shouldNavigateToWeatherForItem:(CalStorePageItemParameterizedCalendar*)pageItem
                         withCallback:(CalStorePageItemHandlerDelegateCallback)showViewControllerCallback;
{
    // create our custom weather view controller
    MyCustomWeatherViewController* vc = [[MyCustomWeatherViewController alloc] init];
    vc.pageItem = pageItem;

    // let the UI class present/push it
    showViewControllerCallback(vc);

    // we override this behavior, so return NO to indicate the default behavior should not be performed
    return NO;
}

@end

Showing custom Intro Walkthrough

The Intro Walkthrough can be provided with custom content from a plist.

NSBundle *bundle = [NSBundle mainBundle];
NSString* plistPath = [bundle pathForResource:@"Intro" ofType:@"plist"];
[[CalStoreController sharedController] presentModalIntroFromViewController:self.window.rootViewController 
                                                             withPlistPath:plistPath];

Each page of the intro is configured as dictionary.

<array>
    <dict>
        <key>title</key>
        <string>Page1 title</string>
        <key>description</key>
        <string>Page1 description</string>
        <key>image</key>
        <string>Walkthrough-1.png</string>
        <key>background_color</key>
        <string>#EFEFF4</string>
        <key>text_background_color</key>
        <string>#E36364</string>
    </dict>
</array>

The plist and images are loaded from the main bundle of your app. Consider localizing the plist file, matching you apps supported languages.