Fjalapeno has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/223194

Change subject: Creating Fetcher to encapsulate async article fetching logic
......................................................................

Creating Fetcher to encapsulate async article fetching logic

T104590

Created WMFArticleFetcher
New fetcher wraps ArticleFetcher and adds promise API
Refactored WebVC to use new WMFArticleFetcher
Refactored saved pages fetcher to handle Article Fetcher API changes

Added new NSError for redirects

Removed some reliance of the Article Fetcher on the session singleton (but not 
all)
Removed Article Fetcher code that assumes "singleton" status of the article 
fetcher

Removed "titleToTempDirThumbURLMap" from session singleton (images are expected 
to be saved in the datastore)
Removed nearby code that did the above and filed a ticket to re-add

Changed article fetcher API to separate initialization from fetching
Changed article fetcher to accept titles (instead of articles)

Change-Id: I7b5200f791bd4485cedab88b98344204531bb16a
---
M NSError+WMFExtensions.h
M NSError+WMFExtensions.m
M 
Pods/Pods.xcodeproj/xcshareddata/xcschemes/Pods-WikipediaUnitTests-SDWebImage.xcscheme
M Wikipedia.xcodeproj/project.pbxproj
M Wikipedia/Networking/Fetchers/ArticleFetcher.h
M Wikipedia/Networking/Fetchers/ArticleFetcher.m
M Wikipedia/Networking/Fetchers/NearbyFetcher.m
M Wikipedia/Networking/Fetchers/SavedArticlesFetcher.m
M Wikipedia/Networking/Fetchers/SearchResultFetcher.h
M Wikipedia/Networking/Fetchers/SearchResultFetcher.m
M Wikipedia/Session/SessionSingleton.h
M Wikipedia/Session/SessionSingleton.m
A Wikipedia/UI-V5/WMFArticleFetcher.h
A Wikipedia/UI-V5/WMFArticleFetcher.m
M Wikipedia/UI-V5/WMFArticleViewController.m
M Wikipedia/View Controllers/WebView/WebViewController.m
M Wikipedia/View Controllers/WebView/WebViewController_Private.h
17 files changed, 307 insertions(+), 266 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/apps/ios/wikipedia 
refs/changes/94/223194/1

diff --git a/NSError+WMFExtensions.h b/NSError+WMFExtensions.h
index ca8f88c..974f2b3 100644
--- a/NSError+WMFExtensions.h
+++ b/NSError+WMFExtensions.h
@@ -1,16 +1,30 @@
 
 #import <Foundation/Foundation.h>
 
+@class MWKTitle;
+
 extern NSString* const WMFErrorDomain;
+extern NSString* const WMFRedirectTitleKey;
 
 typedef NS_ENUM(NSInteger, WMFErrorType) {
     
     WMFErrorTypeStringLength,
     WMFErrorTypeStringMissingParameter,
+    WMFErrorTypeRedirected,
+
 };
 
 @interface NSError (WMFExtensions)
 
 + (NSError*)wmf_errorWithType:(WMFErrorType)type 
userInfo:(NSDictionary*)userInfo;
 
++ (NSError*)wmf_redirectedErrorWithTitle:(MWKTitle*)redirectedtitle;
+
+@end
+
+
+@interface NSDictionary (WMFErrorExtensions)
+
+- (MWKTitle*)wmf_redirectTitle;
+
 @end
diff --git a/NSError+WMFExtensions.m b/NSError+WMFExtensions.m
index 14e11ad..bc8b3e2 100644
--- a/NSError+WMFExtensions.m
+++ b/NSError+WMFExtensions.m
@@ -2,6 +2,7 @@
 #import "NSError+WMFExtensions.h"
 
 NSString* const WMFErrorDomain = @"WMFErrorDomain";
+NSString* const WMFRedirectTitleKey = @"WMFRedirectTitleKey";
 
 @implementation NSError (WMFExtensions)
 
@@ -10,4 +11,20 @@
     return [NSError errorWithDomain:WMFErrorDomain code:type 
userInfo:userInfo];
 }
 
++ (NSError*)wmf_redirectedErrorWithTitle:(MWKTitle*)redirectedTitle{
+
+    return [self wmf_errorWithType:WMFErrorTypeRedirected 
userInfo:redirectedTitle ? @{WMFRedirectTitleKey : redirectedTitle}: nil];
+    
+}
+
+
+@end
+
+
+@implementation NSDictionary (WMFErrorExtensions)
+
+- (MWKTitle*)wmf_redirectTitle{
+    return self[WMFRedirectTitleKey];
+}
+
 @end
diff --git 
a/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Pods-WikipediaUnitTests-SDWebImage.xcscheme
 
b/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Pods-WikipediaUnitTests-SDWebImage.xcscheme
index be30f81..7c517da 100644
--- 
a/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Pods-WikipediaUnitTests-SDWebImage.xcscheme
+++ 
b/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Pods-WikipediaUnitTests-SDWebImage.xcscheme
@@ -14,7 +14,7 @@
             buildForAnalyzing = "YES">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "92F8EB23140D42C02EBABE71"
+               BlueprintIdentifier = "DAA05C73B23753A7EC46363D"
                BuildableName = "libPods-WikipediaUnitTests-SDWebImage.a"
                BlueprintName = "Pods-WikipediaUnitTests-SDWebImage"
                ReferencedContainer = "container:Pods.xcodeproj">
@@ -39,15 +39,6 @@
       ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
       allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "5907BCD658CC44B83B452185"
-            BuildableName = "libPods-WikipediaUnitTests-SDWebImage.a"
-            BlueprintName = "Pods-WikipediaUnitTests-SDWebImage"
-            ReferencedContainer = "container:Pods.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <AdditionalOptions>
       </AdditionalOptions>
    </LaunchAction>
diff --git a/Wikipedia.xcodeproj/project.pbxproj 
b/Wikipedia.xcodeproj/project.pbxproj
index 28a062c..2d01adc 100644
--- a/Wikipedia.xcodeproj/project.pbxproj
+++ b/Wikipedia.xcodeproj/project.pbxproj
@@ -187,6 +187,7 @@
                08D631F71A69B1AB00D87AD0 /* WMFImageGalleryViewController.m in 
Sources */ = {isa = PBXBuildFile; fileRef = 08D631F61A69B1AB00D87AD0 /* 
WMFImageGalleryViewController.m */; };
                0E2B06F61B2CE45800EA2F53 /* WMFSavedPagesDataSource.m in 
Sources */ = {isa = PBXBuildFile; fileRef = 0E2B06F51B2CE45800EA2F53 /* 
WMFSavedPagesDataSource.m */; };
                0E2B07021B2D1DE200EA2F53 /* WMFBottomStackLayout.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = 0E2B07011B2D1DE200EA2F53 /* 
WMFBottomStackLayout.m */; };
+               0E34AC571B45DC9500475A1A /* WMFArticleFetcher.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 0E34AC561B45DC9500475A1A /* WMFArticleFetcher.m 
*/; };
                0E366B361B2F176700ABFB86 /* WMFOffScreenFlowLayout.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = 0E366B351B2F176700ABFB86 /* 
WMFOffScreenFlowLayout.m */; };
                0E366B3A1B2F33BC00ABFB86 /* WMFSearchResults.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 0E366B391B2F33BC00ABFB86 /* WMFSearchResults.m 
*/; };
                0E366B3F1B2F5C4500ABFB86 /* WMFSearchFetcher.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 0E366B3E1B2F5C4500ABFB86 /* WMFSearchFetcher.m 
*/; };
@@ -740,6 +741,8 @@
                0E2B06F51B2CE45800EA2F53 /* WMFSavedPagesDataSource.m */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; 
path = WMFSavedPagesDataSource.m; sourceTree = "<group>"; };
                0E2B07001B2D1DE200EA2F53 /* WMFBottomStackLayout.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WMFBottomStackLayout.h; sourceTree = "<group>"; };
                0E2B07011B2D1DE200EA2F53 /* WMFBottomStackLayout.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= WMFBottomStackLayout.m; sourceTree = "<group>"; };
+               0E34AC551B45DC9500475A1A /* WMFArticleFetcher.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WMFArticleFetcher.h; sourceTree = "<group>"; };
+               0E34AC561B45DC9500475A1A /* WMFArticleFetcher.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= WMFArticleFetcher.m; sourceTree = "<group>"; };
                0E366B341B2F176700ABFB86 /* WMFOffScreenFlowLayout.h */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path 
= WMFOffScreenFlowLayout.h; sourceTree = "<group>"; };
                0E366B351B2F176700ABFB86 /* WMFOffScreenFlowLayout.m */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; 
path = WMFOffScreenFlowLayout.m; sourceTree = "<group>"; };
                0E366B381B2F33BC00ABFB86 /* WMFSearchResults.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WMFSearchResults.h; sourceTree = "<group>"; };
@@ -2190,6 +2193,8 @@
                        children = (
                                0E94AFF41B209882000BC5EA /* 
WMFArticleViewController.h */,
                                0E94AFF51B209882000BC5EA /* 
WMFArticleViewController.m */,
+                               0E34AC551B45DC9500475A1A /* WMFArticleFetcher.h 
*/,
+                               0E34AC561B45DC9500475A1A /* WMFArticleFetcher.m 
*/,
                        );
                        name = Article;
                        sourceTree = "<group>";
@@ -3228,6 +3233,7 @@
                                BCA96E771AAA35EE009A61FA /* 
UIView+WMFDefaultNib.m in Sources */,
                                04414DDB1A140FAF00A41B4E /* 
SearchDidYouMeanButton.m in Sources */,
                                0E94AFFB1B20A22C000BC5EA /* WMFStyleManager.m 
in Sources */,
+                               0E34AC571B45DC9500475A1A /* WMFArticleFetcher.m 
in Sources */,
                                040D83591AB0ECFD000896D5 /* 
WMFCenteredPathView.m in Sources */,
                                BCB669B41A83F6C400C7B1FE /* MWKArticle.m in 
Sources */,
                                0E2B06F61B2CE45800EA2F53 /* 
WMFSavedPagesDataSource.m in Sources */,
diff --git a/Wikipedia/Networking/Fetchers/ArticleFetcher.h 
b/Wikipedia/Networking/Fetchers/ArticleFetcher.h
index 941a4ef..1cf372d 100644
--- a/Wikipedia/Networking/Fetchers/ArticleFetcher.h
+++ b/Wikipedia/Networking/Fetchers/ArticleFetcher.h
@@ -4,7 +4,8 @@
 #import <Foundation/Foundation.h>
 #import "FetcherBase.h"
 
-@class Article, AFHTTPRequestOperationManager, ArticleFetcher, MWKArticle;
+@class AFHTTPRequestOperationManager, ArticleFetcher, AFHTTPRequestOperation, 
MWKTitle;
+
 
 @protocol ArticleFetcherDelegate <FetchFinishedDelegate>
 
@@ -17,12 +18,13 @@
 
 @interface ArticleFetcher : FetcherBase
 
-@property (strong, nonatomic, readonly) MWKArticle* article;
+@property (nonatomic, strong, readonly) MWKDataStore* dataStore;
+@property (nonatomic, strong, readonly) MWKTitle* title;
 
-// Kick-off method. Results are reported to "delegate" via the 
FetchFinishedDelegate protocol method.
-- (instancetype)initAndFetchSectionsForArticle:(MWKArticle*)articleStore
-                                   
withManager:(AFHTTPRequestOperationManager*)manager
-                            
thenNotifyDelegate:(id<ArticleFetcherDelegate>)delegate;
+- (AFHTTPRequestOperation*)fetchSectionsForTitle:(MWKTitle*)title
+                                     inDataStore:(MWKDataStore*)store
+                                     
withManager:(AFHTTPRequestOperationManager*)manager
+                              
thenNotifyDelegate:(id<ArticleFetcherDelegate>)delegate;
 
 @property (nonatomic, weak) id<ArticleFetcherDelegate> fetchFinishedDelegate;
 
diff --git a/Wikipedia/Networking/Fetchers/ArticleFetcher.m 
b/Wikipedia/Networking/Fetchers/ArticleFetcher.m
index 29eed6a..bc03874 100644
--- a/Wikipedia/Networking/Fetchers/ArticleFetcher.m
+++ b/Wikipedia/Networking/Fetchers/ArticleFetcher.m
@@ -4,10 +4,9 @@
 #import "ArticleFetcher.h"
 #import "WMFNetworkUtilities.h"
 #import "Defines.h"
-#import "QueuesSingleton.h"
+#import "SessionSingleton.h"
 #import "NSString+Extras.h"
 #import "AFHTTPRequestOperationManager.h"
-#import "SessionSingleton.h"
 #import "ReadingActionFunnel.h"
 #import "NSString+Extras.h"
 #import "NSObject+Extras.h"
@@ -16,14 +15,19 @@
 #import <CoreTelephony/CTTelephonyNetworkInfo.h>
 #import <SystemConfiguration/SystemConfiguration.h>
 #import "WMFArticleParsing.h"
+#import "ZeroConfigState.h"
 
 // Reminder: For caching reasons, don't do "(scale * 320)" here.
 #define LEAD_IMAGE_WIDTH (([UIScreen mainScreen].scale > 1) ? 640 : 320)
 
 @interface ArticleFetcher ()
 
-// The Article object to be updated with the downloaded data.
-@property (nonatomic, strong) MWKArticle* article;
+@property (nonatomic, strong, readwrite) MWKDataStore* dataStore;
+@property (nonatomic, strong, readwrite) ZeroConfigState* zeroConfig;
+@property (nonatomic, assign, readwrite) BOOL sendUsageReports;
+
+
+@property (nonatomic, strong, readwrite) MWKTitle* title;
 
 @end
 
@@ -31,47 +35,33 @@
 
 @dynamic fetchFinishedDelegate;
 
-- (instancetype)initAndFetchSectionsForArticle:(MWKArticle*)article
-                                   
withManager:(AFHTTPRequestOperationManager*)manager
-                            thenNotifyDelegate:(id<ArticleFetcherDelegate> 
)delegate {
-    self = [super init];
-    assert(article != nil);
+- (AFHTTPRequestOperation*)fetchSectionsForTitle:(MWKTitle*)title
+                                     inDataStore:(MWKDataStore*)store
+                                     
withManager:(AFHTTPRequestOperationManager*)manager
+                              thenNotifyDelegate:(id<ArticleFetcherDelegate> 
)delegate {
+    assert(title != nil);
+    assert(store != nil);
     assert(manager != nil);
     assert(delegate != nil);
-    if (self) {
-        self.article               = article;
-        self.fetchFinishedDelegate = delegate;
-        [self fetchWithManager:manager];
-    }
-    return self;
+    self.title                 = title;
+    self.dataStore             = store;
+    self.fetchFinishedDelegate = delegate;
+    return [self fetchWithManager:manager];
 }
 
-- (void)fetchWithManager:(AFHTTPRequestOperationManager*)manager {
-    NSString* title     = self.article.title.text;
-    NSString* subdomain = self.article.title.site.language;
-
-    if (!self.article) {
-        NSLog(@"NO ARTICLE OBJECT");
-        return;
+- 
(AFHTTPRequestOperation*)fetchWithManager:(AFHTTPRequestOperationManager*)manager
 {
+    if (!self.title.text) {
+        return nil;
     }
-    if (!self.fetchFinishedDelegate) {
-        NSLog(@"NO DOWNLOAD DELEGATE");
-        return;
-    }
-    if (!subdomain) {
-        NSLog(@"NO DOMAIN");
-        return;
-    }
-    if (!title) {
-        NSLog(@"NO TITLE");
-        return;
+    if (!self.title.site.language) {
+        return nil;
     }
 
-    NSURL* url = [[SessionSingleton sharedInstance] urlForLanguage:subdomain];
+    NSURL* url = [[SessionSingleton sharedInstance] 
urlForLanguage:self.title.site.language];
 
     // First retrieve lead section data, then get the remaining sections data.
 
-    NSDictionary* params = [self getParamsForTitle:title];
+    NSDictionary* params = [self getParamsForTitle:self.title];
 
     [[MWNetworkActivityIndicatorManager sharedManager] push];
 
@@ -85,15 +75,13 @@
             //NSLog(@"JSON: %@", responseObject);
             [[MWNetworkActivityIndicatorManager sharedManager] pop];
 
+            MWKArticle* article = [self.dataStore articleWithTitle:self.title];
             // Convert the raw NSData response to a dictionary.
             NSDictionary* responseDictionary = [self 
dictionaryFromDataResponse:localResponseObject];
 
-            // Clear any MCCMNC header - needed because manager is a singleton.
-            [self 
removeMCCMNCHeaderFromRequestSerializer:manager.requestSerializer];
-
             @try {
-                [self.article 
importMobileViewJSON:responseDictionary[@"mobileview"]];
-                [self.article save];
+                [article 
importMobileViewJSON:responseDictionary[@"mobileview"]];
+                [article save];
             }@catch (NSException* e) {
                 NSLog(@"%@", e);
                 NSError* err = [NSError errorWithDomain:@"ArticleFetcher" 
code:666 userInfo:@{ @"exception": e }];
@@ -101,28 +89,23 @@
                 return;
             }
 
-            for (int section = 0; section < [self.article.sections count]; 
section++) {
-                (void)self.article.sections[section].images;             // 
hack
-                WMFInjectArticleWithImagesFromSection(self.article, 
self.article.sections[section].text, section);
+            for (int section = 0; section < [article.sections count]; 
section++) {
+                (void)article.sections[section].images;             // hack
+                WMFInjectArticleWithImagesFromSection(article, 
article.sections[section].text, section);
             }
-
-            [self associateThumbFromTempDirWithArticle];
 
             // Update article and section image data.
             // Reminder: don't recall article save here as it expensively 
re-writes all section html.
-            [self.article saveWithoutSavingSectionText];
+            [article saveWithoutSavingSectionText];
 
             dispatch_async(dispatch_get_main_queue(), ^{
                 [self finishWithError:nil
-                          fetchedData:self.article];
+                          fetchedData:article];
             });
         });
     } failure:^(AFHTTPRequestOperation* operation, NSError* error) {
         NSLog(@"Error: %@", error);
         [[MWNetworkActivityIndicatorManager sharedManager] pop];
-
-        // Clear any MCCMNC header - needed because manager is a singleton.
-        [self 
removeMCCMNCHeaderFromRequestSerializer:manager.requestSerializer];
 
         [self finishWithError:error
                   fetchedData:nil];
@@ -141,9 +124,11 @@
             [self.fetchFinishedDelegate articleFetcher:self 
didUpdateProgress:progress];
         }
     }];
+
+    return operation;
 }
 
-- (NSDictionary*)getParamsForTitle:(NSString*)title {
+- (NSDictionary*)getParamsForTitle:(MWKTitle*)title {
     NSMutableDictionary* params = @{
         @"format": @"json",
         @"action": @"mobileview",
@@ -151,7 +136,7 @@
                                                       @"fromtitle", @"index"]),
         @"noheadings": @"true",
         @"sections": @"all",
-        @"page": title,
+        @"page": title.text,
         @"thumbwidth": @(LEAD_IMAGE_WIDTH),
         @"prop": WMFJoinedPropertyParameters(@[@"sections", @"text", 
@"lastmodified", @"lastmodifiedby",
                                                @"languagecount", @"id", 
@"protection", @"editable", @"displaytitle",
@@ -177,6 +162,8 @@
         ||
         ([url.relativePath rangeOfString:@"/w/api.php"].location == NSNotFound)
         ) {
+        [requestSerializer setValue:nil forHTTPHeaderField:@"X-MCCMNC"];
+
         return;
     } else {
         CTCarrier* mno = [[[CTTelephonyNetworkInfo alloc] init] 
subscriberCellularProvider];
@@ -207,63 +194,6 @@
                 [SessionSingleton sharedInstance].zeroConfigState.sentMCCMNC = 
true;
 
                 [requestSerializer setValue:mccMnc 
forHTTPHeaderField:@"X-MCCMNC"];
-
-                // NSLog(@"%@", mccMnc);
-            }
-        }
-    }
-}
-
-- 
(void)removeMCCMNCHeaderFromRequestSerializer:(AFHTTPRequestSerializer*)requestSerializer
 {
-    [requestSerializer setValue:nil forHTTPHeaderField:@"X-MCCMNC"];
-}
-
-- (void)associateThumbFromTempDirWithArticle {
-    BOOL foundThumbInTempDir = NO;
-
-    // Map which search and nearby populates with title/thumb url mappings.
-    NSDictionary* map = [SessionSingleton 
sharedInstance].titleToTempDirThumbURLMap;
-    NSString* title   = self.article.title.text;
-    if (title) {
-        NSString* thumbURL = map[title];
-        if (thumbURL) {
-            // Associate Search/Nearby thumb url with article.thumbnailURL.
-            if (thumbURL) {
-                self.article.thumbnailURL = thumbURL;
-            }
-
-            if ([[self.article existingImageWithURL:thumbURL] isDownloaded]) {
-                return;
-            }
-
-            NSString* cacheFilePath = 
[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)
-                                        firstObject]
-                                       
stringByAppendingPathComponent:thumbURL.lastPathComponent];
-            BOOL isDirectory      = NO;
-            BOOL cachedFileExists = [[NSFileManager defaultManager] 
fileExistsAtPath:cacheFilePath
-                                                                         
isDirectory:&isDirectory];
-            if (cachedFileExists) {
-                NSError* error = nil;
-                NSData* data   = [NSData dataWithContentsOfFile:cacheFilePath 
options:0 error:&error];
-                if (!error) {
-                    // Copy Search/Nearby thumb binary to core data store so 
it doesn't have to be re-downloaded.
-                    MWKImage* image = [self.article importImageURL:thumbURL 
sectionId:kMWKArticleSectionNone];
-                    [self.article importImageData:data image:image];
-                    foundThumbInTempDir = YES;
-                }
-            }
-        }
-    }
-    if (!foundThumbInTempDir) {
-        MWKImageList* images = self.article.images;
-        // If no image found in temp dir, use first article image.
-        if (images.count > 0) {
-            MWKImage* image = images[0];
-            self.article.thumbnailURL = image.sourceURL;
-        } else {
-            // If still no image, use article image if there is one.
-            if (self.article.imageURL) {
-                self.article.thumbnailURL = self.article.imageURL;
             }
         }
     }
diff --git a/Wikipedia/Networking/Fetchers/NearbyFetcher.m 
b/Wikipedia/Networking/Fetchers/NearbyFetcher.m
index 668c5eb..a4c0e27 100644
--- a/Wikipedia/Networking/Fetchers/NearbyFetcher.m
+++ b/Wikipedia/Networking/Fetchers/NearbyFetcher.m
@@ -67,18 +67,6 @@
         NSMutableArray* output = @[].mutableCopy;
         if (!error) {
             output = [self getSanitizedResponse:responseObject];
-
-            // Populate the map so the article fetcher can grab thumb
-            // from temp dir.
-            NSMutableDictionary* map = [SessionSingleton 
sharedInstance].titleToTempDirThumbURLMap;
-            [map removeAllObjects];
-            for (NSDictionary* result in output) {
-                NSString* title = result[@"title"];
-                NSString* thumbUrl = result[@"thumbnail"][@"source"];
-                if (title && thumbUrl) {
-                    map[title] = thumbUrl;
-                }
-            }
         }
 
         if (output.count == 0) {
diff --git a/Wikipedia/Networking/Fetchers/SavedArticlesFetcher.m 
b/Wikipedia/Networking/Fetchers/SavedArticlesFetcher.m
index def23de..69110ee 100644
--- a/Wikipedia/Networking/Fetchers/SavedArticlesFetcher.m
+++ b/Wikipedia/Networking/Fetchers/SavedArticlesFetcher.m
@@ -62,10 +62,10 @@
         self.fetchedArticles = [NSMutableArray array];
 
         for (MWKSavedPageEntry* entry in self.savedPageList) {
-            MWKArticle* article = [self.dataStore 
articleWithTitle:entry.title];
-
             if (entry.title) {
-                self.fetchersByArticleTitle[entry.title] = [[ArticleFetcher 
alloc] initAndFetchSectionsForArticle:article withManager:manager 
thenNotifyDelegate:self];
+                ArticleFetcher* fetcher = [[ArticleFetcher alloc] init];
+                self.fetchersByArticleTitle[entry.title] = fetcher;
+                [fetcher fetchSectionsForTitle:entry.title 
inDataStore:self.dataStore withManager:manager thenNotifyDelegate:self];
             }
         }
     });
diff --git a/Wikipedia/Networking/Fetchers/SearchResultFetcher.h 
b/Wikipedia/Networking/Fetchers/SearchResultFetcher.h
index 70450e1..53f978d 100644
--- a/Wikipedia/Networking/Fetchers/SearchResultFetcher.h
+++ b/Wikipedia/Networking/Fetchers/SearchResultFetcher.h
@@ -4,7 +4,9 @@
 #import <Foundation/Foundation.h>
 #import "FetcherBase.h"
 #import "Defines.h"
-#import <AFNetworking/AFHTTPRequestOperation.h>
+
+@class AFHTTPRequestOperationManager;
+@class AFHTTPRequestOperation;
 
 typedef NS_ENUM (NSInteger, SearchResultFetcherErrorType) {
     SEARCH_RESULT_ERROR_UNKNOWN    = 0,
@@ -26,8 +28,6 @@
     SEARCH_REASON_SUPPLEMENT_PREFIX_WITH_FULL_TEXT
 };
 
-@class AFHTTPRequestOperationManager;
-
 @interface SearchResultFetcher : FetcherBase
 
 @property (nonatomic, strong, readonly) NSString* searchTerm;
@@ -37,7 +37,6 @@
 @property (nonatomic, strong, readonly) NSArray* searchResults;
 @property (nonatomic, strong, readonly) NSString* searchSuggestion;
 
-@property (nonatomic, strong, readonly) NSDictionary* articleTitleToImageMap;
 
 // Kick-off method. Results are reported to "delegate" via the 
FetchFinishedDelegate protocol method.
 - (instancetype)initAndSearchForTerm:(NSString*)searchTerm
diff --git a/Wikipedia/Networking/Fetchers/SearchResultFetcher.m 
b/Wikipedia/Networking/Fetchers/SearchResultFetcher.m
index 833ec0e..676bd99 100644
--- a/Wikipedia/Networking/Fetchers/SearchResultFetcher.m
+++ b/Wikipedia/Networking/Fetchers/SearchResultFetcher.m
@@ -2,7 +2,8 @@
 //  Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
 
 #import "SearchResultFetcher.h"
-#import "AFHTTPRequestOperationManager.h"
+#import <AFNetworking/AFHTTPRequestOperation.h>
+#import <AFNetworking/AFHTTPRequestOperationManager.h>
 #import "MWNetworkActivityIndicatorManager.h"
 #import "SessionSingleton.h"
 #import "NSObject+Extras.h"
diff --git a/Wikipedia/Session/SessionSingleton.h 
b/Wikipedia/Session/SessionSingleton.h
index aa86bb7..5674f2b 100644
--- a/Wikipedia/Session/SessionSingleton.h
+++ b/Wikipedia/Session/SessionSingleton.h
@@ -78,11 +78,4 @@
 
 - (NSURL*)urlForLanguage:(NSString*)language __deprecated_msg("Use -[MWKSite 
apiEndpoint] instead.");
 
-// Search and Nearby fetch thumbnails which are tossed in the tmp dir so we
-// don't have to worry about pruning. However, when we then load an article
-// we need to yank out the thumb for that article so it can be saved in the
-// data store. This dictionary gives us an easy place to see what temp thumb
-// file is known to be associated with an article title.
-@property (strong, nonatomic) NSMutableDictionary* titleToTempDirThumbURLMap;
-
 @end
diff --git a/Wikipedia/Session/SessionSingleton.m 
b/Wikipedia/Session/SessionSingleton.m
index db06fa8..386d589 100644
--- a/Wikipedia/Session/SessionSingleton.m
+++ b/Wikipedia/Session/SessionSingleton.m
@@ -59,8 +59,6 @@
         self.userDataStore = [dataStore userDataStore];
 
         _currentArticleSite = [self lastKnownSite];
-
-        self.titleToTempDirThumbURLMap = @{}.mutableCopy;
     }
     return self;
 }
diff --git a/Wikipedia/UI-V5/WMFArticleFetcher.h 
b/Wikipedia/UI-V5/WMFArticleFetcher.h
new file mode 100644
index 0000000..869489d
--- /dev/null
+++ b/Wikipedia/UI-V5/WMFArticleFetcher.h
@@ -0,0 +1,23 @@
+
+#import <Foundation/Foundation.h>
+
+@class MWKSite;
+@class MWKTitle;
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef void (^ WMFArticleFetcherProgress)(CGFloat progress);
+
+@interface WMFArticleFetcher : NSObject
+
+@property (nonatomic, strong, readonly) MWKDataStore* dataStore;
+
+- (instancetype)initWithDataStore:(MWKDataStore*)dataStore;
+
+- (AnyPromise*)fetchArticleForPageTitle:(MWKTitle*)pageTitle 
progress:(WMFArticleFetcherProgress)progress;
+
+- (void)cancelCurrentFetch;
+
+@end
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file
diff --git a/Wikipedia/UI-V5/WMFArticleFetcher.m 
b/Wikipedia/UI-V5/WMFArticleFetcher.m
new file mode 100644
index 0000000..113b40d
--- /dev/null
+++ b/Wikipedia/UI-V5/WMFArticleFetcher.m
@@ -0,0 +1,105 @@
+
+#import "WMFArticleFetcher.h"
+#import "AFHTTPRequestOperationManager+WMFConfig.h"
+#import "ArticleFetcher.h"
+#import "Wikipedia-Swift.h"
+#import "PromiseKit.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WMFArticleFetcher ()<ArticleFetcherDelegate>
+
+@property (nonatomic, strong, readwrite) MWKDataStore* dataStore;
+
+@property (nonatomic, strong) AFHTTPRequestOperationManager* operationManager;
+
+@property (nonatomic, strong) ArticleFetcher* fetcher;
+
+@property (nonatomic, strong, nullable) AFHTTPRequestOperation* operation;
+@property (nonatomic, copy, nullable) WMFArticleFetcherProgress progressBlock;
+@property (nonatomic, copy, nullable) PMKResolver resolver;
+
+@end
+
+@implementation WMFArticleFetcher
+
+- (instancetype)initWithDataStore:(MWKDataStore*)dataStore {
+    self = [super init];
+    if (self) {
+        self.dataStore = dataStore;
+        AFHTTPRequestOperationManager* manager = 
[AFHTTPRequestOperationManager wmf_createDefaultManager];
+        manager.responseSerializer = [AFHTTPResponseSerializer serializer];
+        self.operationManager      = manager;
+    }
+    return self;
+}
+
+- (AnyPromise*)fetchArticleForPageTitle:(MWKTitle*)pageTitle 
progress:(WMFArticleFetcherProgress)progress {
+    [self cancelCurrentFetch];
+
+    self.progressBlock = progress;
+
+    return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
+        self.resolver = resolve;
+
+        self.fetcher = [[ArticleFetcher alloc] init];
+        self.operation = [self.fetcher fetchSectionsForTitle:pageTitle 
inDataStore:self.dataStore withManager:self.operationManager 
thenNotifyDelegate:self];
+
+        if (self.operation == nil) {
+            resolve([NSError 
wmf_errorWithType:WMFErrorTypeStringMissingParameter userInfo:nil]);
+            [self reset];
+        }
+    }];
+}
+
+- (void)articleFetcher:(ArticleFetcher*)savedArticlesFetcher
+     didUpdateProgress:(CGFloat)progress {
+    if (!self.progressBlock) {
+        return;
+    }
+
+    dispatchOnMainQueue(^{
+        self.progressBlock(progress);
+    });
+}
+
+- (void)fetchFinished:(id)sender
+          fetchedData:(id)fetchedData
+               status:(FetchFinalStatus)status
+                error:(NSError*)error {
+    if (!self.resolver) {
+        [self reset];
+        return;
+    }
+
+    MWKArticle* article = fetchedData;
+
+    if (!error) {
+        MWKTitle* redirectedTitle = article.redirected;
+        if (redirectedTitle) {
+            error = [NSError wmf_redirectedErrorWithTitle:redirectedTitle];
+        }
+    }
+
+    if (!error) {
+        self.resolver(article);
+    } else {
+        self.resolver(error);
+    }
+    [self reset];
+}
+
+- (void)cancelCurrentFetch {
+    [self.operation cancel];
+    [self reset];
+}
+
+- (void)reset {
+    self.operation     = nil;
+    self.progressBlock = NULL;
+    self.resolver      = nil;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file
diff --git a/Wikipedia/UI-V5/WMFArticleViewController.m 
b/Wikipedia/UI-V5/WMFArticleViewController.m
index 6863bb0..944f325 100644
--- a/Wikipedia/UI-V5/WMFArticleViewController.m
+++ b/Wikipedia/UI-V5/WMFArticleViewController.m
@@ -1,4 +1,3 @@
-
 #import "WMFArticleViewController.h"
 #import <Masonry/Masonry.h>
 #import "Wikipedia-Swift.h"
diff --git a/Wikipedia/View Controllers/WebView/WebViewController.m 
b/Wikipedia/View Controllers/WebView/WebViewController.m
index ba2c546..047aef4 100644
--- a/Wikipedia/View Controllers/WebView/WebViewController.m
+++ b/Wikipedia/View Controllers/WebView/WebViewController.m
@@ -8,6 +8,7 @@
 #import "UIBarButtonItem+WMFButtonConvenience.h"
 #import "RandomArticleFetcher.h"
 #import "MWKSiteInfoFetcher.h"
+#import "WMFArticleFetcher.h"
 #import "MWKSiteInfo.h"
 #import "UIViewController+WMFStoryboardUtilities.h"
 #import "MWKLanguageLink.h"
@@ -43,7 +44,7 @@
 
 @property (nonatomic) BOOL isAnimatingTopAndBottomMenuHidden;
 @property (readonly, strong, nonatomic) MWKSiteInfoFetcher* siteInfoFetcher;
-
+@property (strong, nonatomic) WMFArticleFetcher* articleFetcher;
 @property (strong, nonatomic) UIPopoverController* popover;
 @property (strong, nonatomic) WMFShareFunnel* shareFunnel;
 @property (strong, nonatomic) WMFShareOptionsViewController* 
shareOptionsViewController;
@@ -1180,10 +1181,6 @@
 
 #pragma mark Memory
 
-- (void)didReceiveMemoryWarning {
-    [super didReceiveMemoryWarning];
-}
-
 - (void)updateHistoryDateVisitedForArticleBeingNavigatedFrom {
     // This is a quick hack to help with the natural back/forward behavior of 
the case
     // where you go back and forth from some master article to others.
@@ -1199,24 +1196,12 @@
 
 #pragma mark - Article loading
 
-- (void)navigateToPage:(MWKTitle*)title
-       discoveryMethod:(MWKHistoryDiscoveryMethod)discoveryMethod {
-    NSString* cleanTitle = title.text;
-    NSParameterAssert(cleanTitle.length);
-
-    [self hideKeyboard];
-
-    // Show loading message
-    //[self showAlert:MWLocalizedString(@"search-loading-section-zero", nil) 
type:ALERT_TYPE_TOP duration:-1];
-
-    self.jumpToFragment = title.fragment;
-
-    if (discoveryMethod != MWKHistoryDiscoveryMethodBackForward && 
discoveryMethod != MWKHistoryDiscoveryMethodReloadFromNetwork && 
discoveryMethod != MWKHistoryDiscoveryMethodReloadFromCache) {
-        [self updateHistoryDateVisitedForArticleBeingNavigatedFrom];
+- (WMFArticleFetcher*)articleFetcher {
+    if (!_articleFetcher) {
+        _articleFetcher = [[WMFArticleFetcher alloc] 
initWithDataStore:self.session.dataStore];
     }
 
-    [self retrieveArticleForPageTitle:title
-                      discoveryMethod:discoveryMethod];
+    return _articleFetcher;
 }
 
 - (void)reloadCurrentArticleFromNetwork {
@@ -1236,23 +1221,24 @@
     }
 }
 
-- (void)cancelArticleLoading {
-    [[QueuesSingleton sharedInstance].articleFetchManager.operationQueue 
cancelAllOperations];
-}
+- (void)navigateToPage:(MWKTitle*)title
+       discoveryMethod:(MWKHistoryDiscoveryMethod)discoveryMethod {
+    NSString* cleanTitle = title.text;
+    NSParameterAssert(cleanTitle.length);
 
-- (void)cancelSearchLoading {
-    [[QueuesSingleton sharedInstance].searchResultsFetchManager.operationQueue 
cancelAllOperations];
-}
+    [self hideKeyboard];
 
-- (void)retrieveArticleForPageTitle:(MWKTitle*)pageTitle
-                    discoveryMethod:(MWKHistoryDiscoveryMethod)discoveryMethod 
{
-    // Cancel certain in-progress fetches.
     [self cancelSearchLoading];
     [self cancelArticleLoading];
 
-    self.currentTitle = pageTitle;
+    if (discoveryMethod != MWKHistoryDiscoveryMethodBackForward && 
discoveryMethod != MWKHistoryDiscoveryMethodReloadFromNetwork && 
discoveryMethod != MWKHistoryDiscoveryMethodReloadFromCache) {
+        [self updateHistoryDateVisitedForArticleBeingNavigatedFrom];
+    }
 
     MWKArticle* article = [self.session.dataStore 
articleWithTitle:self.currentTitle];
+
+    self.jumpToFragment                        = title.fragment;
+    self.currentTitle                          = title;
     self.session.currentArticle                = article;
     self.session.currentArticleDiscoveryMethod = discoveryMethod;
 
@@ -1275,100 +1261,74 @@
         }
     }
 
-    // If article is cached
     if ([article isCached] && !needsRefresh) {
         [self displayArticle:self.session.currentArticle.title];
-        //[self showAlert:MWLocalizedString(@"search-loading-article-loaded", 
nil) type:ALERT_TYPE_TOP duration:-1];
         [self fadeAlert];
-    } else {
-        [self showProgressViewAnimated:YES];
-        self.isFetchingArticle = YES;
+        return;
+    }
 
-        // "fetchFinished:" above will be notified when articleFetcher has 
actually retrieved some data.
-        // Note: cast to void to avoid compiler warning: 
http://stackoverflow.com/a/7915839
-        (void)[[ArticleFetcher alloc] 
initAndFetchSectionsForArticle:self.session.currentArticle
-                                                         
withManager:[QueuesSingleton sharedInstance].articleFetchManager
-                                                  thenNotifyDelegate:self];
+    [self loadArticleWithTitleFromNetwork:title];
+}
+
+- (void)cancelArticleLoading {
+    [self.articleFetcher cancelCurrentFetch];
+}
+
+- (void)cancelSearchLoading {
+    [[QueuesSingleton sharedInstance].searchResultsFetchManager.operationQueue 
cancelAllOperations];
+}
+
+- (void)loadArticleWithTitleFromNetwork:(MWKTitle*)title {
+    [self showProgressViewAnimated:YES];
+    self.isFetchingArticle = YES;
+
+    [self.articleFetcher fetchArticleForPageTitle:title progress:^(CGFloat 
progress){
+        [self updateProgress:[self 
totalProgressWithArticleFetcherProgress:progress] animated:YES completion:NULL];
+    }].then(^(MWKArticle* article){
+        [self handleFetchedArticle:article];
+    }).catch(^(NSError* error){
+        [self handleFetchArticleError:error];
+    });
+}
+
+- (void)handleFetchedArticle:(MWKArticle*)article {
+    self.isFetchingArticle = NO;
+
+    [self displayArticle:article.title];
+
+    [self hideAlert];
+}
+
+- (void)handleFetchArticleError:(NSError*)error {
+    MWKTitle* redirect = [[error userInfo] wmf_redirectTitle];
+
+    if (redirect) {
+        [self handleRedirectForTitle:redirect];
+    } else {
+        self.isFetchingArticle = NO;
+
+        [self displayArticle:self.session.currentArticle.title];
+
+        NSString* errorMsg = error.localizedDescription;
+        [self showAlert:errorMsg type:ALERT_TYPE_TOP duration:-1];
     }
 }
 
-- (void)presentPopupForArticle:(MWKArticle*)article {
-    WMFArticleViewController* vc = [WMFArticleViewController 
articleViewControllerFromDefaultStoryBoard];
-    vc.savedPages      = self.session.userDataStore.savedPageList;
-    vc.article         = article;
-    vc.contentTopInset = 64.0;
+- (void)handleRedirectForTitle:(MWKTitle*)title {
+    MWKHistoryEntry* history                  = 
[self.session.userDataStore.historyList entryForTitle:title];
+    MWKHistoryDiscoveryMethod discoveryMethod =
+        (history) ? history.discoveryMethod : MWKHistoryDiscoveryMethodSearch;
 
-    self.popupTransition                        = [[WMFArticlePopupTransition 
alloc] initWithPresentingViewController:self presentedViewController:vc 
contentScrollView:nil];
-    self.popupTransition.nonInteractiveDuration = 0.5;
-    vc.transitioningDelegate                    = self.popupTransition;
-    vc.modalPresentationStyle                   = UIModalPresentationCustom;
-
-    [self presentViewController:vc animated:YES completion:NULL];
+    [self navigateToPage:title discoveryMethod:discoveryMethod];
 }
 
-#pragma mark - ArticleFetcherDelegate
-
-- (void)articleFetcher:(ArticleFetcher*)savedArticlesFetcher
-     didUpdateProgress:(CGFloat)progress {
-    [self updateProgress:[self 
totalProgressWithArticleFetcherProgress:progress] animated:YES completion:NULL];
-}
+#pragma mark - FetchFinishedDelegate
 
 - (void)fetchFinished:(id)sender
           fetchedData:(id)fetchedData
                status:(FetchFinalStatus)status
                 error:(NSError*)error {
-    if ([sender isKindOfClass:[ArticleFetcher class]]) {
-        MWKArticle* article = self.session.currentArticle;
-
-        switch (status) {
-            case FETCH_FINAL_STATUS_SUCCEEDED:
-            {
-                // Redirect if necessary.
-                MWKTitle* redirectedTitle = article.redirected;
-                if (redirectedTitle) {
-                    // Get discovery method for call to 
"retrieveArticleForPageTitle:".
-                    // There should only be a single history item (at most).
-                    MWKHistoryEntry* history = 
[self.session.userDataStore.historyList entryForTitle:article.title];
-                    // Get the article's discovery method.
-                    MWKHistoryDiscoveryMethod discoveryMethod =
-                        (history) ? history.discoveryMethod : 
MWKHistoryDiscoveryMethodSearch;
-
-                    // Redirect!
-                    [self retrieveArticleForPageTitle:redirectedTitle
-                                      discoveryMethod:discoveryMethod];
-                    return;
-                }
-
-                self.isFetchingArticle = NO;
-
-                // Update the toc and web view.
-                [self displayArticle:article.title];
-
-                [self hideAlert];
-            }
-            break;
-
-            case FETCH_FINAL_STATUS_FAILED:
-            {
-                self.isFetchingArticle = NO;
-
-                [self displayArticle:article.title];
-
-                NSString* errorMsg = error.localizedDescription;
-                [self showAlert:errorMsg type:ALERT_TYPE_TOP duration:-1];
-            }
-            break;
-
-            case FETCH_FINAL_STATUS_CANCELLED:
-            {
-                self.isFetchingArticle = NO;
-            }
-            break;
-
-            default:
-                break;
-        }
-    } else if ([sender isKindOfClass:[WikipediaZeroMessageFetcher class]]) {
+    if ([sender isKindOfClass:[WikipediaZeroMessageFetcher class]]) {
         switch (status) {
             case FETCH_FINAL_STATUS_SUCCEEDED:
             {
@@ -1421,6 +1381,22 @@
     }
 }
 
+#pragma mark - Article Popup
+
+- (void)presentPopupForArticle:(MWKArticle*)article {
+    WMFArticleViewController* vc = [WMFArticleViewController 
articleViewControllerFromDefaultStoryBoard];
+    vc.savedPages      = self.session.userDataStore.savedPageList;
+    vc.article         = article;
+    vc.contentTopInset = 64.0;
+
+    self.popupTransition                        = [[WMFArticlePopupTransition 
alloc] initWithPresentingViewController:self presentedViewController:vc 
contentScrollView:nil];
+    self.popupTransition.nonInteractiveDuration = 0.5;
+    vc.transitioningDelegate                    = self.popupTransition;
+    vc.modalPresentationStyle                   = UIModalPresentationCustom;
+
+    [self presentViewController:vc animated:YES completion:NULL];
+}
+
 #pragma mark - Lead image
 
 - (NSString*)leadImageGetHtml {
diff --git a/Wikipedia/View Controllers/WebView/WebViewController_Private.h 
b/Wikipedia/View Controllers/WebView/WebViewController_Private.h
index 431cb65..f87d5b5 100644
--- a/Wikipedia/View Controllers/WebView/WebViewController_Private.h
+++ b/Wikipedia/View Controllers/WebView/WebViewController_Private.h
@@ -42,7 +42,6 @@
 #import "WikiGlyphLabel.h"
 #import "NSString+FormattedAttributedString.h"
 #import "SavedPagesFunnel.h"
-#import "ArticleFetcher.h"
 #import "AssetsFileFetcher.h"
 
 #import "DataMigrationProgressViewController.h"

-- 
To view, visit https://gerrit.wikimedia.org/r/223194
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I7b5200f791bd4485cedab88b98344204531bb16a
Gerrit-PatchSet: 1
Gerrit-Project: apps/ios/wikipedia
Gerrit-Branch: 5.0
Gerrit-Owner: Fjalapeno <cfl...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to