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"
|
2015-09-16 16:53:07 -07:00
|
|
|
#import "SBJson4.h"
|
|
|
|
#import "NSObject+SBJSON.h"
|
2014-02-20 18:23:58 -08:00
|
|
|
#import "FMDatabase.h"
|
2014-02-20 18:40:58 -08:00
|
|
|
#import "Utilities.h"
|
2014-02-12 16:39:30 -08:00
|
|
|
|
|
|
|
@implementation StoriesCollection
|
|
|
|
|
2014-02-12 20:09:37 -08:00
|
|
|
@synthesize appDelegate;
|
|
|
|
@synthesize activeFeed;
|
|
|
|
@synthesize activeClassifiers;
|
|
|
|
@synthesize activePopularTags;
|
|
|
|
@synthesize activePopularAuthors;
|
2014-05-20 15:29:16 -07:00
|
|
|
@synthesize activeSavedStoryTag;
|
2014-02-12 20:09:37 -08:00
|
|
|
@synthesize activeFolder;
|
|
|
|
@synthesize activeFolderFeeds;
|
|
|
|
@synthesize activeFeedStories;
|
|
|
|
@synthesize activeFeedStoryLocations;
|
|
|
|
@synthesize activeFeedStoryLocationIds;
|
|
|
|
@synthesize activeFeedUserProfiles;
|
|
|
|
@synthesize storyCount;
|
|
|
|
@synthesize storyLocationsCount;
|
|
|
|
@synthesize visibleUnreadCount;
|
2014-02-27 14:49:33 -08:00
|
|
|
@synthesize feedPage;
|
2014-02-12 20:09:37 -08:00
|
|
|
|
|
|
|
@synthesize isRiverView;
|
|
|
|
@synthesize isSocialView;
|
|
|
|
@synthesize isSocialRiverView;
|
2014-05-20 15:29:16 -07:00
|
|
|
@synthesize isSavedView;
|
2014-10-22 17:03:48 -07:00
|
|
|
@synthesize isReadView;
|
2014-02-21 12:24:53 -08:00
|
|
|
@synthesize transferredFromDashboard;
|
2014-12-02 18:36:38 -08:00
|
|
|
@synthesize inSearch;
|
|
|
|
@synthesize searchQuery;
|
2014-02-12 20:09:37 -08:00
|
|
|
|
|
|
|
- (id)init {
|
|
|
|
if (self = [super init]) {
|
|
|
|
self.visibleUnreadCount = 0;
|
|
|
|
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
|
2014-04-18 15:50:32 -07:00
|
|
|
self.activeClassifiers = [NSMutableDictionary dictionary];
|
2014-02-12 20:09:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)initForDashboard {
|
|
|
|
if (self = [self init]) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2014-02-21 12:24:53 -08:00
|
|
|
- (void)reset {
|
|
|
|
[self setStories:nil];
|
|
|
|
[self setFeedUserProfiles:nil];
|
|
|
|
|
2014-02-27 14:49:33 -08:00
|
|
|
self.feedPage = 1;
|
2014-02-21 12:24:53 -08:00
|
|
|
self.activeFeed = nil;
|
2014-05-20 15:29:16 -07:00
|
|
|
self.activeSavedStoryTag = nil;
|
2014-02-21 12:24:53 -08:00
|
|
|
self.activeFolder = nil;
|
|
|
|
self.activeFolderFeeds = nil;
|
2014-03-03 16:21:26 -08:00
|
|
|
self.activeClassifiers = [NSMutableDictionary dictionary];
|
2014-02-21 12:24:53 -08:00
|
|
|
|
|
|
|
self.transferredFromDashboard = NO;
|
|
|
|
self.isRiverView = NO;
|
|
|
|
self.isSocialView = NO;
|
|
|
|
self.isSocialRiverView = NO;
|
2014-05-20 15:29:16 -07:00
|
|
|
self.isSavedView = NO;
|
2014-10-22 17:03:48 -07:00
|
|
|
self.isReadView = NO;
|
2014-02-21 12:24:53 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)transferStoriesFromCollection:(StoriesCollection *)fromCollection {
|
2014-02-27 14:49:33 -08:00
|
|
|
self.feedPage = fromCollection.feedPage;
|
2014-02-21 12:24:53 -08:00
|
|
|
[self setStories:fromCollection.activeFeedStories];
|
|
|
|
[self setFeedUserProfiles:fromCollection.activeFeedUserProfiles];
|
|
|
|
self.activeFolderFeeds = fromCollection.activeFolderFeeds;
|
2014-03-03 16:21:26 -08:00
|
|
|
self.activeClassifiers = fromCollection.activeClassifiers;
|
2014-12-02 18:36:38 -08:00
|
|
|
self.inSearch = fromCollection.inSearch;
|
|
|
|
self.searchQuery = fromCollection.searchQuery;
|
2014-02-27 14:49:33 -08:00
|
|
|
|
2014-02-21 12:24:53 -08:00
|
|
|
}
|
|
|
|
|
2014-02-12 20:09:37 -08:00
|
|
|
#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];
|
2014-02-12 20:41:29 -08:00
|
|
|
[self.activeFeedStoryLocationIds addObject:[story objectForKey:@"story_hash"]];
|
2014-02-12 20:09:37 -08:00
|
|
|
if ([[story objectForKey:@"read_status"] intValue] == 0) {
|
|
|
|
self.visibleUnreadCount += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-03-21 16:23:51 -07:00
|
|
|
self.storyLocationsCount = (int)[self.activeFeedStoryLocations count];
|
2014-02-12 20:09:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (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];
|
2014-02-12 20:41:29 -08:00
|
|
|
if ([appDelegate.activeStory objectForKey:@"story_hash"] == [story objectForKey:@"story_hash"]) {
|
2014-02-12 20:09:37 -08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)indexOfStoryId:(id)storyId {
|
|
|
|
for (int i=0; i < self.storyCount; i++) {
|
|
|
|
NSDictionary *story = [activeFeedStories objectAtIndex:i];
|
2014-02-12 20:41:29 -08:00
|
|
|
if ([story objectForKey:@"story_hash"] == storyId) {
|
2014-02-12 20:09:37 -08:00
|
|
|
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]
|
2014-02-12 20:41:29 -08:00
|
|
|
isEqualToString:[appDelegate.activeStory objectForKey:@"story_hash"]]) {
|
2014-02-12 20:09:37 -08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)indexFromLocation:(NSInteger)location {
|
|
|
|
if (location == -1) return -1;
|
2014-12-03 17:27:31 -08:00
|
|
|
if (location >= [activeFeedStoryLocations count]) return -1;
|
2014-02-12 20:09:37 -08:00
|
|
|
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;
|
2014-02-27 17:12:34 -08:00
|
|
|
} else if (self.activeFolder && (self.isRiverView || self.isSocialRiverView)) {
|
2014-02-12 20:09:37 -08:00
|
|
|
if (readFilterFolderPrefDefault) {
|
|
|
|
return readFilterFolderPrefDefault;
|
|
|
|
} else {
|
|
|
|
return @"unread";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (readFilterFeedPrefDefault) {
|
|
|
|
return readFilterFeedPrefDefault;
|
|
|
|
} else {
|
|
|
|
return @"all";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-10 18:58:23 -07:00
|
|
|
- (NSString *)activeStoryView {
|
|
|
|
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
|
|
|
|
NSString *storyViewPref = [userPreferences stringForKey:[self storyViewKey]];
|
2015-04-26 21:22:25 -07:00
|
|
|
// NSLog(@"Story pref: %@ (%d)", storyViewPref, self.isRiverView);
|
2015-03-10 18:58:23 -07:00
|
|
|
if (storyViewPref) {
|
|
|
|
return storyViewPref;
|
|
|
|
} else {
|
|
|
|
return @"story";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-12 20:09:37 -08:00
|
|
|
- (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"]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-10 18:58:23 -07:00
|
|
|
- (NSString *)storyViewKey {
|
|
|
|
if (self.isRiverView) {
|
|
|
|
return [NSString stringWithFormat:@"folder:%@:story_view", self.activeFolder];
|
|
|
|
} else {
|
|
|
|
return [NSString stringWithFormat:@"%@:story_view", [self.activeFeed objectForKey:@"id"]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-12 20:09:37 -08:00
|
|
|
|
|
|
|
#pragma mark - Story Management
|
|
|
|
|
|
|
|
- (void)addStories:(NSArray *)stories {
|
|
|
|
self.activeFeedStories = [self.activeFeedStories arrayByAddingObjectsFromArray:stories];
|
2014-03-21 16:23:51 -07:00
|
|
|
self.storyCount = (int)[self.activeFeedStories count];
|
2014-02-12 20:09:37 -08:00
|
|
|
[self calculateStoryLocations];
|
2014-03-21 16:23:51 -07:00
|
|
|
self.storyLocationsCount = (int)[self.activeFeedStoryLocations count];
|
2014-02-12 20:09:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setStories:(NSArray *)activeFeedStoriesValue {
|
|
|
|
self.activeFeedStories = activeFeedStoriesValue;
|
2014-03-21 16:23:51 -07:00
|
|
|
self.storyCount = (int)[self.activeFeedStories count];
|
2014-02-12 20:09:37 -08:00
|
|
|
appDelegate.recentlyReadFeeds = [NSMutableSet set];
|
|
|
|
[self calculateStoryLocations];
|
2014-03-21 16:23:51 -07:00
|
|
|
self.storyLocationsCount = (int)[self.activeFeedStoryLocations count];
|
2014-02-12 20:09:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (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-03-05 14:13:49 -08:00
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark Story Actions - read on server
|
|
|
|
|
|
|
|
- (void)syncStoryAsRead:(NSDictionary *)story {
|
|
|
|
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_story_hashes_as_read",
|
|
|
|
NEWSBLUR_URL];
|
|
|
|
NSURL *url = [NSURL URLWithString:urlString];
|
|
|
|
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
|
|
|
|
|
|
|
|
[request setPostValue:[story objectForKey:@"story_hash"]
|
|
|
|
forKey:@"story_hash"];
|
|
|
|
|
|
|
|
[request setDidFinishSelector:@selector(finishMarkAsRead:)];
|
|
|
|
[request setDidFailSelector:@selector(failedMarkAsRead:)];
|
|
|
|
[request setDelegate:self];
|
|
|
|
[request setUserInfo:story];
|
|
|
|
[request startAsynchronous];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)finishMarkAsRead:(ASIFormDataRequest *)request {
|
|
|
|
if ([request responseStatusCode] != 200) {
|
|
|
|
return [self failedMarkAsRead:request];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)failedMarkAsRead:(ASIFormDataRequest *)request {
|
|
|
|
NSString *storyFeedId = [request.userInfo objectForKey:@"story_feed_id"];
|
|
|
|
NSString *storyHash = [request.userInfo objectForKey:@"story_hash"];
|
|
|
|
|
|
|
|
[appDelegate queueReadStories:@{storyFeedId: @[storyHash]}];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)syncStoryAsUnread:(NSDictionary *)story {
|
|
|
|
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_story_as_unread",
|
|
|
|
NEWSBLUR_URL];
|
|
|
|
NSURL *url = [NSURL URLWithString:urlString];
|
|
|
|
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
|
|
|
|
|
|
|
|
[request setPostValue:[story objectForKey:@"story_hash"]
|
|
|
|
forKey:@"story_id"];
|
|
|
|
[request setPostValue:[story objectForKey:@"story_feed_id"]
|
|
|
|
forKey:@"feed_id"];
|
|
|
|
|
|
|
|
[request setDidFinishSelector:@selector(finishMarkAsUnread:)];
|
|
|
|
[request setDidFailSelector:@selector(failedMarkAsUnread:)];
|
|
|
|
[request setDelegate:self];
|
|
|
|
[request setUserInfo:story];
|
|
|
|
[request startAsynchronous];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)finishMarkAsUnread:(ASIFormDataRequest *)request {
|
|
|
|
NSString *responseString = [request responseString];
|
|
|
|
NSData *responseData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
|
|
|
|
NSError *error;
|
|
|
|
NSDictionary *results = [NSJSONSerialization
|
|
|
|
JSONObjectWithData:responseData
|
|
|
|
options:kNilOptions
|
|
|
|
error:&error];
|
|
|
|
|
|
|
|
if ([request responseStatusCode] != 200 || [[results objectForKey:@"code"] integerValue] < 0) {
|
|
|
|
return [self failedMarkAsUnread:request];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)failedMarkAsUnread:(ASIFormDataRequest *)request {
|
|
|
|
NSString *storyFeedId = [request.userInfo objectForKey:@"story_feed_id"];
|
|
|
|
NSString *storyHash = [request.userInfo objectForKey:@"story_hash"];
|
|
|
|
|
2014-03-05 21:31:53 -08:00
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
|
|
|
|
(unsigned long)NULL), ^(void) {
|
|
|
|
BOOL dequeued = [appDelegate dequeueReadStoryHash:storyHash inFeed:storyFeedId];
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
if (!dequeued) {
|
|
|
|
// Offline means can't unread a story unless it was read while offline.
|
|
|
|
[self markStoryRead:storyHash feedId:storyFeedId];
|
|
|
|
// [self.storyTitlesTable reloadData];
|
|
|
|
[appDelegate failedMarkAsUnread:request];
|
|
|
|
} else {
|
|
|
|
// Offline but read story while offline, so it never touched the server.
|
|
|
|
[appDelegate.unreadStoryHashes setObject:[NSNumber numberWithBool:YES] forKey:storyHash];
|
|
|
|
// [self.storyTitlesTable reloadData];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2014-03-05 14:13:49 -08:00
|
|
|
}
|
|
|
|
|
2014-02-20 18:40:58 -08:00
|
|
|
#pragma mark - Story Actions
|
2014-02-20 18:23:58 -08:00
|
|
|
|
2014-03-05 14:13:49 -08:00
|
|
|
- (void)toggleStoryUnread {
|
|
|
|
[self toggleStoryUnread:appDelegate.activeStory];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)toggleStoryUnread:(NSDictionary *)story {
|
|
|
|
BOOL isUnread = [self isStoryUnread:story];
|
|
|
|
if (!isUnread) {
|
|
|
|
[self markStoryUnread:story];
|
|
|
|
[self syncStoryAsUnread:story];
|
|
|
|
} else {
|
|
|
|
[self markStoryRead:story];
|
|
|
|
[self syncStoryAsRead:story];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)markStoryRead:(NSDictionary *)story {
|
|
|
|
[self markStoryRead:[story objectForKey:@"story_hash"] feedId:[story objectForKey:@"story_feed_id"]];
|
|
|
|
}
|
|
|
|
|
2014-02-20 18:23:58 -08:00
|
|
|
- (void)markStoryRead:(NSString *)storyId feedId:(id)feedId {
|
|
|
|
NSString *feedIdStr = [NSString stringWithFormat:@"%@",feedId];
|
|
|
|
NSDictionary *feed = [appDelegate getFeed:feedIdStr];
|
|
|
|
NSDictionary *story = nil;
|
|
|
|
for (NSDictionary *s in self.activeFeedStories) {
|
|
|
|
if ([[s objectForKey:@"story_hash"] isEqualToString:storyId]) {
|
|
|
|
story = s;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[self markStoryRead:story feed:feed];
|
2014-05-16 16:30:52 -07:00
|
|
|
|
|
|
|
NSArray *otherFriendShares = [story objectForKey:@"shared_by_friends"];
|
|
|
|
if ([otherFriendShares count]) {
|
|
|
|
NSLog(@"Shared by friends: %@", otherFriendShares);
|
|
|
|
}
|
|
|
|
|
|
|
|
// decrement all other friend feeds if they have the same story
|
|
|
|
if (![feedIdStr hasPrefix:@"social:"]) {
|
|
|
|
for (int i = 0; i < otherFriendShares.count; i++) {
|
|
|
|
feedIdStr = [NSString stringWithFormat:@"social:%@",
|
|
|
|
[otherFriendShares objectAtIndex:i]];
|
|
|
|
NSDictionary *feed = [appDelegate getFeed:feedIdStr];
|
|
|
|
[self markStoryRead:story feed:feed];
|
|
|
|
}
|
|
|
|
}
|
2014-02-20 18:23:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)markStoryRead:(NSDictionary *)story feed:(NSDictionary *)feed {
|
2014-05-16 16:30:52 -07:00
|
|
|
NSString *feedIdStr;
|
|
|
|
if (feed) {
|
|
|
|
feedIdStr = [NSString stringWithFormat:@"%@", [feed objectForKey:@"id"]];
|
|
|
|
} else {
|
2014-02-20 18:23:58 -08:00
|
|
|
feedIdStr = @"0";
|
|
|
|
}
|
|
|
|
|
|
|
|
NSMutableDictionary *newStory = [story mutableCopy];
|
|
|
|
[newStory setValue:[NSNumber numberWithInt:1] forKey:@"read_status"];
|
|
|
|
|
2014-03-05 15:20:31 -08:00
|
|
|
if ([[appDelegate.activeStory objectForKey:@"story_hash"]
|
|
|
|
isEqualToString:[newStory objectForKey:@"story_hash"]]) {
|
|
|
|
appDelegate.activeStory = newStory;
|
|
|
|
}
|
|
|
|
|
2014-02-20 18:23:58 -08:00
|
|
|
// make the story as read in self.activeFeedStories
|
|
|
|
NSString *newStoryIdStr = [NSString stringWithFormat:@"%@", [newStory valueForKey:@"story_hash"]];
|
2014-11-10 18:25:31 -08:00
|
|
|
[self replaceStory:newStory withId:newStoryIdStr];
|
|
|
|
|
2014-02-20 18:23:58 -08:00
|
|
|
|
2014-03-10 13:56:49 -07:00
|
|
|
// If not a feed, then don't bother updating local feed
|
2014-02-20 18:23:58 -08:00
|
|
|
if (!feed) return;
|
|
|
|
|
|
|
|
self.visibleUnreadCount -= 1;
|
|
|
|
if (![appDelegate.recentlyReadFeeds containsObject:[newStory objectForKey:@"story_feed_id"]]) {
|
|
|
|
[appDelegate.recentlyReadFeeds addObject:[newStory objectForKey:@"story_feed_id"]];
|
|
|
|
}
|
|
|
|
|
|
|
|
NSDictionary *unreadCounts = [appDelegate.dictUnreadCounts objectForKey:feedIdStr];
|
2014-03-10 13:56:49 -07:00
|
|
|
if (!unreadCounts) return; // Not subscribed
|
2014-02-20 18:23:58 -08:00
|
|
|
NSMutableDictionary *newUnreadCounts = [unreadCounts mutableCopy];
|
|
|
|
NSInteger score = [NewsBlurAppDelegate computeStoryScore:[story objectForKey:@"intelligence"]];
|
|
|
|
if (score > 0) {
|
|
|
|
int unreads = MAX(0, [[newUnreadCounts objectForKey:@"ps"] intValue] - 1);
|
|
|
|
[newUnreadCounts setValue:[NSNumber numberWithInt:unreads] forKey:@"ps"];
|
|
|
|
} else if (score == 0) {
|
|
|
|
int unreads = MAX(0, [[newUnreadCounts objectForKey:@"nt"] intValue] - 1);
|
|
|
|
[newUnreadCounts setValue:[NSNumber numberWithInt:unreads] forKey:@"nt"];
|
|
|
|
} else if (score < 0) {
|
|
|
|
int unreads = MAX(0, [[newUnreadCounts objectForKey:@"ng"] intValue] - 1);
|
|
|
|
[newUnreadCounts setValue:[NSNumber numberWithInt:unreads] forKey:@"ng"];
|
|
|
|
}
|
|
|
|
[appDelegate.dictUnreadCounts setObject:newUnreadCounts forKey:feedIdStr];
|
|
|
|
|
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
|
|
|
|
(unsigned long)NULL), ^(void) {
|
|
|
|
[appDelegate.database inTransaction:^(FMDatabase *db, BOOL *rollback) {
|
|
|
|
NSString *storyHash = [newStory objectForKey:@"story_hash"];
|
|
|
|
[db executeUpdate:@"UPDATE stories SET story_json = ? WHERE story_hash = ?",
|
|
|
|
[newStory JSONRepresentation],
|
|
|
|
storyHash];
|
|
|
|
[db executeUpdate:@"DELETE FROM unread_hashes WHERE story_hash = ?",
|
|
|
|
storyHash];
|
|
|
|
[db executeUpdate:@"UPDATE unread_counts SET ps = ?, nt = ?, ng = ? WHERE feed_id = ?",
|
|
|
|
[newUnreadCounts objectForKey:@"ps"],
|
|
|
|
[newUnreadCounts objectForKey:@"nt"],
|
|
|
|
[newUnreadCounts objectForKey:@"ng"],
|
|
|
|
feedIdStr];
|
|
|
|
}];
|
|
|
|
});
|
|
|
|
|
|
|
|
[appDelegate.recentlyReadStories setObject:[NSNumber numberWithBool:YES]
|
|
|
|
forKey:[story objectForKey:@"story_hash"]];
|
|
|
|
[appDelegate.unreadStoryHashes removeObjectForKey:[story objectForKey:@"story_hash"]];
|
2014-03-05 14:13:49 -08:00
|
|
|
[appDelegate finishMarkAsRead:story];
|
|
|
|
}
|
|
|
|
|
2014-11-10 18:25:31 -08:00
|
|
|
- (void)replaceStory:(NSDictionary *)newStory withId:(NSString *)newStoryIdStr {
|
|
|
|
NSMutableArray *newActiveFeedStories = [self.activeFeedStories mutableCopy];
|
|
|
|
for (int i = 0; i < [newActiveFeedStories count]; i++) {
|
|
|
|
NSMutableArray *thisStory = [[newActiveFeedStories objectAtIndex:i] mutableCopy];
|
|
|
|
NSString *thisStoryIdStr = [NSString stringWithFormat:@"%@", [thisStory valueForKey:@"story_hash"]];
|
|
|
|
if ([newStoryIdStr isEqualToString:thisStoryIdStr]) {
|
|
|
|
[newActiveFeedStories replaceObjectAtIndex:i withObject:newStory];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.activeFeedStories = newActiveFeedStories;
|
|
|
|
}
|
|
|
|
|
2014-03-05 14:13:49 -08:00
|
|
|
- (void)markStoryUnread:(NSDictionary *)story {
|
|
|
|
[self markStoryUnread:[story objectForKey:@"story_hash"]
|
|
|
|
feedId:[story objectForKey:@"story_feed_id"]];
|
2014-02-20 18:23:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)markStoryUnread:(NSString *)storyId feedId:(id)feedId {
|
|
|
|
NSString *feedIdStr = [NSString stringWithFormat:@"%@",feedId];
|
|
|
|
NSDictionary *feed = [appDelegate getFeed:feedIdStr];
|
|
|
|
NSDictionary *story = nil;
|
|
|
|
for (NSDictionary *s in self.activeFeedStories) {
|
|
|
|
if ([[s objectForKey:@"story_hash"] isEqualToString:storyId]) {
|
|
|
|
story = s;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[self markStoryUnread:story feed:feed];
|
2014-05-16 16:30:52 -07:00
|
|
|
|
|
|
|
NSArray *otherFriendShares = [story objectForKey:@"shared_by_friends"];
|
|
|
|
if ([otherFriendShares count]) {
|
|
|
|
NSLog(@"Shared by friends: %@", otherFriendShares);
|
|
|
|
}
|
|
|
|
|
|
|
|
// decrement all other friend feeds if they have the same story
|
|
|
|
if (![feedIdStr hasPrefix:@"social:"]) {
|
|
|
|
for (int i = 0; i < otherFriendShares.count; i++) {
|
|
|
|
feedIdStr = [NSString stringWithFormat:@"social:%@",
|
|
|
|
[otherFriendShares objectAtIndex:i]];
|
|
|
|
NSDictionary *feed = [appDelegate getFeed:feedIdStr];
|
|
|
|
[self markStoryUnread:story feed:feed];
|
|
|
|
}
|
|
|
|
}
|
2014-02-20 18:23:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)markStoryUnread:(NSDictionary *)story feed:(NSDictionary *)feed {
|
|
|
|
NSString *feedIdStr = [NSString stringWithFormat:@"%@", [feed objectForKey:@"id"]];
|
|
|
|
if (!feed) {
|
|
|
|
feedIdStr = @"0";
|
|
|
|
}
|
2014-03-05 14:13:49 -08:00
|
|
|
|
2014-02-20 18:23:58 -08:00
|
|
|
NSMutableDictionary *newStory = [story mutableCopy];
|
|
|
|
[newStory setValue:[NSNumber numberWithInt:0] forKey:@"read_status"];
|
|
|
|
|
2014-03-05 15:20:31 -08:00
|
|
|
if ([[appDelegate.activeStory objectForKey:@"story_hash"]
|
|
|
|
isEqualToString:[newStory objectForKey:@"story_hash"]]) {
|
|
|
|
appDelegate.activeStory = newStory;
|
|
|
|
}
|
|
|
|
|
2014-02-20 18:23:58 -08:00
|
|
|
// make the story as read in self.activeFeedStories
|
|
|
|
NSString *newStoryIdStr = [NSString stringWithFormat:@"%@", [newStory valueForKey:@"story_hash"]];
|
2014-11-10 18:25:31 -08:00
|
|
|
[self replaceStory:newStory withId:newStoryIdStr];
|
2014-03-05 15:20:31 -08:00
|
|
|
|
2014-02-20 18:23:58 -08:00
|
|
|
// If not a feed, then don't bother updating local feed.
|
|
|
|
if (!feed) return;
|
|
|
|
|
|
|
|
self.visibleUnreadCount += 1;
|
|
|
|
// if ([self.recentlyReadFeeds containsObject:[newStory objectForKey:@"story_feed_id"]]) {
|
|
|
|
[appDelegate.recentlyReadFeeds removeObject:[newStory objectForKey:@"story_feed_id"]];
|
|
|
|
// }
|
|
|
|
|
|
|
|
NSDictionary *unreadCounts = [appDelegate.dictUnreadCounts objectForKey:feedIdStr];
|
|
|
|
NSMutableDictionary *newUnreadCounts = [unreadCounts mutableCopy];
|
|
|
|
NSInteger score = [NewsBlurAppDelegate computeStoryScore:[story objectForKey:@"intelligence"]];
|
|
|
|
if (score > 0) {
|
|
|
|
int unreads = MAX(0, [[newUnreadCounts objectForKey:@"ps"] intValue] + 1);
|
|
|
|
[newUnreadCounts setValue:[NSNumber numberWithInt:unreads] forKey:@"ps"];
|
|
|
|
} else if (score == 0) {
|
|
|
|
int unreads = MAX(0, [[newUnreadCounts objectForKey:@"nt"] intValue] + 1);
|
|
|
|
[newUnreadCounts setValue:[NSNumber numberWithInt:unreads] forKey:@"nt"];
|
|
|
|
} else if (score < 0) {
|
|
|
|
int unreads = MAX(0, [[newUnreadCounts objectForKey:@"ng"] intValue] + 1);
|
|
|
|
[newUnreadCounts setValue:[NSNumber numberWithInt:unreads] forKey:@"ng"];
|
|
|
|
}
|
2014-03-04 18:09:43 -08:00
|
|
|
if (!newUnreadCounts) return;
|
2014-02-20 18:23:58 -08:00
|
|
|
[appDelegate.dictUnreadCounts setObject:newUnreadCounts forKey:feedIdStr];
|
|
|
|
|
2014-03-05 21:31:53 -08:00
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
|
|
|
|
(unsigned long)NULL), ^(void) {
|
|
|
|
[appDelegate.database inTransaction:^(FMDatabase *db, BOOL *rollback) {
|
|
|
|
NSString *storyHash = [newStory objectForKey:@"story_hash"];
|
|
|
|
[db executeUpdate:@"UPDATE stories SET story_json = ? WHERE story_hash = ?",
|
|
|
|
[newStory JSONRepresentation],
|
|
|
|
storyHash];
|
|
|
|
[db executeUpdate:@"INSERT INTO unread_hashes "
|
|
|
|
"(story_hash, story_feed_id, story_timestamp) VALUES (?, ?, ?)",
|
|
|
|
storyHash, feedIdStr, [newStory objectForKey:@"story_timestamp"]];
|
|
|
|
[db executeUpdate:@"UPDATE unread_counts SET ps = ?, nt = ?, ng = ? WHERE feed_id = ?",
|
|
|
|
[newUnreadCounts objectForKey:@"ps"],
|
|
|
|
[newUnreadCounts objectForKey:@"nt"],
|
|
|
|
[newUnreadCounts objectForKey:@"ng"],
|
|
|
|
feedIdStr];
|
|
|
|
}];
|
|
|
|
});
|
2014-02-20 18:23:58 -08:00
|
|
|
|
|
|
|
[appDelegate.recentlyReadStories removeObjectForKey:[story objectForKey:@"story_hash"]];
|
2014-03-05 14:13:49 -08:00
|
|
|
[appDelegate finishMarkAsUnread:story];
|
2014-02-20 18:23:58 -08:00
|
|
|
}
|
|
|
|
|
2014-03-05 14:13:49 -08:00
|
|
|
#pragma mark - Saved Stories
|
|
|
|
|
|
|
|
- (void)toggleStorySaved {
|
|
|
|
[self toggleStorySaved:appDelegate.activeStory];
|
|
|
|
}
|
|
|
|
|
2014-12-16 15:36:58 -08:00
|
|
|
- (BOOL)toggleStorySaved:(NSDictionary *)story {
|
2014-03-05 14:13:49 -08:00
|
|
|
BOOL isSaved = [[story objectForKey:@"starred"] boolValue];
|
2014-11-04 17:53:27 -08:00
|
|
|
|
2014-03-05 14:13:49 -08:00
|
|
|
if (isSaved) {
|
2014-11-04 17:53:27 -08:00
|
|
|
story = [self markStory:story asSaved:NO];
|
2014-03-05 14:13:49 -08:00
|
|
|
[self syncStoryAsUnsaved:story];
|
|
|
|
} else {
|
2014-11-04 17:53:27 -08:00
|
|
|
story = [self markStory:story asSaved:YES];
|
2014-03-05 14:13:49 -08:00
|
|
|
[self syncStoryAsSaved:story];
|
|
|
|
}
|
2014-12-16 15:36:58 -08:00
|
|
|
|
|
|
|
return !isSaved;
|
2014-03-05 14:13:49 -08:00
|
|
|
}
|
|
|
|
|
2014-11-04 17:53:27 -08:00
|
|
|
- (NSDictionary *)markStory:(NSDictionary *)story asSaved:(BOOL)saved {
|
2014-12-16 15:36:58 -08:00
|
|
|
BOOL firstSaved = NO;
|
2014-11-10 18:25:31 -08:00
|
|
|
NSMutableDictionary *newStory = [story mutableCopy];
|
2015-10-22 10:10:26 -07:00
|
|
|
BOOL isSaved = [[story objectForKey:@"starred"] boolValue];
|
|
|
|
if (isSaved == saved) {
|
|
|
|
return newStory;
|
|
|
|
}
|
2014-02-20 18:40:58 -08:00
|
|
|
[newStory setValue:[NSNumber numberWithBool:saved] forKey:@"starred"];
|
2014-11-10 18:25:31 -08:00
|
|
|
if (saved && ![newStory objectForKey:@"starred_date"]) {
|
2014-11-04 17:53:27 -08:00
|
|
|
[newStory setObject:[Utilities formatLongDateFromTimestamp:nil] forKey:@"starred_date"];
|
2014-11-11 17:21:36 -08:00
|
|
|
appDelegate.savedStoriesCount += 1;
|
2014-12-16 15:36:58 -08:00
|
|
|
firstSaved = YES;
|
2014-11-10 18:25:31 -08:00
|
|
|
} else if (!saved) {
|
2014-02-20 18:40:58 -08:00
|
|
|
[newStory removeObjectForKey:@"starred_date"];
|
2014-11-11 17:21:36 -08:00
|
|
|
appDelegate.savedStoriesCount -= 1;
|
2014-02-20 18:40:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ([[newStory objectForKey:@"story_hash"]
|
|
|
|
isEqualToString:[appDelegate.activeStory objectForKey:@"story_hash"]]) {
|
|
|
|
appDelegate.activeStory = newStory;
|
|
|
|
}
|
|
|
|
|
2014-11-04 17:53:27 -08:00
|
|
|
// Add folder tags if no user tags
|
|
|
|
if (![story objectForKey:@"user_tags"]) {
|
|
|
|
NSArray *parentFolders = [appDelegate parentFoldersForFeed:[story objectForKey:@"story_feed_id"]];
|
|
|
|
NSLog(@"Saving in folders: %@", parentFolders);
|
|
|
|
[newStory setObject:parentFolders forKey:@"user_tags"];
|
|
|
|
}
|
2014-12-16 15:36:58 -08:00
|
|
|
|
|
|
|
// Fake increased count on saved tags if saving for the first time,
|
|
|
|
// will be recounted when save request returns
|
|
|
|
if (firstSaved) {
|
|
|
|
for (NSString *userTag in [newStory objectForKey:@"user_tags"]) {
|
|
|
|
[appDelegate adjustSavedStoryCount:userTag direction:(saved ? 1 : -1)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-20 18:40:58 -08:00
|
|
|
// make the story as read in self.activeFeedStories
|
|
|
|
NSString *newStoryIdStr = [NSString stringWithFormat:@"%@", [newStory valueForKey:@"story_hash"]];
|
2014-11-10 18:25:31 -08:00
|
|
|
[self replaceStory:newStory withId:newStoryIdStr];
|
2014-02-20 18:40:58 -08:00
|
|
|
|
2014-11-04 17:53:27 -08:00
|
|
|
return newStory;
|
2014-02-20 18:40:58 -08:00
|
|
|
}
|
|
|
|
|
2014-03-05 14:13:49 -08:00
|
|
|
- (void)syncStoryAsSaved:(NSDictionary *)story {
|
|
|
|
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_story_as_starred",
|
|
|
|
NEWSBLUR_URL];
|
|
|
|
NSURL *url = [NSURL URLWithString:urlString];
|
|
|
|
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
|
|
|
|
|
2014-11-04 17:53:27 -08:00
|
|
|
[request setPostValue:[story objectForKey:@"story_hash"]
|
2014-03-05 14:13:49 -08:00
|
|
|
forKey:@"story_id"];
|
2014-11-04 17:53:27 -08:00
|
|
|
[request setPostValue:[story objectForKey:@"story_feed_id"]
|
2014-03-05 14:13:49 -08:00
|
|
|
forKey:@"feed_id"];
|
2014-11-04 17:53:27 -08:00
|
|
|
for (NSString *userTag in [story objectForKey:@"user_tags"]) {
|
|
|
|
[request addPostValue:userTag
|
|
|
|
forKey:@"user_tags"];
|
|
|
|
}
|
2014-03-05 14:13:49 -08:00
|
|
|
|
|
|
|
[request setDidFinishSelector:@selector(finishMarkAsSaved:)];
|
|
|
|
[request setDidFailSelector:@selector(requestFailed:)];
|
|
|
|
[request setUserInfo:@{@"story_feed_id":[story
|
|
|
|
objectForKey:@"story_feed_id"],
|
|
|
|
@"story_hash":[story
|
|
|
|
objectForKey:@"story_hash"]}];
|
|
|
|
[request setDelegate:self];
|
|
|
|
[request startAsynchronous];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)finishMarkAsSaved:(ASIFormDataRequest *)request {
|
|
|
|
if ([request responseStatusCode] != 200) {
|
|
|
|
return [self failedMarkAsSaved:request];
|
|
|
|
}
|
2014-11-04 17:53:27 -08:00
|
|
|
|
|
|
|
[self updateSavedStoryCounts:request];
|
|
|
|
|
2014-03-05 14:13:49 -08:00
|
|
|
[appDelegate finishMarkAsSaved:request];
|
|
|
|
}
|
|
|
|
|
2014-11-04 17:53:27 -08:00
|
|
|
- (void)updateSavedStoryCounts:(ASIFormDataRequest *)request {
|
|
|
|
NSString *responseString = [request responseString];
|
|
|
|
NSData *responseData=[responseString dataUsingEncoding:NSUTF8StringEncoding];
|
|
|
|
NSError *error;
|
|
|
|
NSDictionary *results = [NSJSONSerialization
|
|
|
|
JSONObjectWithData:responseData
|
|
|
|
options:kNilOptions
|
|
|
|
error:&error];
|
|
|
|
NSArray *savedStories = [appDelegate updateStarredStoryCounts:results];
|
|
|
|
NSMutableDictionary *allFolders = [appDelegate.dictFolders mutableCopy];
|
|
|
|
[allFolders setValue:savedStories forKey:@"saved_stories"];
|
|
|
|
appDelegate.dictFolders = allFolders;
|
|
|
|
}
|
|
|
|
|
2014-03-05 14:13:49 -08:00
|
|
|
- (void)failedMarkAsSaved:(ASIFormDataRequest *)request {
|
2014-03-05 15:42:53 -08:00
|
|
|
[self markStory:request.userInfo asSaved:NO];
|
2014-03-05 14:13:49 -08:00
|
|
|
|
|
|
|
[appDelegate failedMarkAsSaved:request];
|
|
|
|
}
|
|
|
|
|
2014-05-16 16:30:52 -07:00
|
|
|
- (void)syncStoryAsUnsaved:(NSDictionary *)story {
|
2014-03-05 14:13:49 -08:00
|
|
|
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_story_as_unstarred",
|
|
|
|
NEWSBLUR_URL];
|
|
|
|
NSURL *url = [NSURL URLWithString:urlString];
|
|
|
|
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
|
|
|
|
|
|
|
|
[request setPostValue:[story
|
|
|
|
objectForKey:@"story_hash"]
|
|
|
|
forKey:@"story_id"];
|
|
|
|
[request setPostValue:[story
|
|
|
|
objectForKey:@"story_feed_id"]
|
|
|
|
forKey:@"feed_id"];
|
|
|
|
|
|
|
|
[request setDidFinishSelector:@selector(finishMarkAsUnsaved:)];
|
|
|
|
[request setDidFailSelector:@selector(requestFailed:)];
|
|
|
|
[request setUserInfo:@{@"story_feed_id":[story
|
|
|
|
objectForKey:@"story_feed_id"],
|
|
|
|
@"story_hash":[story
|
|
|
|
objectForKey:@"story_hash"]}];
|
|
|
|
[request setDelegate:self];
|
|
|
|
[request startAsynchronous];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)finishMarkAsUnsaved:(ASIFormDataRequest *)request {
|
|
|
|
if ([request responseStatusCode] != 200) {
|
|
|
|
return [self failedMarkAsUnsaved:request];
|
|
|
|
}
|
|
|
|
|
2014-11-04 17:53:27 -08:00
|
|
|
[self updateSavedStoryCounts:request];
|
2014-03-05 14:13:49 -08:00
|
|
|
[appDelegate finishMarkAsUnsaved:request];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)failedMarkAsUnsaved:(ASIFormDataRequest *)request {
|
2014-03-05 15:42:53 -08:00
|
|
|
[self markStory:request.userInfo asSaved:YES];
|
2014-03-05 14:13:49 -08:00
|
|
|
[appDelegate failedMarkAsUnsaved:request];
|
|
|
|
}
|
2014-02-20 18:40:58 -08:00
|
|
|
|
2014-02-12 16:39:30 -08:00
|
|
|
@end
|