2014-02-12 16:39:30 -08:00
|
|
|
//
|
|
|
|
// StoriesCollection.m
|
|
|
|
// NewsBlur
|
|
|
|
//
|
|
|
|
// Created by Samuel Clay on 2/12/14.
|
|
|
|
// Copyright (c) 2014 NewsBlur. All rights reserved.
|
|
|
|
//
|
|
|
|
|
2014-02-12 20:09:37 -08:00
|
|
|
#import "NewsBlurAppDelegate.h"
|
2014-02-12 16:39:30 -08:00
|
|
|
#import "StoriesCollection.h"
|
|
|
|
|
|
|
|
@implementation StoriesCollection
|
|
|
|
|
2014-02-12 20:09:37 -08:00
|
|
|
@synthesize appDelegate;
|
|
|
|
@synthesize activeFeed;
|
|
|
|
@synthesize activeClassifiers;
|
|
|
|
@synthesize activePopularTags;
|
|
|
|
@synthesize activePopularAuthors;
|
|
|
|
@synthesize activeFolder;
|
|
|
|
@synthesize activeFolderFeeds;
|
|
|
|
@synthesize activeFeedStories;
|
|
|
|
@synthesize activeFeedStoryLocations;
|
|
|
|
@synthesize activeFeedStoryLocationIds;
|
|
|
|
@synthesize activeFeedUserProfiles;
|
|
|
|
@synthesize storyCount;
|
|
|
|
@synthesize storyLocationsCount;
|
|
|
|
@synthesize visibleUnreadCount;
|
|
|
|
|
|
|
|
@synthesize isRiverView;
|
|
|
|
@synthesize isSocialView;
|
|
|
|
@synthesize isSocialRiverView;
|
|
|
|
|
|
|
|
|
|
|
|
- (id)init {
|
|
|
|
if (self = [super init]) {
|
|
|
|
self.visibleUnreadCount = 0;
|
|
|
|
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)initForDashboard {
|
|
|
|
if (self = [self init]) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - Story Traversal
|
|
|
|
|
|
|
|
- (BOOL)isStoryUnread:(NSDictionary *)story {
|
|
|
|
BOOL readStatusUnread = [[story objectForKey:@"read_status"] intValue] == 0;
|
|
|
|
BOOL storyHashUnread = [[appDelegate.unreadStoryHashes
|
|
|
|
objectForKey:[story objectForKey:@"story_hash"]] boolValue];
|
|
|
|
BOOL recentlyRead = [[appDelegate.recentlyReadStories
|
|
|
|
objectForKey:[story objectForKey:@"story_hash"]] boolValue];
|
|
|
|
|
|
|
|
// NSLog(@"isUnread: (%d || %d) && %d (%@ / %@)", readStatusUnread, storyHashUnread,
|
|
|
|
// !recentlyRead, [[story objectForKey:@"story_title"] substringToIndex:10],
|
|
|
|
// [story objectForKey:@"story_hash"]);
|
|
|
|
|
|
|
|
return (readStatusUnread || storyHashUnread) && !recentlyRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)calculateStoryLocations {
|
|
|
|
self.visibleUnreadCount = 0;
|
|
|
|
self.activeFeedStoryLocations = [NSMutableArray array];
|
|
|
|
self.activeFeedStoryLocationIds = [NSMutableArray array];
|
|
|
|
for (int i=0; i < self.storyCount; i++) {
|
|
|
|
NSDictionary *story = [self.activeFeedStories objectAtIndex:i];
|
|
|
|
NSInteger score = [NewsBlurAppDelegate computeStoryScore:[story objectForKey:@"intelligence"]];
|
|
|
|
if (score >= appDelegate.selectedIntelligence || [[story objectForKey:@"sticky"] boolValue]) {
|
|
|
|
NSNumber *location = [NSNumber numberWithInt:i];
|
|
|
|
[self.activeFeedStoryLocations addObject:location];
|
|
|
|
[self.activeFeedStoryLocationIds addObject:[story objectForKey:@"id"]];
|
|
|
|
if ([[story objectForKey:@"read_status"] intValue] == 0) {
|
|
|
|
self.visibleUnreadCount += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)indexOfNextUnreadStory {
|
|
|
|
NSInteger location = [self locationOfNextUnreadStory];
|
|
|
|
return [self indexFromLocation:location];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)locationOfNextUnreadStory {
|
|
|
|
NSInteger activeLocation = [self locationOfActiveStory];
|
|
|
|
|
|
|
|
for (NSInteger i=activeLocation+1; i < [self.activeFeedStoryLocations count]; i++) {
|
|
|
|
NSInteger storyIndex = [[self.activeFeedStoryLocations objectAtIndex:i] intValue];
|
|
|
|
NSDictionary *story = [activeFeedStories objectAtIndex:storyIndex];
|
|
|
|
if ([self isStoryUnread:story]) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (activeLocation > 0) {
|
|
|
|
for (NSInteger i=activeLocation-1; i >= 0; i--) {
|
|
|
|
NSInteger storyIndex = [[self.activeFeedStoryLocations objectAtIndex:i] intValue];
|
|
|
|
NSDictionary *story = [activeFeedStories objectAtIndex:storyIndex];
|
|
|
|
if ([self isStoryUnread:story]) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)indexOfNextStory {
|
|
|
|
NSInteger location = [self locationOfNextStory];
|
|
|
|
return [self indexFromLocation:location];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)locationOfNextStory {
|
|
|
|
NSInteger activeLocation = [self locationOfActiveStory];
|
|
|
|
NSInteger nextStoryLocation = activeLocation + 1;
|
|
|
|
if (nextStoryLocation < [self.activeFeedStoryLocations count]) {
|
|
|
|
return nextStoryLocation;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)indexOfActiveStory {
|
|
|
|
for (NSInteger i=0; i < self.storyCount; i++) {
|
|
|
|
NSDictionary *story = [activeFeedStories objectAtIndex:i];
|
|
|
|
if ([appDelegate.activeStory objectForKey:@"id"] == [story objectForKey:@"id"]) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)indexOfStoryId:(id)storyId {
|
|
|
|
for (int i=0; i < self.storyCount; i++) {
|
|
|
|
NSDictionary *story = [activeFeedStories objectAtIndex:i];
|
|
|
|
if ([story objectForKey:@"id"] == storyId) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)locationOfStoryId:(id)storyId {
|
|
|
|
for (int i=0; i < [activeFeedStoryLocations count]; i++) {
|
|
|
|
if ([activeFeedStoryLocationIds objectAtIndex:i] == storyId) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)locationOfActiveStory {
|
|
|
|
for (int i=0; i < [activeFeedStoryLocations count]; i++) {
|
|
|
|
if ([[activeFeedStoryLocationIds objectAtIndex:i]
|
|
|
|
isEqualToString:[appDelegate.activeStory objectForKey:@"id"]]) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)indexFromLocation:(NSInteger)location {
|
|
|
|
if (location == -1) return -1;
|
|
|
|
return [[activeFeedStoryLocations objectAtIndex:location] intValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)activeOrder {
|
|
|
|
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
|
|
|
|
NSString *orderPrefDefault = [userPreferences stringForKey:@"default_order"];
|
|
|
|
NSString *orderPref = [userPreferences stringForKey:[self orderKey]];
|
|
|
|
|
|
|
|
if (orderPref) {
|
|
|
|
return orderPref;
|
|
|
|
} else if (orderPrefDefault) {
|
|
|
|
return orderPrefDefault;
|
|
|
|
} else {
|
|
|
|
return @"newest";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)activeReadFilter {
|
|
|
|
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
|
|
|
|
NSString *readFilterFeedPrefDefault = [userPreferences stringForKey:@"default_feed_read_filter"];
|
|
|
|
NSString *readFilterFolderPrefDefault = [userPreferences stringForKey:@"default_folder_read_filter"];
|
|
|
|
NSString *readFilterPref = [userPreferences stringForKey:[self readFilterKey]];
|
|
|
|
|
|
|
|
if (readFilterPref) {
|
|
|
|
return readFilterPref;
|
|
|
|
} else if (self.isRiverView || self.isSocialRiverView) {
|
|
|
|
if (readFilterFolderPrefDefault) {
|
|
|
|
return readFilterFolderPrefDefault;
|
|
|
|
} else {
|
|
|
|
return @"unread";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (readFilterFeedPrefDefault) {
|
|
|
|
return readFilterFeedPrefDefault;
|
|
|
|
} else {
|
|
|
|
return @"all";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)orderKey {
|
|
|
|
if (self.isRiverView) {
|
|
|
|
return [NSString stringWithFormat:@"folder:%@:order", self.activeFolder];
|
|
|
|
} else {
|
|
|
|
return [NSString stringWithFormat:@"%@:order", [self.activeFeed objectForKey:@"id"]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)readFilterKey {
|
|
|
|
if (self.isRiverView) {
|
|
|
|
return [NSString stringWithFormat:@"folder:%@:read_filter", self.activeFolder];
|
|
|
|
} else {
|
|
|
|
return [NSString stringWithFormat:@"%@:read_filter", [self.activeFeed objectForKey:@"id"]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Story Management
|
|
|
|
|
|
|
|
- (void)addStories:(NSArray *)stories {
|
|
|
|
self.activeFeedStories = [self.activeFeedStories arrayByAddingObjectsFromArray:stories];
|
|
|
|
self.storyCount = [self.activeFeedStories count];
|
|
|
|
[self calculateStoryLocations];
|
|
|
|
self.storyLocationsCount = [self.activeFeedStoryLocations count];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setStories:(NSArray *)activeFeedStoriesValue {
|
|
|
|
self.activeFeedStories = activeFeedStoriesValue;
|
|
|
|
self.storyCount = [self.activeFeedStories count];
|
|
|
|
appDelegate.recentlyReadFeeds = [NSMutableSet set];
|
|
|
|
[self calculateStoryLocations];
|
|
|
|
self.storyLocationsCount = [self.activeFeedStoryLocations count];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setFeedUserProfiles:(NSArray *)activeFeedUserProfilesValue{
|
|
|
|
self.activeFeedUserProfiles = activeFeedUserProfilesValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)addFeedUserProfiles:(NSArray *)activeFeedUserProfilesValue {
|
|
|
|
self.activeFeedUserProfiles = [self.activeFeedUserProfiles arrayByAddingObjectsFromArray:activeFeedUserProfilesValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)pushReadStory:(id)storyId {
|
|
|
|
if ([appDelegate.readStories lastObject] != storyId) {
|
|
|
|
[appDelegate.readStories addObject:storyId];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)popReadStory {
|
|
|
|
if (storyCount == 0) {
|
|
|
|
return nil;
|
|
|
|
} else {
|
|
|
|
[appDelegate.readStories removeLastObject];
|
|
|
|
id lastStory = [appDelegate.readStories lastObject];
|
|
|
|
return lastStory;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-12 16:39:30 -08:00
|
|
|
@end
|