Created
January 3, 2012 11:43
-
-
Save curthard89/1554602 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GDataController.m | |
// Caffeinated | |
// | |
// Created by Curtis Hard on 03/11/2010. | |
// Copyright (c) 2010 GeekyGoodness. All rights reserved. | |
// | |
#import "GDataController.h" | |
@implementation GDataController | |
#define FAVICON_URL @"http://s2.googleusercontent.com/s2/favicons?domain=%@&alt=feed" | |
#define ARCHIVE_FOLDER [NSString stringWithFormat:@"%@",[self class]] | |
#define LOGGED_IN if( ! [self loggedIn] ){return;} | |
#define MAX_SYNC_PROCESS 20 | |
#define MAX_USER_SYNC_NOTICE 100 | |
@synthesize delegate, session, account, credentials, maxPreviousItems, addSubscriptionDelegate; | |
@synthesize maxSyncCount, maxFetchCount, continueToken, lazyLoad, lazyLoadCount, archivePath, lastChecked; | |
@synthesize ignoreArchivedChanges, loggedIn, emulateGoogleClient, defaultClientName, searchSubscriptionsDelegate; | |
@synthesize authenticating, syncing; | |
static GDataController * defaultController = nil; | |
void GDataControllerApply( Protocol * protocol, dispatch_block_t block ) | |
{ | |
if( [[GDataController defaultController] conformsToProtocol:protocol] ) | |
{ | |
dispatch_async( dispatch_get_main_queue(), block ); | |
} | |
} | |
+ (GDataController *)defaultController | |
{ | |
static dispatch_once_t onceToken; | |
dispatch_once(&onceToken, ^{ | |
defaultController = [[GDataController alloc] init]; | |
}); | |
return defaultController; | |
} | |
- (void)dealloc { | |
[self archivePreferences]; | |
[defaultClientName release], defaultClientName = nil; | |
[session release], session = nil; | |
[requestQueue release], requestQueue = nil; | |
[favIconQueue release], favIconQueue = nil; | |
[credentials release], credentials = nil; | |
[archivePath release], archivePath = nil; | |
[account release], account = nil; | |
[lastChecked release], lastChecked = nil; | |
[itemReadUnreadQueue release], itemReadUnreadQueue = nil; | |
[tagQueueCounts release], tagQueueCounts = nil; | |
[itemRequestCounts release], itemRequestCounts = nil; | |
[tokenQueue release], tokenQueue = nil; | |
[groupArray release], groupArray = nil; | |
[prefs release], prefs = nil; | |
[processTimer invalidate]; | |
[processTimer release], processTimer = nil; | |
[defaultClientName release], defaultClientName = nil; | |
[pageDictionary release], pageDictionary = nil; | |
[dateCheckDictionary release], dateCheckDictionary = nil; | |
[super dealloc]; | |
} | |
- (id)init | |
{ | |
if( ( self = [super init] ) != nil ) | |
{ | |
[self setMaxFetchCount:1000]; | |
[self setMaxSyncCount:99999999]; // good luck reaching that, if you do...kudos to you | |
[self setMaxPreviousItems:500]; | |
[self setLazyLoadCount:100]; | |
itemReadUnreadQueue = [[NSMutableDictionary alloc] init]; | |
tagQueueCounts = [[NSMutableDictionary alloc] init]; | |
tagQueueCount = [[NSMutableDictionary alloc] init]; | |
itemRequestCounts = [[NSMutableDictionary alloc] init]; | |
// set up the request queue | |
requestQueue = [[GDataOperationQueue alloc] initWithController:self]; | |
[requestQueue setSuspended:YES]; | |
[requestQueue addObserver:self | |
forKeyPath:@"operations" | |
options:0 | |
context:NULL]; | |
[requestQueue addObserver:self | |
forKeyPath:@"suspended" | |
options:0 | |
context:NULL]; | |
[self addObserver:self | |
forKeyPath:@"authenticating" | |
options:0 | |
context:NULL]; | |
// limit to 1 item at a time, as google reader api only supports that | |
[requestQueue setMaxConcurrentOperationCount:1]; | |
favIconQueue = [[NSOperationQueue alloc] init]; | |
[favIconQueue setMaxConcurrentOperationCount:10]; | |
// first run? | |
firstRun = YES; | |
// find last checked | |
lastChecked = [[NSUserDefaults standardUserDefaults] objectForKey:@"GDataControllerDateChecked"]; | |
NSString * clientName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; | |
clientName = [clientName stringByReplacingOccurrencesOfString:@" " | |
withString:@"%20"]; | |
[self setDefaultClientName:clientName]; | |
} | |
return self; | |
} | |
- (BOOL)pendingLocalChanges:(BOOL *)userNotice | |
{ | |
if( [itemReadUnreadQueue count] >= MAX_USER_SYNC_NOTICE ) | |
{ | |
*userNotice = YES; | |
} | |
if( [itemReadUnreadQueue count] != 0 ) | |
{ | |
return YES; | |
} | |
NSInteger count = 0; | |
for( id op in [requestQueue operations] ) | |
{ | |
if( | |
[op isKindOfClass:[GDataItemEditTag class]] || | |
[op isKindOfClass:[GDataSubscriptionAdd class]] || | |
[op isKindOfClass:[GDataSubscriptionEditLabel class]] ) | |
{ | |
count++; | |
} | |
} | |
if( ( count * MAX_SYNC_PROCESS ) >= MAX_USER_SYNC_NOTICE ) | |
{ | |
*userNotice = YES; | |
} | |
return count != 0; | |
} | |
- (BOOL)hasItemsRequestInQueue | |
{ | |
for( id operation in [requestQueue operations] ) | |
{ | |
if( [operation isKindOfClass:[GDataItems class]] ) | |
{ | |
return YES; | |
} | |
} | |
return NO; | |
} | |
- (void)archive | |
{ | |
if( ! [self archivePath] ) | |
{ | |
return; | |
} | |
NSString * path = [NSString stringWithFormat:@"%@/%@.gr",[self archivePath],[[[self credentials] username] MD5String]]; | |
[NSArchiver archiveRootObject:requestQueue | |
toFile:path]; | |
} | |
- (void)reset | |
{ | |
[self archivePendingChanges]; | |
[self archivePreferences]; | |
[prefs release], prefs = nil; | |
[dateCheckDictionary release], dateCheckDictionary = nil; | |
firstRun = YES; | |
requiresRefresh = NO; | |
[self setLoggedIn:NO]; | |
[self setIgnoreArchivedChanges:NO]; | |
[itemReadUnreadQueue removeAllObjects]; | |
[session release], session = nil; | |
[credentials release], credentials = nil; | |
[account release], account = nil; | |
[requestQueue cancelAllOperations]; | |
[favIconQueue cancelAllOperations]; | |
[groupArray removeAllObjects]; | |
[lastChecked release], lastChecked = nil; | |
[tagQueueCounts removeAllObjects]; | |
[self setLastChecked:nil]; | |
} | |
- (void)logout | |
{ | |
if( defaultController != nil ) | |
{ | |
[defaultController release], defaultController = nil; | |
} | |
defaultController = [[[self class] alloc] init]; | |
} | |
- (NSString *)folderIdentifierWithName:(NSString *)aName | |
{ | |
return [NSString stringWithFormat:@"user/%@/label/%@",[[self account] userID],aName]; | |
} | |
- (void)resumeQueues | |
{ | |
LOGGED_IN | |
suspended = NO; | |
[requestQueue setSuspended:NO]; | |
} | |
- (void)suspendQueues | |
{ | |
LOGGED_IN | |
suspended = YES; | |
[requestQueue setSuspended:YES]; | |
} | |
- (BOOL)suspended | |
{ | |
return suspended; | |
} | |
- (NSString *)clientName | |
{ | |
return [self emulateGoogleClient] ? @"scroll" : defaultClientName; | |
} | |
// listeners for the change in operations within the queue | |
- (void)observeValueForKeyPath:(NSString *)keyPath | |
ofObject:(id)object | |
change:(NSDictionary *)change | |
context:(void *)context | |
{ | |
if( [keyPath isEqualToString:@"operations"] || [keyPath isEqualToString:@"authenticating"] ) | |
{ | |
BOOL flag = ( [[requestQueue operations] count] != 0 ) || [self authenticating]; | |
[self setSyncing:flag]; | |
if( [[self delegate] respondsToSelector:@selector(gDataController:isSyncing:)] ) | |
{ | |
[[self delegate] gDataController:self | |
isSyncing:flag]; | |
} | |
} | |
} | |
- (void)checkItemsInQueueWithMask:(GDataItemsMask)mask | |
{ | |
for( id operation in [requestQueue operations] ) | |
{ | |
if( [operation isKindOfClass:[GDataItems class]] ) | |
{ | |
return; | |
} | |
} | |
if( [[self delegate] respondsToSelector:@selector(gDataControllerDidFinishRequestingItems:mask:)] ) | |
{ | |
[[self delegate] gDataControllerDidFinishRequestingItems:self | |
mask:mask]; | |
} | |
} | |
// this should be ran 1st, passing in the credentials object with | |
// username and password., if it fails, you will know about it | |
- (void)authenticateWithCredentials:(GDataCredentials *)aCredential | |
{ | |
// release if already set and different | |
[self setAuthenticating:YES]; | |
if( [self credentials] && [self credentials] != aCredential ) | |
{ | |
credentials = nil; | |
[credentials release]; | |
} | |
// set them | |
[self setCredentials:aCredential]; | |
// set up the auth | |
GDataAuth * auth = [[GDataAuth alloc] initWithCredentials:[self credentials]]; | |
[auth setDelegate:self]; | |
// request | |
[auth authenticate]; | |
} | |
// puts a request into the queue for subscriptions | |
- (void)requestSubscriptions | |
{ | |
LOGGED_IN | |
// push a subscription request in | |
[requestQueue addOperation:[[[GDataSubscriptions alloc] init] autorelease]]; | |
} | |
- (void)requestUnreadCount:(id)sender | |
{ | |
LOGGED_IN | |
[self processPendingChanges]; | |
GDataUnreadCount * operation = [[[GDataUnreadCount alloc] init] autorelease]; | |
[operation setQueuePriority:NSOperationQueuePriorityNormal]; | |
[requestQueue addOperation:operation]; | |
} | |
- (void)requestItems:(BOOL)flag | |
limitByDate:(BOOL)limit | |
{ | |
[self requestItems:(flag?GDATA_ITEMS_TYPE_READ:GDATA_ITEMS_TYPE_UNREAD) | |
limitByDate:limit | |
startDate:nil | |
endDate:nil | |
maxCount:NSNotFound | |
maxFetchCount:NSNotFound]; | |
} | |
- (void)setDate:(NSDate *)date | |
forTag:(GDataItemsTag)tag | |
temp:(BOOL)flag | |
{ | |
NSString * type = [NSString stringWithFormat:@"%d",tag]; | |
NSMutableDictionary * dict = nil; | |
if( [dateCheckDictionary objectForKey:type] != nil ) | |
{ | |
dict = [dateCheckDictionary objectForKey:type]; | |
} else { | |
dict = [[[NSMutableDictionary alloc] init] autorelease]; | |
} | |
[dict setObject:date | |
forKey:(flag?@"temp":@"legit")]; | |
[dateCheckDictionary setObject:dict | |
forKey:type]; | |
[prefs setObject:dateCheckDictionary | |
forKey:PREFS_DATE_CHECKED_KEY]; | |
[self archivePreferences]; | |
} | |
- (void)resetDates | |
{ | |
[dateCheckDictionary removeAllObjects]; | |
[prefs removeObjectForKey:PREFS_DATE_CHECKED_KEY]; | |
[self archivePreferences]; | |
} | |
- (void)pushDateForTag:(GDataItemsTag)tag | |
{ | |
NSString * key = [NSString stringWithFormat:@"%d",tag]; | |
NSMutableDictionary * dict = [dateCheckDictionary objectForKey:key]; | |
if( dict != nil ) | |
{ | |
if( [dict objectForKey:@"temp"] ) | |
{ | |
[dict setObject:[dict objectForKey:@"temp"] | |
forKey:@"legit"]; | |
[dict removeObjectForKey:@"temp"]; | |
[dateCheckDictionary setObject:dict | |
forKey:key]; | |
} | |
} | |
[self archivePreferences]; | |
} | |
- (NSDate *)dateForTag:(GDataItemsTag)tag | |
temp:(BOOL)flag | |
{ | |
return [[dateCheckDictionary objectForKey:[NSString stringWithFormat:@"%d",tag]] objectForKey:(flag?@"temp":@"legit")];; | |
} | |
- (NSInteger)timeSinceDateForTag:(GDataItemsTag)tag | |
toDate:(NSDate *)date; | |
{ | |
NSTimeInterval time = [[self dateForTag:tag | |
temp:NO] timeIntervalSince1970]; | |
NSTimeInterval newTime = [date timeIntervalSince1970]; | |
return (NSInteger)round( newTime - time ); | |
} | |
- (void)setLastChecked:(NSDate *)flag | |
{ | |
if( lastChecked != nil ) | |
{ | |
[lastChecked release], lastChecked = nil; | |
} | |
if( flag != nil ) | |
{ | |
lastChecked = [flag copy]; | |
} | |
} | |
- (NSDate *)lastChecked | |
{ | |
return [[NSUserDefaults standardUserDefaults] objectForKey:@"GDataControllerDateChecked"]; | |
} | |
- (void)orderItemsOperation:(GDataItems *)items | |
{ | |
if( [items type] == GDATA_ITEMS_TYPE_UNREAD ) | |
{ | |
// push up the queue, make every read request have depency of this | |
[[requestQueue operations] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) | |
{ | |
if( [obj isKindOfClass:[GDataItems class]] && items != obj ) | |
{ | |
GDataItems * oldItems = obj; | |
if( [oldItems type] == GDATA_ITEMS_TYPE_READ ) | |
{ | |
[oldItems addDependency:items]; | |
} | |
} | |
}]; | |
} else if( [items type] == GDATA_ITEMS_TYPE_READ ) { | |
// find the last unread items request | |
[[requestQueue operations] enumerateObjectsWithOptions:NSEnumerationReverse | |
usingBlock:^(id obj, NSUInteger idx, BOOL *stop) | |
{ | |
if( [obj isKindOfClass:[GDataItems class]] && items != obj ) | |
{ | |
GDataItems * oldItems = obj; | |
if( [oldItems type] == GDATA_ITEMS_TYPE_UNREAD ) | |
{ | |
[items addDependency:oldItems]; | |
} | |
} | |
}]; | |
} | |
} | |
- (void)orderProcessChangesOperation:(GDataItemEditTag *)items | |
{ | |
// first we want to order it against any other edit operations in the queue | |
[[requestQueue operations] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) | |
{ | |
if( ! [obj isKindOfClass:[GDataItemEditTag class]] && ! [obj isExecuting] ) | |
{ | |
[obj addDependency:items]; | |
} | |
}]; | |
} | |
// puts a request in the queue for items | |
- (void)requestItems:(GDataItemsTag)tag | |
limitByDate:(BOOL)limit | |
startDate:(NSDate *)startDate | |
endDate:(NSDate *)endDate | |
maxCount:(NSInteger)max | |
maxFetchCount:(NSInteger)maxFetch | |
{ | |
LOGGED_IN | |
[self processPendingChanges]; | |
// push items request in | |
GDataItems * items = [[[GDataItems alloc] init] autorelease]; | |
[items setFetchUID:[[NSProcessInfo processInfo] globallyUniqueString]]; | |
[items setType:tag]; | |
[items setQueuePriority:( tag == GDATA_ITEMS_TYPE_READ ? NSOperationQueuePriorityVeryLow : NSOperationQueuePriorityVeryHigh )]; | |
[items setMaxCount:(maxFetch == NSNotFound?[self maxFetchCount]:maxFetch)]; | |
[items setMaxItemCount:max]; | |
[items setLimitByDate:limit]; | |
[items setFirstRun:firstRun]; | |
[items setFromDate:startDate]; | |
[items setToDate:endDate]; | |
NSDate * date = [NSDate date]; | |
// is the tag unread? | |
if( tag == GDATA_ITEMS_TYPE_UNREAD ) | |
{ | |
// minus an hour, as googles craw might not of happened | |
NSTimeInterval time = [date timeIntervalSince1970]; | |
time -= ( 60 * 60 ); // 1 hour | |
date = [NSDate dateWithTimeIntervalSince1970:time]; | |
} | |
[self orderItemsOperation:items]; | |
[self setDate:date | |
forTag:tag | |
temp:YES]; | |
if( [[self delegate] respondsToSelector:@selector(gDataController:didRequestItems:)] ) | |
{ | |
[[self delegate] gDataController:self | |
didRequestItems:items]; | |
} | |
[requestQueue addOperation:items]; | |
// starred items will be fetched ever 20 request calls, | |
// or on the 0 call - so when the first request is called | |
if( starredInc == 20 || starredInc == 0 ) | |
{ | |
items = [[[GDataItems alloc] init] autorelease]; | |
[items setFetchUID:[[NSProcessInfo processInfo] globallyUniqueString]]; | |
[items setType:GDATA_ITEMS_TYPE_STARRED]; | |
[items setMaxCount:NSNotFound]; | |
[items setMaxItemCount:NSNotFound]; | |
[items setLimitByDate:NO]; | |
[items setQueuePriority:NSOperationQueuePriorityHigh]; | |
[requestQueue addOperation:items]; | |
[self setDate:[NSDate date] | |
forTag:GDATA_ITEMS_TYPE_STARRED | |
temp:YES]; | |
if( starredInc != 0 ) | |
{ | |
starredInc = -1; | |
} | |
if( [[self delegate] respondsToSelector:@selector(gDataController:didRequestItems:)] ) | |
{ | |
[[self delegate] gDataController:self | |
didRequestItems:items]; | |
} | |
} | |
starredInc++; | |
} | |
- (void)requestItemsForSubscription:(GDataSubscription *)sub | |
maxCount:(NSInteger)maxItem | |
maxFetchCount:(NSInteger)maxFetch | |
unread:(BOOL)flag | |
fromDate:(NSDate *)fromDate | |
allowContinuation:(BOOL)cont | |
{ | |
LOGGED_IN | |
[self processPendingChanges]; | |
GDataItems * operation = [[[GDataItems alloc] init] autorelease]; | |
[operation setSubscription:sub]; | |
[operation setType:GDATA_ITEMS_TYPE_READ]; | |
[operation setLimitByDate:YES]; | |
[operation setLastChecked:fromDate]; | |
[operation setFetchUID:[[NSProcessInfo processInfo] globallyUniqueString]]; | |
[operation setFromDate:fromDate]; | |
[operation setMaxCount:(maxFetch == NSNotFound?[self maxFetchCount]:maxFetch)]; | |
[operation setMaxItemCount:maxItem]; | |
[operation setQueuePriority:NSOperationQueuePriorityNormal]; | |
[requestQueue addOperation:operation]; | |
} | |
- (NSString *)prefsFileLocation | |
{ | |
NSString * path = NSUserLibraryPathWithDirectory([NSString stringWithFormat:@"%@/%@",ARCHIVE_FOLDER,[[self credentials] username]]); | |
NSString * file = [NSString stringWithFormat:@"%@/prefs.plist",path]; | |
return file; | |
} | |
- (void)unarchivePreferences | |
{ | |
LOGGED_IN | |
NSString * file = [self prefsFileLocation]; | |
if( [[NSFileManager defaultManager] fileExistsAtPath:file] ) | |
{ | |
prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:file]; | |
} else { | |
prefs = [[NSMutableDictionary alloc] init]; | |
} | |
} | |
- (void)archivePreferences | |
{ | |
if( prefs == nil ) | |
{ | |
return; | |
} | |
[prefs writeToFile:[self prefsFileLocation] | |
atomically:NO]; | |
} | |
- (void)unarchivePendingChanges | |
{ | |
LOGGED_IN | |
NSString * path = NSUserLibraryPathWithDirectory([NSString stringWithFormat:@"%@/%@",ARCHIVE_FOLDER,[[self credentials] username]]); | |
NSString * file = [NSString stringWithFormat:@"%@/changes.plist",path]; | |
if( ! [[NSFileManager defaultManager] fileExistsAtPath:file] ) | |
{ | |
return; | |
} | |
NSMutableDictionary * archiveDict = [[[NSMutableDictionary alloc] initWithContentsOfFile:file] autorelease]; | |
GGLog(@"Unarchiving %lu changes",[[archiveDict allKeys] count]); | |
// remove the file | |
NSError * error = nil; | |
[[NSFileManager defaultManager] removeItemAtPath:file | |
error:&error]; | |
NSMutableDictionary * tempDict = [[[NSMutableDictionary alloc] init] autorelease]; | |
// loop through each key | |
NSString * hashPath = NSUserLibraryPathWithDirectory([NSString stringWithFormat:@"%@/%@/hashes",ARCHIVE_FOLDER,[[self credentials] username]]); | |
for( NSString * key in [archiveDict allKeys] ) | |
{ | |
// unarchive the item | |
NSDictionary * dict = [archiveDict objectForKey:key]; | |
NSString * hash = [dict objectForKey:@"item"]; | |
// find the item | |
NSString * itemLoc = [NSString stringWithFormat:@"%@/%@.item",hashPath,hash]; | |
GDataItem * item = (GDataItem *)[NSKeyedUnarchiver unarchiveObjectWithFile:itemLoc]; | |
[tempDict setObject:item | |
forKey:key]; | |
// remove the file | |
[[NSFileManager defaultManager] removeItemAtPath:itemLoc | |
error:&error]; | |
} | |
// add them back in | |
for( NSString * key in [tempDict allKeys] ) | |
{ | |
[[archiveDict objectForKey:key] setObject:[tempDict objectForKey:key] | |
forKey:@"item"]; | |
} | |
// now add them to the pending list | |
for( NSString * key in [archiveDict allKeys] ) | |
{ | |
[itemReadUnreadQueue setObject:[archiveDict objectForKey:key] | |
forKey:key]; | |
} | |
} | |
- (void)archivePendingChanges | |
{ | |
NSInteger count = [[itemReadUnreadQueue allKeys] count]; | |
if( count == 0 ) | |
{ | |
return; | |
} | |
GGLog(@"Archiving %lu changes",count); | |
// archive it against the account | |
NSString * path = NSUserLibraryPathWithDirectory([NSString stringWithFormat:@"%@/%@",ARCHIVE_FOLDER,[[self credentials] username]]); | |
NSMutableDictionary * tempDict = [[[NSMutableDictionary alloc] init] autorelease]; | |
for( NSString * key in itemReadUnreadQueue ) | |
{ | |
NSMutableDictionary * dict = [[[itemReadUnreadQueue objectForKey:key] mutableCopy] autorelease]; | |
GDataItem * item = [dict objectForKey:@"item"]; | |
NSUInteger hash = [item hash]; | |
// replace the item with a hash | |
[dict setObject:[NSString stringWithFormat:@"%lu",hash] | |
forKey:@"item"]; | |
// save the item into hashes | |
NSString * hashPath = NSUserLibraryPathWithDirectory([NSString stringWithFormat:@"%@/%@/hashes",ARCHIVE_FOLDER,[[self credentials] username]]); | |
[NSKeyedArchiver archiveRootObject:item | |
toFile:[NSString stringWithFormat:@"%@/%lu.item",hashPath,hash]]; | |
[tempDict setObject:dict | |
forKey:key]; | |
} | |
for( NSString * key in [tempDict allKeys] ) | |
{ | |
[itemReadUnreadQueue setObject:[tempDict objectForKey:key] | |
forKey:key]; | |
} | |
path = [NSString stringWithFormat:@"%@/changes.plist",path]; | |
[itemReadUnreadQueue writeToFile:path | |
atomically:YES]; | |
} | |
- (void)processPendingChanges | |
{ | |
LOGGED_IN | |
if( processTimer != nil ) | |
{ | |
if( [processTimer isValid] ) | |
{ | |
[processTimer invalidate]; | |
} | |
[processTimer release], processTimer = nil; | |
} | |
if( [[itemReadUnreadQueue allKeys] count] == 0 ) | |
{ | |
return; | |
} | |
syncStartTime = [[NSDate date] timeIntervalSince1970]; | |
NSString * queueIdentifier = [[NSProcessInfo processInfo] globallyUniqueString]; | |
[tagQueueCounts setObject:[NSNumber numberWithInteger:0] | |
forKey:queueIdentifier]; | |
[tagQueueCount setObject:[NSNumber numberWithInteger:0] | |
forKey:queueIdentifier]; | |
NSMutableDictionary * items = [[[NSMutableDictionary alloc] init] autorelease]; | |
// sort them | |
for( NSDictionary * dict in [itemReadUnreadQueue allValues] ) | |
{ | |
GDataItem * item = [dict objectForKey:@"item"]; | |
NSMutableArray * array = nil; | |
if( ( array = [items objectForKey:[item identifier]] ) == nil ) | |
{ | |
array = [[[NSMutableArray alloc] init] autorelease]; | |
[items setObject:array | |
forKey:[item identifier]]; | |
} | |
[array addObject:dict]; | |
} | |
NSMutableArray * newItems = [[[NSMutableArray alloc] init] autorelease]; | |
// sort each group | |
NSSortDescriptor * sort = [[[NSSortDescriptor alloc] initWithKey:@"microtime" | |
ascending:YES] autorelease]; | |
for( NSMutableArray * arr in [items allValues] ) | |
{ | |
NSArray * newArray = [arr sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]]; | |
[newItems addObject:[newArray lastObject]]; | |
} | |
GGLog(@"Found %lu changes, processing...",[newItems count]); | |
// do the deed | |
NSMutableDictionary * tags = [[[NSMutableDictionary alloc] init] autorelease]; | |
for( NSDictionary * dict in newItems ) | |
{ | |
BOOL add = [[dict objectForKey:@"add"] boolValue]; | |
NSString * tag = [[dict objectForKey:@"tag"] stringValue]; | |
GDataItem * item = [dict objectForKey:@"item"]; | |
if( ! [tags objectForKey:tag] ) | |
{ | |
[tags setObject:[[[NSMutableDictionary alloc] init] autorelease] | |
forKey:tag]; | |
} | |
if( ! [[tags objectForKey:tag] objectForKey:@"add"] ) | |
{ | |
[[tags objectForKey:tag] setObject:[[[NSMutableArray alloc] init] autorelease] | |
forKey:@"add"]; | |
} | |
if( ! [[tags objectForKey:tag] objectForKey:@"remove"] ) | |
{ | |
[[tags objectForKey:tag] setObject:[[[NSMutableArray alloc] init] autorelease] | |
forKey:@"remove"]; | |
} | |
[[[tags objectForKey:tag] objectForKey:( add ? @"add" : @"remove" )] addObject:item]; | |
} | |
[itemReadUnreadQueue removeAllObjects]; | |
for( NSString * key in [tags allKeys] ) | |
{ | |
[self batchEditTagWithItems:[[tags objectForKey:key] objectForKey:@"add"] | |
tag:[key intValue] | |
add:YES | |
queueIdentifier:queueIdentifier]; | |
[self batchEditTagWithItems:[[tags objectForKey:key] objectForKey:@"remove"] | |
tag:[key intValue] | |
add:NO | |
queueIdentifier:queueIdentifier]; | |
} | |
} | |
- (void)batchEditTagWithItems:(NSArray *)array | |
tag:(GDataItemsTag)tag | |
add:(BOOL)flag | |
queueIdentifier:(NSString *)queueIdentifier | |
{ | |
NSInteger count = [array count]; | |
if( count == 0 ) | |
{ | |
return; | |
} | |
NSInteger max = MAX_SYNC_PROCESS; | |
NSInteger i = 0; | |
NSInteger tempI = 0; | |
NSMutableArray * arg = [[[NSMutableArray alloc] init] autorelease]; | |
for( GDataItem * item in array ) | |
{ | |
[arg addObject:item]; | |
if( tempI == ( max - 1 ) || i == ( count - 1 ) ) | |
{ | |
GDataItemEditTag * operation = [[[GDataItemEditTag alloc] init] autorelease]; | |
[operation setItems:arg]; | |
[operation setAdd:flag]; | |
[operation setTag:tag]; | |
[operation setQueueIdentifier:queueIdentifier]; | |
[operation setQueuePriority:NSOperationQueuePriorityVeryHigh]; | |
[requestQueue addOperation:operation]; | |
[self orderProcessChangesOperation:operation]; | |
GGLog(@"Batching items sent with count %lu",[arg count]); | |
arg = [[[NSMutableArray alloc] init] autorelease]; | |
tempI = -1; | |
NSInteger daCount = [[tagQueueCounts objectForKey:queueIdentifier] integerValue]; | |
daCount++; | |
[tagQueueCounts setObject:[NSNumber numberWithInteger:daCount] | |
forKey:queueIdentifier]; | |
[tagQueueCount setObject:[NSNumber numberWithInteger:daCount] | |
forKey:queueIdentifier]; | |
} | |
i++; | |
tempI++; | |
} | |
} | |
- (void)queueItem:(GDataItem *)item | |
tag:(GDataItemsTag)tag | |
add:(BOOL)flag | |
{ | |
LOGGED_IN | |
if( processTimer != nil ) | |
{ | |
if( [processTimer isValid] ) | |
{ | |
[processTimer invalidate]; | |
} | |
[processTimer release], processTimer = nil; | |
} | |
NSNumber * micro = [NSNumber numberWithDouble:[NSDate microtime]]; | |
[itemReadUnreadQueue setObject:[NSDictionary dictionaryWithObjectsAndKeys:item,@"item",[NSNumber numberWithBool:flag],@"add",[NSNumber numberWithInt:tag],@"tag",micro,@"microtime", nil] | |
forKey:[item identifier]]; | |
processTimer = [[NSTimer scheduledTimerWithTimeInterval:10 | |
target:self | |
selector:@selector(processPendingChanges) | |
userInfo:nil | |
repeats:NO] retain]; | |
} | |
// marks item as unread | |
- (void)markItemAsUnread:(GDataItem *)item | |
{ | |
[self queueItem:item | |
tag:GDATA_ITEM_TAG_READ | |
add:NO]; | |
} | |
// marks an item as read, add to a queue then gets synced next time the | |
// items are requested | |
- (void)markItemAsRead:(GDataItem *)item | |
{ | |
[self queueItem:item | |
tag:GDATA_ITEM_TAG_READ | |
add:YES]; | |
} | |
// stars an item | |
- (void)starItem:(GDataItem *)item | |
{ | |
[self queueItem:item | |
tag:GDATA_ITEM_TAG_STARRED | |
add:YES]; | |
} | |
// removes the star flag against an item | |
- (void)unstarItem:(GDataItem *)item | |
{ | |
[self queueItem:item | |
tag:GDATA_ITEM_TAG_STARRED | |
add:NO]; | |
} | |
// edit tag on an item | |
- (void)addTag:(GDataItemsTag)tag | |
toItem:(GDataItem *)item | |
{ | |
LOGGED_IN | |
GDataItemEditTag * operation = [[[GDataItemEditTag alloc] init] autorelease]; | |
[operation setItem:item]; | |
[operation setAdd:YES]; | |
[operation setRemove:NO]; | |
[operation setTag:tag]; | |
[operation setQueuePriority:NSOperationQueuePriorityVeryHigh]; | |
[requestQueue addOperation:operation]; | |
} | |
- (void)removeTag:(GDataItemsTag)tag | |
fromItem:(GDataItem *)item | |
{ | |
LOGGED_IN | |
GDataItemEditTag * operation = [[[GDataItemEditTag alloc] init] autorelease]; | |
[operation setItem:item]; | |
[operation setAdd:NO]; | |
[operation setRemove:YES]; | |
[operation setTag:tag]; | |
[operation setQueuePriority:NSOperationQueuePriorityVeryHigh]; | |
[requestQueue addOperation:operation]; | |
} | |
// add subscription to folder | |
- (void)addSubscription:(GDataSubscription *)subscription | |
toFolder:(GDataFolder *)folder | |
{ | |
LOGGED_IN | |
[self processPendingChanges]; | |
GDataSubscriptionEditLabel * operation = [[[GDataSubscriptionEditLabel alloc] init] autorelease]; | |
[operation setSubscription:subscription]; | |
[operation setFolder:folder]; | |
[operation setAdd:YES]; | |
[operation setRemove:NO]; | |
[operation setQueuePriority:NSOperationQueuePriorityVeryHigh]; | |
[requestQueue addOperation:operation]; | |
} | |
// remove subscription from folder | |
- (void)removeSubscription:(GDataSubscription *)subscription | |
fromFolder:(GDataFolder *)folder | |
{ | |
LOGGED_IN | |
[self processPendingChanges]; | |
GDataSubscriptionEditLabel * operation = [[[GDataSubscriptionEditLabel alloc] init] autorelease]; | |
[operation setSubscription:subscription]; | |
[operation setFolder:folder]; | |
[operation setAdd:NO]; | |
[operation setRemove:YES]; | |
[operation setQueuePriority:NSOperationQueuePriorityHigh]; | |
[requestQueue addOperation:operation]; | |
} | |
// subscribe to a feed | |
- (void)subscribeToURLWithString:(NSString *)URL | |
{ | |
} | |
// unsubscribe from a feed | |
- (void)unsubscribe:(GDataSubscription *)subscription | |
{ | |
LOGGED_IN | |
[self processPendingChanges]; | |
GDataSubscriptionEditLabel * operation = [[[GDataSubscriptionEditLabel alloc] init] autorelease]; | |
[operation setSubscription:subscription]; | |
[operation setUnsubscribe:YES]; | |
[operation setQueuePriority:NSOperationQueuePriorityVeryHigh]; | |
[requestQueue addOperation:operation]; | |
} | |
- (void)requestReadItemsForSubscription:(GDataSubscription *)sub | |
{ | |
LOGGED_IN | |
[self processPendingChanges]; | |
GDataItems * operation = [[[GDataItems alloc] init] autorelease]; | |
[operation setSubscription:sub]; | |
[operation setMaxCount:[self maxFetchCount]]; | |
[operation setType:GDATA_ITEMS_TYPE_READ]; | |
[operation setFetchUID:[[NSProcessInfo processInfo] globallyUniqueString]]; | |
[operation setQueuePriority:NSOperationQueuePriorityNormal]; | |
[self orderItemsOperation:operation]; | |
[requestQueue addOperation:operation]; | |
} | |
- (void)requestItemsForSubscription:(GDataSubscription *)sub | |
{ | |
LOGGED_IN | |
[self processPendingChanges]; | |
GDataItems * operation = [[[GDataItems alloc] init] autorelease]; | |
[operation setSubscription:sub]; | |
[operation setMaxCount:[self maxFetchCount]]; | |
[operation setType:GDATA_ITEMS_TYPE_UNREAD]; | |
[operation setFetchUID:[[NSProcessInfo processInfo] globallyUniqueString]]; | |
[operation setQueuePriority:NSOperationQueuePriorityNormal]; | |
[self orderItemsOperation:operation]; | |
[requestQueue addOperation:operation]; | |
} | |
// add a feed | |
- (void)addSubscriptionWithURLString:(NSString *)URLString | |
{ | |
LOGGED_IN | |
[self processPendingChanges]; | |
GDataSubscriptionAdd * operation = [[[GDataSubscriptionAdd alloc] initWithURLString:URLString] autorelease]; | |
[operation setQueuePriority:NSOperationQueuePriorityVeryHigh]; | |
[operation setDelegate:[self addSubscriptionDelegate]]; | |
[requestQueue addOperation:operation]; | |
} | |
// pauses the current operations queue | |
- (void)pauseRequestQueue | |
{ | |
[requestQueue setSuspended:YES]; | |
} | |
// continues the request queue | |
- (void)continueRequestQueue | |
{ | |
LOGGED_IN | |
[requestQueue setSuspended:NO]; | |
} | |
// removes all objects from the request queue | |
- (void)clearRequestQueue | |
{ | |
[requestQueue cancelAllOperations]; | |
} | |
// request ids until a certain date | |
- (void)requestReadItemsFromNowToDate:(NSDate *)date | |
{ | |
[self requestReadItemsFromNowToDate:date | |
useIds:YES]; | |
} | |
- (void)requestIdentifiersFromNowToDate:(NSDate *)date | |
type:(int)type | |
{ | |
LOGGED_IN; | |
[self processPendingChanges]; | |
GDataItemIdentifiers * identifiers = [[[GDataItemIdentifiers alloc] initWithDate:date] autorelease]; | |
[identifiers setQueuePriority:NSOperationQueuePriorityHigh]; | |
[identifiers setType:type]; | |
[requestQueue addOperation:identifiers]; | |
} | |
- (void)requestReadItemsFromNowToDate:(NSDate *)date | |
useIds:(BOOL)flag | |
{ | |
LOGGED_IN | |
[self processPendingChanges]; | |
if( flag ) | |
{ | |
GDataItemIdentifiers * identifiers = [[[GDataItemIdentifiers alloc] initWithDate:date] autorelease]; | |
[identifiers setQueuePriority:NSOperationQueuePriorityHigh]; | |
[identifiers setType:GDATA_ITEMS_TYPE_READ]; | |
[requestQueue addOperation:identifiers]; | |
return; | |
} | |
GDataItems * items = [[[GDataItems alloc] init] autorelease]; | |
[items setType:GDATA_ITEMS_TYPE_READ]; | |
[items setLimitByDate:YES]; | |
[items setToDate:date]; | |
[requestQueue addOperation:items]; | |
} | |
// refresh favicons | |
- (void)refreshFavicons:(NSArray *)subscriptions | |
force:(BOOL)flag | |
{ | |
LOGGED_IN | |
for( GDataSubscription * subscription in subscriptions ) | |
{ | |
if( ! flag && [[self delegate] respondsToSelector:@selector(gDataController:checkFaviconExistanceForSubscription:)] ) | |
{ | |
if( [[self delegate] gDataController:self | |
checkFaviconExistanceForSubscription:subscription] ) | |
{ | |
continue; | |
} | |
} | |
[favIconQueue addOperationWithBlock:^(void){ | |
NSString * url = [[subscription identifier] stringByReplacingOccurrencesOfString:@"feed/" | |
withString:@""]; | |
if( [subscription htmlURL] ) | |
{ | |
url = [subscription htmlURL]; | |
} | |
url = [[NSURL URLWithString:url] host]; | |
// check the link href | |
NSError * error; | |
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@",url]]]; | |
NSString * html = nil; | |
html = [[[NSString alloc] initWithData:data | |
encoding:NSUTF8StringEncoding] autorelease]; | |
if( [html length] ) | |
{ | |
NSXMLDocument * DOM = nil; | |
DOM = [[[NSXMLDocument alloc] initWithXMLString:html | |
options:NSXMLDocumentXHTMLKind|NSXMLDocumentTidyHTML | |
error:&error] autorelease]; | |
if( DOM == nil || DOM == NULL ) | |
{ | |
return; | |
} | |
NSArray * nodes = [[DOM rootElement] nodesForXPath:@"head/link[contains(@rel,'icon')]" | |
error:&error]; | |
if( [nodes count] ) | |
{ | |
NSString * href = [[[nodes lastObject] attributeForName:@"href"] stringValue]; | |
if( [href rangeOfString:@"http"].location != NSNotFound ) | |
{ | |
url = href; | |
} else { | |
url = [NSString stringWithFormat:@"http://%@%@",url,href]; | |
} | |
} else { | |
url = [NSString stringWithFormat:@"http://%@/favicon.ico",url]; | |
} | |
} else { | |
url = [NSString stringWithFormat:FAVICON_URL,url]; | |
} | |
NSData * blob = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]]; | |
dispatch_async( dispatch_get_main_queue(), ^{ | |
NSData * returnData = blob; | |
if( ! [blob length] ) | |
{ | |
returnData = nil; | |
} | |
// tell the delegate we receieved the data | |
if( [[self delegate] conformsToProtocol:@protocol(GDataControllerDelegate)] ) | |
{ | |
[[self delegate] gDataController:self | |
didReceieveFaviconData:returnData | |
forSubscription:subscription]; | |
} | |
}); | |
}]; | |
} | |
} | |
- (void)searchForSubscritionsWithTerm:(NSString *)term | |
maxResults:(NSInteger)results | |
{ | |
NSInteger pages = ceil( results / 10 ); | |
for( NSInteger i = 0; i < pages; i++ ) | |
{ | |
[self searchForSubscritionsWithTerm:term | |
page:i]; | |
} | |
} | |
- (void)searchForSubscritionsWithTerm:(NSString *)term | |
page:(NSInteger)page | |
{ | |
GDataSearchSubscriptions * operation = [[[GDataSearchSubscriptions alloc] initWithSearchTerm:term | |
page:page] autorelease]; | |
[operation setQueuePriority:NSOperationQueuePriorityHigh]; | |
[requestQueue addOperation:operation]; | |
} | |
- (void)cancelAllSearchSubscriptionsRequests | |
{ | |
for( id operation in [requestQueue operations] ) | |
{ | |
if( [operation isKindOfClass:[GDataSearchSubscriptions class]] ) | |
{ | |
[operation cancel]; | |
} | |
} | |
} | |
#pragma mark GDataSearchSubscriptions | |
- (void)gDataSearchSubscriptions:(GDataSearchSubscriptions *)operation | |
didFindSubscriptions:(NSArray *)subscriptions | |
term:(NSString *)term | |
page:(NSInteger)page | |
continuation:(BOOL)flag | |
{ | |
if( [subscriptions count] == 0 && ! flag ) | |
{ | |
return; | |
} else if( [subscriptions count] == 0 && flag ) { | |
GDataSearchSubscriptions * newSub = [[operation copy] autorelease]; | |
[newSub setPage:(page+1)]; | |
[requestQueue addOperation:newSub]; | |
} | |
if( [[self searchSubscriptionsDelegate] conformsToProtocol:@protocol(GDataSearchSubscriptionsDelegate)] ) | |
{ | |
[[self searchSubscriptionsDelegate] gDataController:self | |
didFindSubscriptions:subscriptions | |
searchTerm:term | |
page:page | |
continuation:flag]; | |
} | |
} | |
#pragma mark GDataItemEditTagDelegate | |
- (void)gDataItemDidEditTag:(int)tag | |
operation:(GDataItemEditTag *)operation | |
queueIdentifier:(NSString *)queueIdentifier | |
{ | |
NSInteger num = [[tagQueueCounts objectForKey:queueIdentifier] integerValue]; | |
num--; | |
if( num == 0 ) | |
{ | |
syncEndTime = [[NSDate date] timeIntervalSince1970]; | |
[tagQueueCounts removeObjectForKey:queueIdentifier]; | |
if( [[self delegate] respondsToSelector:@selector(gDataControllerDidSyncLocalChanges:)] ) | |
{ | |
[[self delegate] gDataControllerDidSyncLocalChanges:self]; | |
} | |
} else { | |
[tagQueueCounts setObject:[NSNumber numberWithInteger:num] | |
forKey:queueIdentifier]; | |
} | |
} | |
#pragma mark GDataUnreadCountDelegate | |
- (void)gDataUnreadCount:(GDataUnreadCount *)obj | |
didReceiveUnreadCounts:(NSMutableDictionary *)counts | |
{ | |
NSInteger count = 0; | |
for( NSNumber * number in [counts allValues] ) | |
{ | |
count += [number integerValue]; | |
} | |
float f = ((float)count / (float)[self maxFetchCount]); | |
count = ceilf( f ); | |
unreadPageCount = count; | |
if( [[self delegate] respondsToSelector:@selector(gDataController:didReceivePageCount:)] ) | |
{ | |
[[self delegate] gDataController:self | |
didReceivePageCount:count]; | |
} | |
if( [[self delegate] respondsToSelector:@selector(gDataController:didReceiveUnreadCounts:)] ) | |
{ | |
[[self delegate] gDataController:self | |
didReceiveUnreadCounts:counts]; | |
} | |
} | |
#pragma mark GDataOperationDelegate | |
// if net connection is lost | |
- (void)gDataOperationDidLoseConnection:(GDataOperation *)operation | |
{ | |
} | |
// if an operation fails, its most likely to a token expired | |
// if it does expire, grab a new one and add the operation | |
// back into the queue | |
- (void)gDataOperationFailed:(GDataOperation *)operation | |
requestToken:(BOOL)flag | |
{ | |
if( flag ) | |
{ | |
// add to our failed queue | |
GGLog(@"Token request from class %@",[operation class]); | |
[self authenticateWithCredentials:[self credentials]]; | |
[requestQueue setSuspended:YES]; | |
[requestQueue addOperation:[[operation copy] autorelease]]; | |
} else { | |
// assume no net connection | |
BOOL shouldSuspend = YES; | |
GGLog(@"Lost net connection...?"); | |
if( [[self delegate] respondsToSelector:@selector(gDataControllerShouldSuspendQueues:)] ) | |
{ | |
shouldSuspend = [[self delegate] gDataControllerShouldSuspendQueues:self]; | |
} | |
// suspend the queues | |
if( shouldSuspend ) | |
{ | |
[requestQueue setSuspended:YES]; | |
[requestQueue addOperation:[[operation copy] autorelease]]; | |
} | |
} | |
} | |
#pragma mark GDataAuthDelegate | |
- (void)gDataAuthDidAuthenticate:(GDataAuth *)auth | |
account:(GDataAccount *)anAccount | |
{ | |
[self setLoggedIn:YES]; | |
if( firstRun && ! [self ignoreArchivedChanges] ) | |
{ | |
[self unarchivePreferences]; | |
dateCheckDictionary = [[prefs objectForKey:PREFS_DATE_CHECKED_KEY] mutableCopy]; | |
if( ! dateCheckDictionary ) | |
{ | |
dateCheckDictionary = [[NSMutableDictionary alloc] init]; | |
} | |
[self unarchivePendingChanges]; | |
} | |
// save account info | |
[self setAccount:anAccount]; | |
// save the session | |
[self setSession:[auth session]]; | |
// any left over failed queues? | |
[requestQueue setSuspended:NO]; | |
[auth release]; | |
[self setAuthenticating:NO]; | |
if( [[self delegate] conformsToProtocol:@protocol(GDataControllerDelegate)] ) | |
{ | |
// tell delegate were good to go | |
[[self delegate] gDataControllerDidAuthenticate:self]; | |
} | |
} | |
- (void)gDataAuthDidFailToAuthenticate:(GDataAuth *)auth | |
{ | |
if( [[self delegate] conformsToProtocol:@protocol(GDataControllerDelegate)] ) | |
{ | |
[[self delegate] gDataControllerDidFailToAuthenticate:self]; | |
} | |
} | |
#pragma mark GDataSubscriptionsEditDelegate | |
- (void)gDataSubscriptionEdit:(GDataSubscriptionEditLabel *)edit | |
didRemoveSubscription:(GDataSubscription *)subscription | |
{ | |
if( [[self delegate] conformsToProtocol:@protocol(GDataControllerDelegate)] ) | |
{ | |
[[self delegate] gDataController:self | |
didRemoveSubscription:subscription]; | |
} | |
} | |
#pragma mark GDataItemsDelegate | |
- (void)gDataItems:(GDataItems *)items | |
didReceiveEntryCountBeforeParse:(NSUInteger)count | |
{ | |
if( [[self delegate] conformsToProtocol:@protocol(GDataControllerDelegate)] ) | |
{ | |
[[self delegate] gDataController:self | |
didReceiveEntryCountBeforeParse:count]; | |
} | |
} | |
- (void)gDataItems:(GDataItems *)itemsOperation | |
requiredContinuationWithString:(NSString *)string | |
{ | |
if( [itemsOperation itemsCount] == 0 ) | |
{ | |
return; | |
} | |
if( [itemsOperation maxItemCount] != NSNotFound ) | |
{ | |
NSInteger curCount = 0; | |
if( [[itemRequestCounts allKeys] indexOfObject:[itemsOperation fetchUID]] != NSNotFound ) | |
{ | |
curCount = [[itemRequestCounts objectForKey:[itemsOperation fetchUID]] integerValue]; | |
} | |
curCount += [itemsOperation itemsCount]; | |
if( curCount >= [itemsOperation maxItemCount] ) | |
{ | |
[itemsOperation setStop:YES]; | |
[itemRequestCounts removeObjectForKey:[itemsOperation fetchUID]]; | |
return; | |
} else { | |
[itemRequestCounts setObject:[NSNumber numberWithInteger:curCount] | |
forKey:[itemsOperation fetchUID]]; | |
} | |
} | |
currentSyncCount += [self maxFetchCount]; | |
GDataItems * items = [[itemsOperation copy] autorelease]; | |
[itemsOperation setQueuePriority:([itemsOperation type]==GDATA_ITEMS_TYPE_UNREAD?NSOperationQueuePriorityVeryHigh:NSOperationQueuePriorityVeryLow)]; | |
[items setContinueToken:string]; | |
[self orderItemsOperation:items]; | |
[requestQueue addOperation:items]; | |
} | |
- (void)GDataItemIdentifiers:(GDataItemIdentifiers *)ident | |
didReceieveIdentifiers:(NSArray *)identifiers | |
type:(int)type | |
{ | |
if( [[self delegate] conformsToProtocol:@protocol(GDataControllerDelegate)] ) | |
{ | |
[[self delegate] gDataController:self | |
didReceiveItemIdentifiers:identifiers | |
toDate:[[[ident date] copy] autorelease] | |
type:type]; | |
} | |
} | |
- (void)gDataItems:(GDataItems *)items | |
didReceiveList:(NSArray *)list | |
type:(GDataItemsTag)type | |
{ | |
if( firstRun ) | |
{ | |
firstRun = NO; | |
} | |
if( ! [items continueToken] || [self lazyLoad] ) | |
{ | |
currentSyncCount = 0; | |
} | |
if( ( [items continueToken] == nil || [items stop] ) && [[self delegate] respondsToSelector:@selector(gDataController:didFinishReceivingItemsOfType:)] ) | |
{ | |
[self pushDateForTag:type]; | |
[[self delegate] gDataController:self | |
didFinishReceivingItemsOfType:type]; | |
} | |
if( [[self delegate] conformsToProtocol:@protocol(GDataControllerDelegate)] ) | |
{ | |
[[self delegate] gDataController:self | |
didReceieveItemsList:list | |
type:type | |
continued:( [items continueToken] ? YES : NO )]; | |
} | |
isRefreshingItems = NO; | |
GDataItemsMask mask = GDataUnreadItems; | |
switch( [items type] ) | |
{ | |
case GDATA_ITEMS_TYPE_UNREAD: | |
mask = GDataUnreadItems; | |
break; | |
case GDATA_ITEMS_TYPE_READ: | |
mask = GDataReadItems; | |
break; | |
case GDATA_ITEMS_TYPE_STARRED: | |
mask = GDataStarredItems; | |
break; | |
} | |
[self checkItemsInQueueWithMask:mask]; | |
} | |
#pragma mark GDataSubscriptionsDelegate | |
- (void)gDataSubscriptions:(GDataSubscriptions *)subscriptions | |
didReceiveError:(GDataError *)anError | |
{ | |
} | |
- (void)gDataSubscriptions:(GDataSubscriptions *)subscriptions | |
didReceiveList:(NSArray *)array | |
{ | |
[self refreshFavicons:array | |
force:NO]; | |
if( [[self delegate] conformsToProtocol:@protocol(GDataControllerDelegate)] ) | |
{ | |
[[self delegate] gDataController:self | |
didReceieveSubscriptionList:array]; | |
} | |
} | |
#pragma mark GDataSubscriptionsAddDelegate | |
- (void)gDataSubscriptionsAdd:(GDataSubscriptionAdd *)sub | |
didAddSubscription:(GDataSubscription *)subscription | |
delegate:(id)del | |
{ | |
if( [del respondsToSelector:@selector(gDataController:didSubscribeToSubscription:)] ) | |
{ | |
[del gDataController:self | |
didSubscribeToSubscription:subscription]; | |
[self refreshFavicons:[NSArray arrayWithObject:subscription] | |
force:YES]; | |
} | |
} | |
- (void)gDataSubscriptionsAdd:(GDataSubscriptionAdd *)sub | |
didFailToAddSubscriptionWithURLString:(NSString *)urlString | |
delegate:(id)del | |
{ | |
[del gDataController:self | |
didFailToSubscribeToURLWithString:urlString]; | |
} | |
- (void)gDataItems:(GDataItems *)items | |
didFindImageLocations:(NSArray *)array | |
{ | |
if( [[self delegate] respondsToSelector:@selector(gDataController:didFindImageLocations:)] ) | |
{ | |
[[self delegate] gDataController:self | |
didFindImageLocations:array]; | |
} | |
} | |
- (NSInteger)countForItemsType:(GDataItemsTag)type | |
{ | |
if( [[self delegate] respondsToSelector:@selector(gDataController:countForItemsType:)] ) | |
{ | |
return [[self delegate] gDataController:self | |
countForItemsType:type]; | |
} | |
return -1; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment