mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-31 21:41:33 +00:00
Adding NSURLCache layer for caching of offline images. No more rewriting of image URLs. Thanks to @zacwest for the push on this.
This commit is contained in:
parent
de7a84e5a2
commit
aaf6ea042e
7 changed files with 132 additions and 24 deletions
|
@ -55,11 +55,12 @@
|
||||||
#import "NSString+HTML.h"
|
#import "NSString+HTML.h"
|
||||||
#import "UIView+ViewController.h"
|
#import "UIView+ViewController.h"
|
||||||
#import "UIViewController+OSKUtilities.h"
|
#import "UIViewController+OSKUtilities.h"
|
||||||
|
#import "NBURLCache.h"
|
||||||
#import <float.h>
|
#import <float.h>
|
||||||
|
|
||||||
@implementation NewsBlurAppDelegate
|
@implementation NewsBlurAppDelegate
|
||||||
|
|
||||||
#define CURRENT_DB_VERSION 31
|
#define CURRENT_DB_VERSION 32
|
||||||
|
|
||||||
@synthesize window;
|
@synthesize window;
|
||||||
|
|
||||||
|
@ -209,7 +210,11 @@
|
||||||
|
|
||||||
cachedFavicons = [[TMCache alloc] initWithName:@"NBFavicons"];
|
cachedFavicons = [[TMCache alloc] initWithName:@"NBFavicons"];
|
||||||
cachedStoryImages = [[TMCache alloc] initWithName:@"NBStoryImages"];
|
cachedStoryImages = [[TMCache alloc] initWithName:@"NBStoryImages"];
|
||||||
|
|
||||||
|
NBURLCache *urlCache = [[NBURLCache alloc] init];
|
||||||
|
[NSURLCache setSharedURLCache:urlCache];
|
||||||
|
[[NSURLCache sharedURLCache] removeAllCachedResponses];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -279,6 +279,8 @@
|
||||||
{
|
{
|
||||||
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
|
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
|
||||||
|
|
||||||
|
// if (error.code == 102 && [error.domain isEqual:@"WebKitErrorDomain"]) { }
|
||||||
|
|
||||||
// User clicking on another link before the page loads is OK.
|
// User clicking on another link before the page loads is OK.
|
||||||
if ([error code] != NSURLErrorCancelled) {
|
if ([error code] != NSURLErrorCancelled) {
|
||||||
[self informError:error];
|
[self informError:error];
|
||||||
|
@ -293,18 +295,25 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)loadAddress:(id)sender {
|
- (IBAction)loadAddress:(id)sender {
|
||||||
if (!activeUrl) {
|
activeUrl = [appDelegate.activeOriginalStoryURL absoluteString];
|
||||||
activeUrl = [appDelegate.activeOriginalStoryURL absoluteString];
|
|
||||||
}
|
|
||||||
NSString* urlString = activeUrl;
|
NSString* urlString = activeUrl;
|
||||||
NSURL* url = [NSURL URLWithString:urlString];
|
NSURL* url = [NSURL URLWithString:urlString];
|
||||||
|
// if ([urlString containsString:@"story_images"]) {
|
||||||
|
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||||
|
// NSString *storyImagesDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"story_images"];
|
||||||
|
//
|
||||||
|
// urlString = [urlString substringFromIndex:NSMaxRange([urlString
|
||||||
|
// rangeOfString:@"story_images/"])];
|
||||||
|
// NSString *path = [storyImagesDirectory stringByAppendingPathComponent:urlString];
|
||||||
|
// url = [NSURL fileURLWithPath:path];
|
||||||
|
// }
|
||||||
if (!url.scheme) {
|
if (!url.scheme) {
|
||||||
NSString* modifiedURLString = [NSString stringWithFormat:@"%@", urlString];
|
NSString* modifiedURLString = [NSString stringWithFormat:@"%@", urlString];
|
||||||
url = [NSURL URLWithString:modifiedURLString];
|
url = [NSURL URLWithString:modifiedURLString];
|
||||||
}
|
}
|
||||||
if ([self.webView isLoading]) {
|
// if ([self.webView isLoading]) {
|
||||||
[self.webView stopLoading];
|
// [self.webView stopLoading];
|
||||||
}
|
// }
|
||||||
NSURLRequest* request = [NSURLRequest requestWithURL:url];
|
NSURLRequest* request = [NSURLRequest requestWithURL:url];
|
||||||
[self.webView loadRequest:request];
|
[self.webView loadRequest:request];
|
||||||
titleView.text = @"Loading...";
|
titleView.text = @"Loading...";
|
||||||
|
|
|
@ -272,20 +272,20 @@
|
||||||
contentWidthClass, (int)floorf(CGRectGetWidth(self.view.frame))];
|
contentWidthClass, (int)floorf(CGRectGetWidth(self.view.frame))];
|
||||||
|
|
||||||
// Replace image urls that are locally cached, even when online
|
// Replace image urls that are locally cached, even when online
|
||||||
NSString *storyHash = [self.activeStory objectForKey:@"story_hash"];
|
// NSString *storyHash = [self.activeStory objectForKey:@"story_hash"];
|
||||||
NSArray *imageUrls = [appDelegate.activeCachedImages objectForKey:storyHash];
|
// NSArray *imageUrls = [appDelegate.activeCachedImages objectForKey:storyHash];
|
||||||
if (imageUrls) {
|
// if (imageUrls) {
|
||||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||||
NSString *storyImagesDirectory = [[paths objectAtIndex:0]
|
// NSString *storyImagesDirectory = [[paths objectAtIndex:0]
|
||||||
stringByAppendingPathComponent:@"story_images"];
|
// stringByAppendingPathComponent:@"story_images"];
|
||||||
for (NSString *imageUrl in imageUrls) {
|
// for (NSString *imageUrl in imageUrls) {
|
||||||
NSString *cachedImage = [storyImagesDirectory
|
// NSString *cachedImage = [storyImagesDirectory
|
||||||
stringByAppendingPathComponent:[Utilities md5:imageUrl]];
|
// stringByAppendingPathComponent:[Utilities md5:imageUrl]];
|
||||||
storyContent = [storyContent
|
// storyContent = [storyContent
|
||||||
stringByReplacingOccurrencesOfString:imageUrl
|
// stringByReplacingOccurrencesOfString:imageUrl
|
||||||
withString:cachedImage];
|
// withString:cachedImage];
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
NSString *riverClass = (appDelegate.storiesCollection.isRiverView ||
|
NSString *riverClass = (appDelegate.storiesCollection.isRiverView ||
|
||||||
appDelegate.storiesCollection.isSocialView ||
|
appDelegate.storiesCollection.isSocialView ||
|
||||||
|
@ -1552,7 +1552,8 @@ shouldStartLoadWithRequest:(NSURLRequest *)request
|
||||||
actionSheetViewImageIndex = [actions addButtonWithTitle:@"View and zoom"];
|
actionSheetViewImageIndex = [actions addButtonWithTitle:@"View and zoom"];
|
||||||
actionSheetCopyImageIndex = [actions addButtonWithTitle:@"Copy image"];
|
actionSheetCopyImageIndex = [actions addButtonWithTitle:@"Copy image"];
|
||||||
actionSheetSaveImageIndex = [actions addButtonWithTitle:@"Save to camera roll"];
|
actionSheetSaveImageIndex = [actions addButtonWithTitle:@"Save to camera roll"];
|
||||||
[actions showFromRect:CGRectMake(pt.x, pt.y, 1, 1) inView:appDelegate.storyPageControl.view animated:YES];
|
[actions showFromRect:CGRectMake(pt.x, pt.y, 1, 1)
|
||||||
|
inView:appDelegate.storyPageControl.view animated:YES];
|
||||||
// [actions showInView:appDelegate.storyPageControl.view];
|
// [actions showInView:appDelegate.storyPageControl.view];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,7 @@
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||||
NSString *cacheDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"story_images"];
|
NSString *cacheDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"story_images"];
|
||||||
NSString *fullPath = [cacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@", md5Url]];
|
NSString *fullPath = [cacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", md5Url, [[[request originalURL] absoluteString] pathExtension]]];
|
||||||
|
|
||||||
[fileManager createFileAtPath:fullPath contents:responseData attributes:nil];
|
[fileManager createFileAtPath:fullPath contents:responseData attributes:nil];
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -675,6 +675,7 @@
|
||||||
FFF1E4CB17750D2C00BF59D3 /* menu_icn_preferences.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C917750D2C00BF59D3 /* menu_icn_preferences.png */; };
|
FFF1E4CB17750D2C00BF59D3 /* menu_icn_preferences.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C917750D2C00BF59D3 /* menu_icn_preferences.png */; };
|
||||||
FFF1E4CC17750D2C00BF59D3 /* menu_icn_preferences@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4CA17750D2C00BF59D3 /* menu_icn_preferences@2x.png */; };
|
FFF1E4CC17750D2C00BF59D3 /* menu_icn_preferences@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4CA17750D2C00BF59D3 /* menu_icn_preferences@2x.png */; };
|
||||||
FFFC608517165A1D00DC22E2 /* THCircularProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFC60831716578E00DC22E2 /* THCircularProgressView.m */; };
|
FFFC608517165A1D00DC22E2 /* THCircularProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFC60831716578E00DC22E2 /* THCircularProgressView.m */; };
|
||||||
|
FFFF683D19D628000081904A /* NBURLCache.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFF683C19D628000081904A /* NBURLCache.m */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
@ -1623,6 +1624,8 @@
|
||||||
FFF1E4CA17750D2C00BF59D3 /* menu_icn_preferences@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icn_preferences@2x.png"; sourceTree = "<group>"; };
|
FFF1E4CA17750D2C00BF59D3 /* menu_icn_preferences@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icn_preferences@2x.png"; sourceTree = "<group>"; };
|
||||||
FFFC60821716578E00DC22E2 /* THCircularProgressView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THCircularProgressView.h; sourceTree = "<group>"; };
|
FFFC60821716578E00DC22E2 /* THCircularProgressView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THCircularProgressView.h; sourceTree = "<group>"; };
|
||||||
FFFC60831716578E00DC22E2 /* THCircularProgressView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THCircularProgressView.m; sourceTree = "<group>"; };
|
FFFC60831716578E00DC22E2 /* THCircularProgressView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THCircularProgressView.m; sourceTree = "<group>"; };
|
||||||
|
FFFF683B19D628000081904A /* NBURLCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NBURLCache.h; path = "Other Sources/NBURLCache.h"; sourceTree = "<group>"; };
|
||||||
|
FFFF683C19D628000081904A /* NBURLCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NBURLCache.m; path = "Other Sources/NBURLCache.m"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -1742,6 +1745,8 @@
|
||||||
FF1F13D718AAC97900FDA816 /* UIImage+Resize.m */,
|
FF1F13D718AAC97900FDA816 /* UIImage+Resize.m */,
|
||||||
FFA0483F19CA5F5B00618DC4 /* UIWebView+Offsets.h */,
|
FFA0483F19CA5F5B00618DC4 /* UIWebView+Offsets.h */,
|
||||||
FFA0484019CA5F5B00618DC4 /* UIWebView+Offsets.m */,
|
FFA0484019CA5F5B00618DC4 /* UIWebView+Offsets.m */,
|
||||||
|
FFFF683B19D628000081904A /* NBURLCache.h */,
|
||||||
|
FFFF683C19D628000081904A /* NBURLCache.m */,
|
||||||
);
|
);
|
||||||
name = "Other Sources";
|
name = "Other Sources";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -3498,6 +3503,7 @@
|
||||||
1D3623260D0F684500981E51 /* NewsBlurAppDelegate.m in Sources */,
|
1D3623260D0F684500981E51 /* NewsBlurAppDelegate.m in Sources */,
|
||||||
FFA047DA19CA54A800618DC4 /* NSMutableURLRequest+OSKUtilities.m in Sources */,
|
FFA047DA19CA54A800618DC4 /* NSMutableURLRequest+OSKUtilities.m in Sources */,
|
||||||
28D7ACF80DDB3853001CB0EB /* NewsBlurViewController.m in Sources */,
|
28D7ACF80DDB3853001CB0EB /* NewsBlurViewController.m in Sources */,
|
||||||
|
FFFF683D19D628000081904A /* NBURLCache.m in Sources */,
|
||||||
FFA0481619CA54A800618DC4 /* OSKPagedHorizontalLayout.m in Sources */,
|
FFA0481619CA54A800618DC4 /* OSKPagedHorizontalLayout.m in Sources */,
|
||||||
78FC34F711CA94900055C312 /* NSObject+SBJSON.m in Sources */,
|
78FC34F711CA94900055C312 /* NSObject+SBJSON.m in Sources */,
|
||||||
FFA0482119CA54A800618DC4 /* OSKSaveToCameraRollActivity.m in Sources */,
|
FFA0482119CA54A800618DC4 /* OSKSaveToCameraRollActivity.m in Sources */,
|
||||||
|
|
15
clients/ios/Other Sources/NBURLCache.h
Normal file
15
clients/ios/Other Sources/NBURLCache.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// NBURLCache.h
|
||||||
|
// NewsBlur
|
||||||
|
//
|
||||||
|
// Created by Samuel Clay on 9/26/14.
|
||||||
|
// Copyright (c) 2014 NewsBlur. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface NBURLCache : NSURLCache {
|
||||||
|
NSMutableDictionary *cachedResponses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
72
clients/ios/Other Sources/NBURLCache.m
Normal file
72
clients/ios/Other Sources/NBURLCache.m
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
//
|
||||||
|
// NBURLCache.m
|
||||||
|
// NewsBlur
|
||||||
|
//
|
||||||
|
// Created by Samuel Clay on 9/26/14.
|
||||||
|
// Copyright (c) 2014 NewsBlur. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NBURLCache.h"
|
||||||
|
#import "Utilities.h"
|
||||||
|
|
||||||
|
@implementation NBURLCache
|
||||||
|
|
||||||
|
- (NSString *)substitutePath:(NSString *)pathString {
|
||||||
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||||
|
NSString *storyImagesDirectory = [[paths objectAtIndex:0]
|
||||||
|
stringByAppendingPathComponent:@"story_images"];
|
||||||
|
NSString *cachedImage = [[storyImagesDirectory
|
||||||
|
stringByAppendingPathComponent:[Utilities md5:pathString]] stringByAppendingPathExtension:[pathString pathExtension]];
|
||||||
|
return cachedImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
|
||||||
|
{
|
||||||
|
// Get the path for the request
|
||||||
|
NSString *pathString = [[request URL] absoluteString];
|
||||||
|
|
||||||
|
// See if we have a substitution file for this path
|
||||||
|
NSString *substitutionFileName = [self substitutePath:pathString];
|
||||||
|
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:substitutionFileName];
|
||||||
|
if (!substitutionFileName || !exists)
|
||||||
|
{
|
||||||
|
NSLog(@"No cache found: %@ / %@", pathString, substitutionFileName);
|
||||||
|
// No substitution file, return the default cache response
|
||||||
|
return [super cachedResponseForRequest:request];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've already created a cache entry for this path, then return it.
|
||||||
|
NSCachedURLResponse *cachedResponse = [cachedResponses objectForKey:pathString];
|
||||||
|
if (cachedResponse)
|
||||||
|
{
|
||||||
|
NSLog(@"Memory cached: %@", pathString);
|
||||||
|
// return cachedResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the path to the substitution file
|
||||||
|
NSString *substitutionFilePath = substitutionFileName;
|
||||||
|
|
||||||
|
// Load the data
|
||||||
|
NSData *data = [NSData dataWithContentsOfFile:substitutionFilePath];
|
||||||
|
|
||||||
|
// Create the cacheable response
|
||||||
|
NSURLResponse *response = [[NSURLResponse alloc]
|
||||||
|
initWithURL:[request URL]
|
||||||
|
MIMEType:nil
|
||||||
|
expectedContentLength:[data length]
|
||||||
|
textEncodingName:nil];
|
||||||
|
cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response
|
||||||
|
data:data];
|
||||||
|
|
||||||
|
NSLog(@"Got cached response: %@ / %@", pathString, substitutionFileName);
|
||||||
|
// Add it to our cache dictionary for subsequent responses
|
||||||
|
if (!cachedResponses)
|
||||||
|
{
|
||||||
|
cachedResponses = [[NSMutableDictionary alloc] init];
|
||||||
|
}
|
||||||
|
[cachedResponses setObject:cachedResponse forKey:pathString];
|
||||||
|
|
||||||
|
return cachedResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
Loading…
Add table
Reference in a new issue