#import "ThingsTaskHandler.h" NS_ASSUME_NONNULL_BEGIN @implementation ThingsTaskHandler - (BOOL)objectHasChildren:(QSObject *)object { return YES; } - (void)setQuickIconForObject:(QSObject *)object { NSImage *baseImage = [QSResourceManager imageNamed:@"com.culturedcode.ThingsMac"]; NSString *badge = @"checkmark.circle"; NSColor *color = [NSColor colorWithRed:0.310 green:0.616 blue:0.976 alpha:1.0]; if (object.primaryType == kProjectType) { badge = @"circle"; color = [NSColor colorWithRed:0.157 green:0.376 blue:0.733 alpha:1.0]; } NSImage *imageWithBadge = [baseImage imageOfSize:NSMakeSize(512, 512) withSystemBadge:badge ofColor:color]; if (imageWithBadge) { [object setIcon:imageWithBadge]; } else { [object setIcon:baseImage]; } } - (BOOL)loadChildrenForObject:(QSObject *)object { NSDictionary *contents = [object objectForType:object.primaryType]; if (!contents) { NSLog(@"Malformed Things Task: No content."); return NO; } NSString *path = [contents objectForKey:@"path"]; if (!path) { NSLog(@"Malformed Things Task: No path."); return NO; } NSString *uuid = [contents objectForKey:@"uuid"]; if (!uuid) { NSLog(@"Malformed Things Task: No uuid."); return NO; } // Tasks and Projects are basically the same thing in the Things database. So we use the same handler. // The big difference is that projects can't have projects, and tasks can't have tasks NSMutableArray *children = [NSMutableArray array]; [children addObjectsFromArray:[self tagsForTaskIdentifiedBy:uuid usingDatabaseAt:path ]]; [children addObjectsFromArray:[self areasForTaskIdentifiedBy:uuid usingDatabaseAt:path ]]; if (object.primaryType == kProjectType) { [children addObjectsFromArray:[self tasksForTaskIdentifiedBy:uuid usingDatabaseAt:path ]]; [children addObjectsFromArray:[self tasksInHeadingsForTaskIdentifiedBy:uuid usingDatabaseAt:path ]]; } else { [children addObjectsFromArray:[self projectsForTaskIdentifiedBy:uuid usingDatabaseAt:path ]]; } [object setChildren:children]; return YES; } - (NSArray *)tagsForTaskIdentifiedBy:(NSString *)uuid usingDatabaseAt:(NSString *)path { NSString *query = [NSString stringWithFormat: @"SELECT " "tag.uuid as uuid, " "tag.title as title " "FROM TMTask AS task " "LEFT JOIN TMTaskTag as junction " "ON junction.tasks = task.uuid " "LEFT JOIN TMTag as tag " "ON junction.tags = tag.uuid " "WHERE task.uuid = '%@' " "AND tag.uuid IS NOT NULL " "ORDER BY tag.title;", uuid]; NSArray *results = [SQLHelper executeSql:query onFile:path]; NSMutableArray *objects = [NSMutableArray array]; [results enumerateObjectsUsingBlock:^(NSDictionary *dictionary, NSUInteger i, BOOL *stop) { [objects addObject:[ObjectHelper tagFromSQLResult:dictionary usingPath:path ]]; }]; return objects; } - (NSArray *)projectsForTaskIdentifiedBy:(NSString *)uuid usingDatabaseAt:(NSString *)path { NSString *query = [NSString stringWithFormat: @"SELECT " "project.uuid as uuid, " "project.creationDate as creationDate, " "project.status as status, " "project.title as title, " "project.notes as notes, " "project.area as area " "FROM TMTask AS task " "LEFT JOIN TMTask as project " "ON task.project = project.uuid " "AND project.type = 1 " "WHERE task.uuid = '%@' " "AND project.uuid IS NOT NULL " "AND project.trashed = 0 " "AND project.status = 0 " "ORDER BY project.title;", uuid]; NSArray *results = [SQLHelper executeSql:query onFile:path]; NSMutableArray *objects = [NSMutableArray array]; [results enumerateObjectsUsingBlock:^(NSDictionary *dictionary, NSUInteger i, BOOL *stop) { [objects addObject:[ObjectHelper projectFromSQLResult:dictionary usingPath:path ]]; }]; return objects; } - (NSArray *)areasForTaskIdentifiedBy:(NSString *)uuid usingDatabaseAt:(NSString *)path { NSString *query = [NSString stringWithFormat: @"SELECT " "area.uuid as uuid, " "area.title as title " "FROM TMTask AS task " "LEFT JOIN TMTask as project " "ON task.project = project.uuid " "LEFT JOIN TMArea as area " "ON task.area = area.uuid OR project.area = area.uuid " "WHERE task.uuid = '%@' " "AND area.uuid IS NOT NULL " "ORDER BY area.title;", uuid]; NSArray *results = [SQLHelper executeSql:query onFile:path]; NSMutableArray *objects = [NSMutableArray array]; if (results) { [results enumerateObjectsUsingBlock:^(NSDictionary *dictionary, NSUInteger i, BOOL *stop) { [objects addObject:[ObjectHelper areaFromSQLResult:dictionary usingPath:path ]]; }]; } return objects; } - (NSArray *)tasksForTaskIdentifiedBy:(NSString *)uuid usingDatabaseAt:(NSString *)path { NSString *query = [NSString stringWithFormat: @"SELECT " "uuid, " "creationDate, " "status, " "title, " "notes, " "area " "FROM TMTask " "WHERE project = '%@' " "AND type = 0 " "AND trashed = 0 " "AND status = 0 " "ORDER BY title;", uuid]; NSArray *results = [SQLHelper executeSql:query onFile:path]; NSMutableArray *objects = [NSMutableArray array]; [results enumerateObjectsUsingBlock:^(NSDictionary *dictionary, NSUInteger i, BOOL *stop) { [objects addObject:[ObjectHelper taskFromSQLResult:dictionary usingPath:path ]]; }]; return objects; } - (NSArray *)tasksInHeadingsForTaskIdentifiedBy:(NSString *)uuid usingDatabaseAt:(NSString *)path { NSString *query = [NSString stringWithFormat: @"SELECT " "task.uuid as uuid, " "task.creationDate as creationDate, " "task.status as status, " "task.title as title, " "task.notes as notes, " "task.area as area " "FROM TMTask AS heading " "LEFT JOIN TMTask AS task " "ON task.heading = heading.uuid " "WHERE heading.project = '%@' " "AND task.type = 0 " "AND task.trashed = 0 " "AND task.status = 0 " "ORDER BY task.title;", uuid]; NSArray *results = [SQLHelper executeSql:query onFile:path]; NSMutableArray *objects = [NSMutableArray array]; [results enumerateObjectsUsingBlock:^(NSDictionary *dictionary, NSUInteger i, BOOL *stop) { [objects addObject:[ObjectHelper taskFromSQLResult:dictionary usingPath:path ]]; }]; return objects; } @end NS_ASSUME_NONNULL_END