Auto update feeds. Menu rebuild so far only after close.

This commit is contained in:
relikd
2018-10-28 15:25:52 +01:00
parent 5fcaf97fe0
commit 080991ebc4
10 changed files with 357 additions and 49 deletions

View File

@@ -42,8 +42,11 @@ typedef BOOL (^FeedConfigRecursiveItemsBlock) (FeedConfig *parent, FeedItem *ite
@property (getter=typ, setter=setTyp:) FeedConfigType typ;
@property (readonly) NSArray<FeedConfig*> *sortedChildren;
@property (readonly) NSIndexPath *indexPath;
- (BOOL)descendantFeedItems:(FeedConfigRecursiveItemsBlock)block;
- (void)calculateAndSetScheduled;
- (void)mergeChangesAndSave;
- (NSString*)readableRefreshString;
- (NSString*)readableDescription;
@end

View File

@@ -40,6 +40,12 @@
return [self.children sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"sortIndex" ascending:YES]]];
}
- (NSIndexPath *)indexPath {
if (self.parent == nil)
return [NSIndexPath indexPathWithIndex:(NSUInteger)self.sortIndex];
return [self.parent.indexPath indexPathByAddingIndex:(NSUInteger)self.sortIndex];
}
/**
Iterate over all descendant @c FeedItems in sub groups
@@ -61,6 +67,25 @@
return YES;
}
/// @return Time interval respecting the selected unit. E.g., returns @c 180 for @c '3m'
- (NSTimeInterval)timeInterval {
static const int unit[] = {1, 60, 3600, 86400, 604800}; // smhdw
return self.refreshNum * unit[self.refreshUnit % 5];
}
/// Calculate date from @c refreshNum and @c refreshUnit and set as next scheduled feed update.
- (void)calculateAndSetScheduled {
self.scheduled = [[NSDate date] dateByAddingTimeInterval:[self timeInterval]];
}
/// Update item with @c mergeChanges:YES and save the context
- (void)mergeChangesAndSave {
[self.managedObjectContext performBlockAndWait:^{
[self.managedObjectContext refreshObject:self mergeChanges:YES];
[self.managedObjectContext save:nil];
}];
}
/// @return Formatted string for update interval ( e.g., @c 30m or @c 12h )
- (NSString*)readableRefreshString {
return [NSString stringWithFormat:@"%d%c", self.refreshNum, [@"smhdw" characterAtIndex:self.refreshUnit % 5]];

View File

@@ -35,6 +35,8 @@
@property (weak) IBOutlet NSPopover *warningPopover;
@property (copy) NSString *previousURL;
@property (copy) NSString *httpDate;
@property (copy) NSString *httpEtag;
@property (strong) NSError *feedError;
@property (strong) RSParsedFeed *feedResult;
@@ -107,15 +109,19 @@
item.refreshUnit = (int16_t)self.refreshUnit.indexOfSelectedItem;
if (self.shouldDeletePrevArticles) {
[StoreCoordinator overwriteConfig:item withFeed:self.feedResult];
[item.managedObjectContext performBlockAndWait:^{
if (item.feed)
[item.managedObjectContext deleteObject:(NSManagedObject*)item.feed];
if (self.feedResult)
item.feed = [StoreCoordinator createFeedFrom:self.feedResult inContext:item.managedObjectContext];
// TODO: move to separate function and add icon download
if (!item.meta) {
item.meta = [[FeedMeta alloc] initWithEntity:FeedMeta.entity insertIntoManagedObjectContext:item.managedObjectContext];
}
item.meta.httpEtag = self.httpEtag;
item.meta.httpModified = self.httpDate;
}];
}
if ([item.managedObjectContext hasChanges]) {
self.objectIsModified = YES;
[item calculateAndSetScheduled];
[item.managedObjectContext performBlockAndWait:^{
[item.managedObjectContext refreshObject:item mergeChanges:YES];
}];
@@ -146,11 +152,16 @@
self.feedError = nil;
[self.spinnerURL startAnimation:nil];
[self.spinnerName startAnimation:nil];
[FeedDownload getFeed:self.previousURL block:^(RSParsedFeed *result, NSError *error, NSHTTPURLResponse* response) {
[FeedDownload newFeed:self.previousURL block:^(RSParsedFeed *result, NSError *error, NSHTTPURLResponse* response) {
self.feedResult = result;
// [httpResponse allHeaderFields][@"Date"]; // @"Expires", @"Last-Modified"
// [httpResponse allHeaderFields][@"Etag"];
self.httpDate = [response allHeaderFields][@"Date"]; // @"Expires", @"Last-Modified"
self.httpEtag = [response allHeaderFields][@"Etag"];
dispatch_async(dispatch_get_main_queue(), ^{
if (response && ![response.URL.absoluteString isEqualToString:self.url.stringValue]) {
// URL was redirected, so replace original text field value with new one
self.url.stringValue = response.URL.absoluteString;
self.previousURL = self.url.stringValue;
}
// TODO: play error sound?
self.feedError = error; // warning indicator .hidden is bound to feedError
self.objectNeedsSaving = YES; // stays YES if this block runs after updateRepresentedObject: