// // TopicsViewController.m // acidcow // // Created by Matthew Handler on 4/15/11. // Copyright 2011 Earl Industries. All rights reserved. // #import "TopicsViewController.h" #import "Topic.h" #import "TopicTableViewCell.h" #import "AcidCowFeedburnerParser.h" #import "PhotoViewController.h" //#import "AsyncImageView.h" #import "HJObjManager.h" #import "HJManagedImageV.h" #import "SourcesEditViewController.h" #import "SectionDictionary.h" #import "FMDatabase.h" #import "FMResultSet.h" #import "PicCastAppDelegate.h" #import "CJSONDeserializer.h" #import "Fetcher.h" #import "Source.h" @implementation TopicsViewController @synthesize tableView, sourcesDictionary; - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"viewDidLoad"); [self.navigationController.navigationBar drawLogo]; self.tableView.rowHeight = 100; [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine]; [self.tableView setSeparatorColor:[UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0]]; UIView *backgroundView = [[UIView alloc] initWithFrame:self.view.frame]; backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"backgroundGradient.png"]]; self.tableView.backgroundView = backgroundView; self.tableView.backgroundColor = [UIColor clearColor]; [backgroundView release]; objMan = [[HJObjManager alloc] initWithLoadingBufferSize:6 memCacheSize:20]; _today = [[Topic dateToString:[NSDate new]] retain]; _yesterday = [[Topic dateToString:[NSDate dateWithTimeIntervalSinceNow:(NSTimeInterval)-86400]] retain]; _tomorrow = [[Topic dateToString:[NSDate dateWithTimeIntervalSinceNow:(NSTimeInterval)+86400]] retain]; NSString* cacheDirectory = [NSHomeDirectory() stringByAppendingString:@"/Library/Caches/imgcache/icons/"] ; HJMOFileCache* fileCache = [[[HJMOFileCache alloc] initWithRootPath:cacheDirectory] autorelease]; objMan.fileCache = fileCache; // Have the file cache trim itself down to a size & age limit, so it doesn't grow forever fileCache.fileCountLimit = 100; fileCache.fileAgeLimit = 60*60*24*7; //1 week [fileCache trimCacheUsingBackgroundThread]; tableDictionary = [[[SectionDictionary alloc] init] retain]; sourcesDictionary = [[[NSMutableDictionary alloc] init] retain]; db = [[FMDatabase databaseWithPath:[PicCastAppDelegate getDatabasePath]] retain]; [db setShouldCacheStatements:NO]; // [db setTraceExecution:true]; // [db setLogsErrors:true]; [self getTopicsFromDb]; [self loadSubscribedTopics]; } - (void) getTopicsFromDb { // grab topics [db open]; FMResultSet *fResult = [db executeQuery:@"SELECT * FROM picCasts ORDER BY releaseDate DESC"]; //order by date, limite _max // put into sections while([fResult next]) { [self addTopicToSectionDictionary:[Topic initFromDatabaseRow:fResult]]; } [fResult close]; [db close]; // put into data structure } - (void) addTopicToSectionDictionary:(Topic *)topic { NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [dateFormatter setDateStyle:NSDateFormatterLongStyle]; [dateFormatter setTimeStyle:NSDateFormatterNoStyle]; [dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"US"] autorelease]]; // convert releasedate to today if its tomorrow, acidcowwwww! [tableDictionary appendObject:topic forKey:[dateFormatter dateFromString:[dateFormatter stringFromDate:topic.releaseDate]]]; } - (void) sourcesEditViewControllerDidFinish:(SourcesEditViewController *)controller { [self dismissModalViewControllerAnimated:YES]; [self loadSubscribedTopics]; //[self _userIs:[controller getUserGenderString] heets:[controller getHeetGenderString]]; } - (void) showSources:(id)sender { SourcesEditViewController *controller = [[SourcesEditViewController alloc] initWithNibName:@"SourcesEditViewController" bundle:nil]; controller.delegate = self; controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; [self presentModalViewController:controller animated:YES]; [controller release]; } - (PhotoViewController *)photoViewController { if (photoViewController == nil) { photoViewController = [[[PhotoViewController alloc] init] autorelease]; } return photoViewController; } #pragma mark - #pragma mark custom sheeyit - (void) addTopicsFromJson:(NSData *)data forSource:(Source *)source { NSError *theError = nil; id dictionary = [[CJSONDeserializer deserializer] deserialize:(NSData *)data error:&theError]; NSArray *array = [dictionary objectForKey:@"list"]; [db open]; for (NSDictionary *obj in array) { FMResultSet *result = [db executeQuery:@"SELECT id FROM picCasts WHERE foreignId = ?", [obj objectForKey:@"id"]]; if (![result next]) { NSLog(@"found new topic"); Topic *topic = [Topic initWithJsonObject:obj]; topic.sourceId = source.foreignId; NSLog(@"new topic on: %@", [Topic dateToString:topic.releaseDate]); if ([topic.picCount intValue] != 0) { [db beginTransaction]; [topic serializeToDatabase:db]; [db commit]; [self addTopicToSectionDictionary:topic]; } } [result close]; } [db close]; [self restructureSections]; } - (void) restructureSections { [self.tableView reloadData]; } // //- (void) addTopicsFromJson:(NSData *)data { // // NSError *theError = nil; // id dictionary = [[CJSONDeserializer deserializer] deserialize:(NSData *)data error:&theError]; // NSArray *array = [dictionary objectForKey:@"list"]; // // [db open]; // for (NSDictionary *obj in array) { // FMResultSet *result = [db executeQuery:@"SELECT id FROM picCasts WHERE foreignId = ?", [obj objectForKey:@"id"]]; // if (![result next]) { // Topic *topic = [Topic initWithJsonObject:obj]; // // if (topic.picCount == 0) break; // NSLog(@"new topic on: %@", [Topic dateToString:topic.releaseDate]); // [db beginTransaction]; // [topic serializeToDatabase:db]; // [db commit]; // // [self addTopicToSectionDictionary:topic]; // } // [result close]; // } // [db close]; // // [self.tableView reloadData]; //} - (void) loadSubscribedTopics { //NSLog(@"load subscribed"); [db open]; FMResultSet *result = [db executeQuery:@"SELECT * FROM sources WHERE subscribed = ?", [NSNumber numberWithInt:1]]; while ([result next]) { Source *source = [[[Source alloc] init] autorelease]; if ([sourcesDictionary objectForKey:[NSNumber numberWithInt:[result intForColumn:@"foreignId"]]] != nil) { source = [sourcesDictionary objectForKey:[NSNumber numberWithInt:[result intForColumn:@"foreignId"]]]; } else { source = [Source initFromDatabaseRow:result]; [sourcesDictionary setObject:source forKey:source.foreignId]; } Fetcher *fetcher = [Fetcher initWithString:[NSString stringWithFormat:@"http://piccast.memeschemes.com/json/sets_by_feed/%@/", source.foreignId] payload:source andDelegate:self]; } [result close]; [db close]; [self.navigationController.navigationBar animateLoading]; } #pragma mark - #pragma mark fetcher delegate protocol - (void) connection:(NSURLConnection *)connection failedWithError:(NSError *)error { [PicCastAppDelegate prompt:@"Error" withMessage:[error localizedDescription] andButtonTitle:@"Aww man..." withDelegate:self]; } - (void) connection:(NSURLConnection *)connection finishedWithData:(NSData *)data { //NSLog(@"%@", [[CJSONDeserializer deserializer] deserialize:(NSData *)data error:nil]); [self addTopicsFromJson:data]; } - (void) connection:(NSURLConnection *)connection finishedWithData:(NSData *)data andPayload:(id)payload { [self.navigationController.navigationBar stopLoadingAnimation]; [self addTopicsFromJson:data forSource:(Source *)payload]; } #pragma mark - #pragma mark Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. //NSLog(@"number of sections: %d", [tableDictionary count]); return [tableDictionary count]; } #pragma mark - #pragma mark Table view delegate //- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // // Navigation logic may go here. Create and push another view controller. // /* // <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil]; // // ... // // Pass the selected object to the new view controller. // [self.navigationController pushViewController:detailViewController animated:YES]; // [detailViewController release]; // */ //} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. //NSLog(@"number of rows in section %d: %d", section, [[tableDictionary objectForIndex:section] count]); //NSLog(@"section: %d count: %d", section, [tableDictionary count]); if (section + 1 == ([tableDictionary count])) return [[tableDictionary objectForIndex:section] count] + 1; else return [[tableDictionary objectForIndex:section] count]; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { //NSLog(@"row title: %@", [tableDictionary keyForIndex:section]); //return [tableDictionary keyForIndex:section]; //how do you convert a key to index from mutabledictionary NSString *key = [Topic dateToString:[tableDictionary keyForIndex:section]]; if ([key compare:_today] == 0) return @"Today"; else if ([key compare:_yesterday] == 0) return @"Yesterday"; else if ([key compare:_tomorrow] == 0) return @"Tomorrow"; else return key; // // NSTimeInterval seconds = fabs([topic.releaseDate timeIntervalSinceNow]); // if (seconds <= 86400.0f) // [tableDictionary appendObject:topic forKey:@"Today"]; // else if (seconds <= 172800.0f) // [tableDictionary appendObject:topic forKey:@"Yesterday"]; // else // [tableDictionary appendObject:topic forKey:[Topic dateToString:topic.releaseDate]]; } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; // Configure the view for the selected state. } - (void)viewWillAppear:(BOOL)animated { NSIndexPath *selectedRowIndexPath = [self.tableView indexPathForSelectedRow]; if (selectedRowIndexPath != nil) { [self.tableView deselectRowAtIndexPath:selectedRowIndexPath animated:NO]; } } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section + 1 == [tableDictionary count] && indexPath.row == [[tableDictionary objectForIndex:indexPath.section] count]) return 44; else return 100; } - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath { //NSLog(@"count: %d section: %d", [tableDictionary count], indexPath.section + 1); if ((indexPath.section + 1) == [tableDictionary count] && indexPath.row == [[tableDictionary objectForIndex:indexPath.section] count]) { static NSString *cellIdentifier = @"moreCell"; UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease]; } [cell.textLabel setText:@"load older PicCasts..."]; [cell.textLabel setTextAlignment:UITextAlignmentCenter]; [cell.textLabel setBackgroundColor:[UIColor clearColor]]; //[cell.textLabel setTextColor:[UIColor colorWithRed:0.05 green:0.05 blue:0.05 alpha:0.05]]; UIView *myBackView = [[UIView alloc] initWithFrame:cell.frame]; myBackView.backgroundColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.0]; cell.backgroundView = myBackView; cell.layer.shadowOffset = CGSizeMake(1, 0); cell.layer.shadowColor = [[UIColor blackColor] CGColor]; cell.layer.shadowRadius = 5; cell.layer.shadowOpacity = .75; CGRect shadowFrame = cell.layer.bounds; CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath; cell.layer.shadowPath = shadowPath; return cell; } else { static NSString *kCellIdentifier = @"TopicTableViewCell"; TopicTableViewCell *cell = (TopicTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier]; HJManagedImageV* mi; HJManagedImageV* micon; if (cell == nil) { NSArray *tmpCell = [[NSBundle mainBundle] loadNibNamed:@"TopicTableViewCell" owner:self options:nil]; for (id currentObj in tmpCell) { if ([currentObj isKindOfClass:[TopicTableViewCell class]]) { cell = (TopicTableViewCell *)currentObj; break; } } micon = [[[HJManagedImageV alloc] initWithFrame:CGRectMake(105,72,16,16)] autorelease]; mi = [[[HJManagedImageV alloc] initWithFrame:CGRectMake(3,3,94,94)] autorelease]; mi.tag = 998; mi.tag = 999; [cell.contentView addSubview:micon]; [cell.contentView addSubview:mi]; } else { //Get a reference to the managed image view that was already in the recycled cell, and clear it micon = (HJManagedImageV*)[cell viewWithTag:998]; mi = (HJManagedImageV*)[cell viewWithTag:999]; [micon clear]; [mi clear]; } UIView *myBackView = [[UIView alloc] initWithFrame:cell.frame]; myBackView.backgroundColor = [UIColor whiteColor]; cell.backgroundView = myBackView; Topic *topic = [[tableDictionary objectForIndex:[indexPath section]] objectAtIndex:[indexPath row]]; //cell.useDarkBackground = (indexPath.row % 2 == 0); cell.title = topic.title; [cell.categoryLabel setText:topic.category]; cell.picCount = [NSString stringWithFormat:@"%@", topic.picCount]; micon.url = [NSURL URLWithString:[[sourcesDictionary objectForKey:topic.sourceId] favicon]]; mi.url = [NSURL URLWithString:topic.iconUrl]; mi.squareCropped = true; [objMan manage:mi]; [objMan manage:micon]; return cell; } } - (void)tableView:(UITableView *)table didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // self.picDumpViewController.topic = [topics objectAtIndex:indexPath.row]; if (indexPath.section + 1 == [tableDictionary count] && indexPath.row == [[tableDictionary objectForIndex:indexPath.section] count]) { NSLog(@"load more from database"); } else { self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"back" style:UIBarButtonItemStyleBordered target:nil action:nil]; photoViewController = [[[PhotoViewController alloc] init] autorelease]; photoViewController.topic = [[tableDictionary objectForIndex:indexPath.section] objectAtIndex:indexPath.row]; [self.navigationController pushViewController:photoViewController animated:YES]; //[application setStatusBarStyle:UIStatusBarStyleBlackOpaque]; } } #pragma mark - #pragma mark View lifecycle /* - (void)viewDidLoad { [super viewDidLoad]; // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem; } */ /* - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; } */ /* - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } */ /* - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; } */ /* - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; } */ /* // Override to allow orientations other than the default portrait orientation. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations. return (interfaceOrientation == UIInterfaceOrientationPortrait); } */ // //#pragma mark Implementation // //- (void)startParsing { // NSLog(@"startParsing"); // //self.navigationItem.rightBarButtonItem.enabled = NO; // // Reset the title // //self.title = NSLocalizedString(@"Getting Recent Picdumps...", @"Loading"); // // Allocate the array for song storage, or empty the results of previous parses // if (topics == nil) { // self.topics = [NSMutableArray array]; // } else { // [topics removeAllObjects]; // [self.tableView reloadData]; // } // // Create the parser, set its delegate, and start it. // self.parser = [[[AcidCowFeedburnerParser alloc] init] autorelease]; // parser.delegate = self; // [parser start]; //} // //- (void)parserDidEndParsingData:(XMLParser *)parser { // //self.title = [NSString stringWithFormat:NSLocalizedString(@"Recent Picdumps (%d)", @"Recent"), [topics count]]; // [self.tableView reloadData]; // //self.navigationItem.rightBarButtonItem.enabled = YES; // self.parser = nil; //} // //- (void)parser:(XMLParser *)parser didParseTopics:(NSArray *)parsedTopics { // [self updateTopicsFromWeb:parsedTopics]; // // // Three scroll view properties are checked to keep the user interface smooth during parse. When new objects are delivered // // by the parser, the table view is reloaded to display them. If the table is reloaded while // // the user is scrolling, this can result in eratic behavior. dragging, tracking, and decelerating can be checked // // for this purpose. When the parser finishes, reloadData will be called in parserDidEndParsingData:, guaranteeing // // that all data will ultimately be displayed even if reloadData is not called in this method because of user interaction. // if (!self.tableView.dragging && !self.tableView.tracking && !self.tableView.decelerating) { // //self.title = [NSString stringWithFormat:NSLocalizedString(@"Recent Picdumps (%d)", @"Recent"), [topics count]]; // [self.tableView reloadData]; // } //} // //- (void)parser:(XMLParser *)parser didFailWithError:(NSError *)error { // // handle errors as appropriate to your application... //} #pragma mark - #pragma mark Memory management - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Relinquish ownership any cached data, images, etc. that aren't in use. } - (void)viewDidUnload { // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand. // For example: self.myOutlet = nil; } - (void)dealloc { [_today release]; [_yesterday release]; [_tomorrow release]; [db release]; [sourcesDictionary release]; [tableDictionary release]; [objMan release]; [super dealloc]; } @end