Fjalapeno has uploaded a new change for review.

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

Change subject: Implementing full text search.
......................................................................

Implementing full text search.

Follow on for Bug: T102362

Updated fetcher for full text search.
Implemented search suggestion button.
Added NSError category for making app specific errors.

Lots of uncrustifucation.

Change-Id: I748da6d9bf6c2bffe733ec49d44d5f057fec5e65
---
M MediaWikiKit/MediaWikiKit/MWKArticle.m
A NSError+WMFExtensions.h
A NSError+WMFExtensions.m
M Wikipedia.xcodeproj/project.pbxproj
M Wikipedia/Networking/Fetchers/SearchResultFetcher.m
M Wikipedia/UI-V5/Global.h
M Wikipedia/UI-V5/TGLStackedViewController/TGLStackedLayout.m
M Wikipedia/UI-V5/UICollectionView+WMFExtensions.h
M Wikipedia/UI-V5/UICollectionView+WMFExtensions.m
M Wikipedia/UI-V5/UIStoryboard+WMFExtensions.m
M Wikipedia/UI-V5/WMFAppViewController.m
M Wikipedia/UI-V5/WMFArticleListCollectionViewController.h
M Wikipedia/UI-V5/WMFArticleListCollectionViewController.m
M Wikipedia/UI-V5/WMFArticleListDataSource.h
M Wikipedia/UI-V5/WMFBottomStackLayout.m
M Wikipedia/UI-V5/WMFOffScreenFlowLayout.m
M Wikipedia/UI-V5/WMFSavedPagesDataSource.m
M Wikipedia/UI-V5/WMFSearchFetcher.h
M Wikipedia/UI-V5/WMFSearchFetcher.m
M Wikipedia/UI-V5/WMFSearchResults.h
M Wikipedia/UI-V5/WMFSearchResults.m
M Wikipedia/UI-V5/WMFSearchViewController.h
M Wikipedia/UI-V5/WMFSearchViewController.m
M Wikipedia/UI-V5/iPhone_Root.storyboard
24 files changed, 358 insertions(+), 348 deletions(-)


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

diff --git a/MediaWikiKit/MediaWikiKit/MWKArticle.m 
b/MediaWikiKit/MediaWikiKit/MWKArticle.m
index b60f71a..9a7dab0 100644
--- a/MediaWikiKit/MediaWikiKit/MWKArticle.m
+++ b/MediaWikiKit/MediaWikiKit/MWKArticle.m
@@ -68,16 +68,15 @@
     return self;
 }
 
-- (instancetype)initWithTitle:(MWKTitle*)title 
dataStore:(MWKDataStore*)dataStore searchResultsDict:(NSDictionary*)dict{
+- (instancetype)initWithTitle:(MWKTitle*)title 
dataStore:(MWKDataStore*)dataStore searchResultsDict:(NSDictionary*)dict {
     self = [self initWithTitle:title dataStore:dataStore];
     if (self) {
         self.entityDescription = [self optionalString:@"description" 
dict:dict];
-        self.snippet = [self optionalString:@"snippet" dict:dict];
+        self.snippet           = [self optionalString:@"snippet" dict:dict];
     }
-    
+
     return self;
 }
-
 
 #pragma mark - NSObject
 
@@ -238,18 +237,17 @@
     return [self.dataStore imageWithURL:url article:self];
 }
 
-- (void)loadThumbnailFromDisk{
-    
+- (void)loadThumbnailFromDisk {
     /**
      *  The folowing logic was pulled from the Article Fetcher
      *  Putting it here to being to coalesce populating Article data
      *  in a single place. This will be addressed natuarlly as we
      *  refactor model class mapping in the network layer.
      */
-    if(!self.thumbnailURL){
+    if (!self.thumbnailURL) {
         return;
     }
-    
+
     if ([[self existingImageWithURL:self.thumbnailURL] isCached]) {
         return;
     }
@@ -270,7 +268,6 @@
         }
     }
 }
-
 
 /**
  * Return image object if folder for that image exists
diff --git a/NSError+WMFExtensions.h b/NSError+WMFExtensions.h
new file mode 100644
index 0000000..1163b0a
--- /dev/null
+++ b/NSError+WMFExtensions.h
@@ -0,0 +1,16 @@
+
+#import <Foundation/Foundation.h>
+
+extern NSString* const WMFErrorDomain;
+
+typedef NS_ENUM(NSInteger, WMFErrorType) {
+    
+    WMFErrorTypeStringLength,
+
+};
+
+@interface NSError (WMFExtensions)
+
++ (NSError*)wmf_errorWithType:(WMFErrorType)type 
userInfo:(NSDictionary*)userInfo;
+
+@end
diff --git a/NSError+WMFExtensions.m b/NSError+WMFExtensions.m
new file mode 100644
index 0000000..14e11ad
--- /dev/null
+++ b/NSError+WMFExtensions.m
@@ -0,0 +1,13 @@
+
+#import "NSError+WMFExtensions.h"
+
+NSString* const WMFErrorDomain = @"WMFErrorDomain";
+
+@implementation NSError (WMFExtensions)
+
++ (NSError*)wmf_errorWithType:(WMFErrorType)type 
userInfo:(NSDictionary*)userInfo{
+    
+    return [NSError errorWithDomain:WMFErrorDomain code:type 
userInfo:userInfo];
+}
+
+@end
diff --git a/Wikipedia.xcodeproj/project.pbxproj 
b/Wikipedia.xcodeproj/project.pbxproj
index 40779ac..c1a0456 100644
--- a/Wikipedia.xcodeproj/project.pbxproj
+++ b/Wikipedia.xcodeproj/project.pbxproj
@@ -180,6 +180,8 @@
                04F27B7818FE0F2E00EDD838 /* PageHistoryViewController.m in 
Sources */ = {isa = PBXBuildFile; fileRef = 04F27B7418FE0F2E00EDD838 /* 
PageHistoryViewController.m */; };
                04F39590186CF80100B0D6FC /* TOCViewController.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 04F3958F186CF80100B0D6FC /* TOCViewController.m 
*/; };
                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 */; };
                0E30072A1B30B97300D95147 /* Article.m in Sources */ = {isa = 
PBXBuildFile; fileRef = 0E30070C1B30B97300D95147 /* Article.m */; };
                0E30072B1B30B97300D95147 /* ArticleData.xcdatamodeld in Sources 
*/ = {isa = PBXBuildFile; fileRef = 0E30070E1B30B97300D95147 /* 
ArticleData.xcdatamodeld */; };
                0E30072C1B30B97300D95147 /* ArticleDataContextSingleton.m in 
Sources */ = {isa = PBXBuildFile; fileRef = 0E3007121B30B97300D95147 /* 
ArticleDataContextSingleton.m */; };
@@ -194,8 +196,6 @@
                0E3007351B30B97300D95147 /* Saved.m in Sources */ = {isa = 
PBXBuildFile; fileRef = 0E3007251B30B97300D95147 /* Saved.m */; };
                0E3007361B30B97300D95147 /* Section.m in Sources */ = {isa = 
PBXBuildFile; fileRef = 0E3007271B30B97300D95147 /* Section.m */; };
                0E3007371B30B97300D95147 /* SectionImage.m in Sources */ = {isa 
= PBXBuildFile; fileRef = 0E3007291B30B97300D95147 /* SectionImage.m */; };
-               0E2B06F61B2CE45800EA2F53 /* WMFSavedPagesDataSource.m in 
Sources */ = {isa = PBXBuildFile; fileRef = 0E2B06F51B2CE45800EA2F53 /* 
WMFSavedPagesDataSource.m */; };
-               0E2B07021B2D1DE200EA2F53 /* WMFBottomStackLayout.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = 0E2B07011B2D1DE200EA2F53 /* 
WMFBottomStackLayout.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 
*/; };
@@ -219,6 +219,7 @@
                0ED44D781B28DA4D00F284BA /* UICollectionView+WMFExtensions.m in 
Sources */ = {isa = PBXBuildFile; fileRef = 0ED44D771B28DA4D00F284BA /* 
UICollectionView+WMFExtensions.m */; };
                0EE7687B1AF982C100A5D046 /* WMFArticleProtocol.m in Sources */ 
= {isa = PBXBuildFile; fileRef = 0EE7687A1AF982C100A5D046 /* 
WMFArticleProtocol.m */; };
                0EE768811AFD25CC00A5D046 /* WMFSearchFunnel.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 0EE768801AFD25CC00A5D046 /* WMFSearchFunnel.m 
*/; };
+               0EFB0EF51B31DE7200D05C08 /* NSError+WMFExtensions.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = 0EFB0EF41B31DE7200D05C08 /* 
NSError+WMFExtensions.m */; };
                701FF5EE601DEA3FCAB7EFD3 /* libPods.a in Frameworks */ = {isa = 
PBXBuildFile; fileRef = D82982ED992F47428037BDF2 /* libPods.a */; };
                954BA118838BF8BA6B01C34A /* libPods-WikipediaUnitTests.a in 
Frameworks */ = {isa = PBXBuildFile; fileRef = 8CE61C6963F825760822A28A /* 
libPods-WikipediaUnitTests.a */; };
                BC092B961B18E89200093C59 /* NSString+WMFPageUtilities.m in 
Sources */ = {isa = PBXBuildFile; fileRef = BC092B951B18E89200093C59 /* 
NSString+WMFPageUtilities.m */; };
@@ -725,6 +726,10 @@
                08D631F81A69B8CD00D87AD0 /* WMFImageGalleryCollectionViewCell.h 
*/ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.h; name = WMFImageGalleryCollectionViewCell.h; path = "Image 
Gallery/WMFImageGalleryCollectionViewCell.h"; sourceTree = "<group>"; };
                08D631F91A69B8CD00D87AD0 /* WMFImageGalleryCollectionViewCell.m 
*/ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.objc; name = WMFImageGalleryCollectionViewCell.m; path = "Image 
Gallery/WMFImageGalleryCollectionViewCell.m"; sourceTree = "<group>"; };
                08F646F7D0488CE3C6D6A763 /* Pods.beta.xcconfig */ = {isa = 
PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = 
Pods.beta.xcconfig; path = "Pods/Target Support Files/Pods/Pods.beta.xcconfig"; 
sourceTree = "<group>"; };
+               0E2B06F41B2CE45800EA2F53 /* WMFSavedPagesDataSource.h */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path 
= WMFSavedPagesDataSource.h; sourceTree = "<group>"; };
+               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>"; };
                0E3007091B30B90100D95147 /* Global.h */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Global.h; 
sourceTree = "<group>"; };
                0E30070B1B30B97300D95147 /* Article.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
Article.h; sourceTree = "<group>"; };
                0E30070C1B30B97300D95147 /* Article.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= Article.m; sourceTree = "<group>"; };
@@ -755,10 +760,6 @@
                0E3007271B30B97300D95147 /* Section.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= Section.m; sourceTree = "<group>"; };
                0E3007281B30B97300D95147 /* SectionImage.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
SectionImage.h; sourceTree = "<group>"; };
                0E3007291B30B97300D95147 /* SectionImage.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= SectionImage.m; sourceTree = "<group>"; };
-               0E2B06F41B2CE45800EA2F53 /* WMFSavedPagesDataSource.h */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path 
= WMFSavedPagesDataSource.h; sourceTree = "<group>"; };
-               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>"; };
                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>"; };
@@ -791,7 +792,6 @@
                0EA4402D1AA6281200B09DBA /* NSDateFormatter+WMFExtensions.m */ 
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.objc; name = "NSDateFormatter+WMFExtensions.m"; path = 
"Wikipedia/Categories/NSDateFormatter+WMFExtensions.m"; sourceTree = 
SOURCE_ROOT; };
                0EBC567D1AD442CC00E82CDD /* BITHockeyManager+WMFExtensions.h */ 
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.h; name = "BITHockeyManager+WMFExtensions.h"; path = 
"Wikipedia/Categories/BITHockeyManager+WMFExtensions.h"; sourceTree = 
SOURCE_ROOT; };
                0EBC567E1AD442CC00E82CDD /* BITHockeyManager+WMFExtensions.m */ 
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.objc; name = "BITHockeyManager+WMFExtensions.m"; path = 
"Wikipedia/Categories/BITHockeyManager+WMFExtensions.m"; sourceTree = 
SOURCE_ROOT; };
-               0ED44D6E1B2893C500F284BA /* Global.h */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Global.h; 
sourceTree = "<group>"; };
                0ED44D731B28AC1E00F284BA /* 
WMFArticleViewControllerContainerCell.h */ = {isa = PBXFileReference; 
fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WMFArticleViewControllerContainerCell.h; sourceTree = "<group>"; };
                0ED44D741B28AC1E00F284BA /* 
WMFArticleViewControllerContainerCell.m */ = {isa = PBXFileReference; 
fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = 
WMFArticleViewControllerContainerCell.m; sourceTree = "<group>"; };
                0ED44D761B28DA4D00F284BA /* UICollectionView+WMFExtensions.h */ 
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.h; path = "UICollectionView+WMFExtensions.h"; sourceTree = 
"<group>"; };
@@ -800,6 +800,8 @@
                0EE7687A1AF982C100A5D046 /* WMFArticleProtocol.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name 
= WMFArticleProtocol.m; path = Wikipedia/Protocols/WMFArticleProtocol.m; 
sourceTree = SOURCE_ROOT; };
                0EE7687F1AFD25CC00A5D046 /* WMFSearchFunnel.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WMFSearchFunnel.h; sourceTree = "<group>"; };
                0EE768801AFD25CC00A5D046 /* WMFSearchFunnel.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= WMFSearchFunnel.m; sourceTree = "<group>"; };
+               0EFB0EF31B31DE7200D05C08 /* NSError+WMFExtensions.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = 
"NSError+WMFExtensions.h"; path = "../../NSError+WMFExtensions.h"; sourceTree = 
"<group>"; };
+               0EFB0EF41B31DE7200D05C08 /* NSError+WMFExtensions.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name 
= "NSError+WMFExtensions.m"; path = "../../NSError+WMFExtensions.m"; sourceTree 
= "<group>"; };
                17A2F22335C5256576CEDBDD /* 
Pods-WikipediaUnitTests.release.xcconfig */ = {isa = PBXFileReference; 
includeInIndex = 1; lastKnownFileType = text.xcconfig; name = 
"Pods-WikipediaUnitTests.release.xcconfig"; path = "Pods/Target Support 
Files/Pods-WikipediaUnitTests/Pods-WikipediaUnitTests.release.xcconfig"; 
sourceTree = "<group>"; };
                1BC5FB470144D2C10C55A037 /* 
Pods-WikipediaUnitTests.alpha.xcconfig */ = {isa = PBXFileReference; 
includeInIndex = 1; lastKnownFileType = text.xcconfig; name = 
"Pods-WikipediaUnitTests.alpha.xcconfig"; path = "Pods/Target Support 
Files/Pods-WikipediaUnitTests/Pods-WikipediaUnitTests.alpha.xcconfig"; 
sourceTree = "<group>"; };
                357504E50DA104E39C6ACFEB /* Pods.release.xcconfig */ = {isa = 
PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = 
Pods.release.xcconfig; path = "Pods/Target Support 
Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
@@ -2094,49 +2096,6 @@
                        name = "Image Gallery";
                        sourceTree = "<group>";
                };
-               0E30070A1B30B97300D95147 /* LegacyCoreData */ = {
-                       isa = PBXGroup;
-                       children = (
-                               0E30070B1B30B97300D95147 /* Article.h */,
-                               0E30070C1B30B97300D95147 /* Article.m */,
-                               0E30070D1B30B97300D95147 /* 
ArticleCoreDataObjects.h */,
-                               0E30070E1B30B97300D95147 /* 
ArticleData.xcdatamodeld */,
-                               0E3007111B30B97300D95147 /* 
ArticleDataContextSingleton.h */,
-                               0E3007121B30B97300D95147 /* 
ArticleDataContextSingleton.m */,
-                               0E3007131B30B97300D95147 /* Categories */,
-                               0E30071A1B30B97300D95147 /* DiscoveryContext.h 
*/,
-                               0E30071B1B30B97300D95147 /* DiscoveryContext.m 
*/,
-                               0E30071C1B30B97300D95147 /* GalleryImage.h */,
-                               0E30071D1B30B97300D95147 /* GalleryImage.m */,
-                               0E30071E1B30B97300D95147 /* History.h */,
-                               0E30071F1B30B97300D95147 /* History.m */,
-                               0E3007201B30B97300D95147 /* Image.h */,
-                               0E3007211B30B97300D95147 /* Image.m */,
-                               0E3007221B30B97300D95147 /* ImageData.h */,
-                               0E3007231B30B97300D95147 /* ImageData.m */,
-                               0E3007241B30B97300D95147 /* Saved.h */,
-                               0E3007251B30B97300D95147 /* Saved.m */,
-                               0E3007261B30B97300D95147 /* Section.h */,
-                               0E3007271B30B97300D95147 /* Section.m */,
-                               0E3007281B30B97300D95147 /* SectionImage.h */,
-                               0E3007291B30B97300D95147 /* SectionImage.m */,
-                       );
-                       path = LegacyCoreData;
-                       sourceTree = SOURCE_ROOT;
-               };
-               0E3007131B30B97300D95147 /* Categories */ = {
-                       isa = PBXGroup;
-                       children = (
-                               0E3007141B30B97300D95147 /* 
NSManagedObject+WMFModelFactory.h */,
-                               0E3007151B30B97300D95147 /* 
NSManagedObject+WMFModelFactory.m */,
-                               0E3007161B30B97300D95147 /* 
NSManagedObjectContext+SimpleFetch.h */,
-                               0E3007171B30B97300D95147 /* 
NSManagedObjectContext+SimpleFetch.m */,
-                               0E3007181B30B97300D95147 /* 
NSManagedObjectModel+LegacyCoreData.h */,
-                               0E3007191B30B97300D95147 /* 
NSManagedObjectModel+LegacyCoreData.m */,
-                       );
-                       path = Categories;
-                       sourceTree = "<group>";
-               };
                0E2B06F71B2D126700EA2F53 /* Data Sources */ = {
                        isa = PBXGroup;
                        children = (
@@ -2200,6 +2159,49 @@
                        name = Cell;
                        sourceTree = "<group>";
                };
+               0E30070A1B30B97300D95147 /* LegacyCoreData */ = {
+                       isa = PBXGroup;
+                       children = (
+                               0E30070B1B30B97300D95147 /* Article.h */,
+                               0E30070C1B30B97300D95147 /* Article.m */,
+                               0E30070D1B30B97300D95147 /* 
ArticleCoreDataObjects.h */,
+                               0E30070E1B30B97300D95147 /* 
ArticleData.xcdatamodeld */,
+                               0E3007111B30B97300D95147 /* 
ArticleDataContextSingleton.h */,
+                               0E3007121B30B97300D95147 /* 
ArticleDataContextSingleton.m */,
+                               0E3007131B30B97300D95147 /* Categories */,
+                               0E30071A1B30B97300D95147 /* DiscoveryContext.h 
*/,
+                               0E30071B1B30B97300D95147 /* DiscoveryContext.m 
*/,
+                               0E30071C1B30B97300D95147 /* GalleryImage.h */,
+                               0E30071D1B30B97300D95147 /* GalleryImage.m */,
+                               0E30071E1B30B97300D95147 /* History.h */,
+                               0E30071F1B30B97300D95147 /* History.m */,
+                               0E3007201B30B97300D95147 /* Image.h */,
+                               0E3007211B30B97300D95147 /* Image.m */,
+                               0E3007221B30B97300D95147 /* ImageData.h */,
+                               0E3007231B30B97300D95147 /* ImageData.m */,
+                               0E3007241B30B97300D95147 /* Saved.h */,
+                               0E3007251B30B97300D95147 /* Saved.m */,
+                               0E3007261B30B97300D95147 /* Section.h */,
+                               0E3007271B30B97300D95147 /* Section.m */,
+                               0E3007281B30B97300D95147 /* SectionImage.h */,
+                               0E3007291B30B97300D95147 /* SectionImage.m */,
+                       );
+                       path = LegacyCoreData;
+                       sourceTree = SOURCE_ROOT;
+               };
+               0E3007131B30B97300D95147 /* Categories */ = {
+                       isa = PBXGroup;
+                       children = (
+                               0E3007141B30B97300D95147 /* 
NSManagedObject+WMFModelFactory.h */,
+                               0E3007151B30B97300D95147 /* 
NSManagedObject+WMFModelFactory.m */,
+                               0E3007161B30B97300D95147 /* 
NSManagedObjectContext+SimpleFetch.h */,
+                               0E3007171B30B97300D95147 /* 
NSManagedObjectContext+SimpleFetch.m */,
+                               0E3007181B30B97300D95147 /* 
NSManagedObjectModel+LegacyCoreData.h */,
+                               0E3007191B30B97300D95147 /* 
NSManagedObjectModel+LegacyCoreData.m */,
+                       );
+                       path = Categories;
+                       sourceTree = "<group>";
+               };
                0E366B371B2F2ACF00ABFB86 /* Layouts */ = {
                        isa = PBXGroup;
                        children = (
@@ -2245,6 +2247,8 @@
                                0E94AFF51B209882000BC5EA /* 
WMFArticleViewController.m */,
                                0E94AFF91B20A22C000BC5EA /* WMFStyleManager.h 
*/,
                                0E94AFFA1B20A22C000BC5EA /* WMFStyleManager.m 
*/,
+                               0EFB0EF31B31DE7200D05C08 /* 
NSError+WMFExtensions.h */,
+                               0EFB0EF41B31DE7200D05C08 /* 
NSError+WMFExtensions.m */,
                                0E2B06FA1B2D129B00EA2F53 /* Common */,
                                0E2B06F71B2D126700EA2F53 /* Data Sources */,
                        );
@@ -3284,6 +3288,7 @@
                                BC8340551B2233BE00A083DB /* 
LanguagesSectionHeaderView.m in Sources */,
                                04D149DD18877343006B4104 /* AlertLabel.m in 
Sources */,
                                BCB669AE1A83F6C400C7B1FE /* MWKHistoryEntry.m 
in Sources */,
+                               0EFB0EF51B31DE7200D05C08 /* 
NSError+WMFExtensions.m in Sources */,
                                0433542618A093C5009305F0 /* 
UIView+RemoveConstraints.m in Sources */,
                                04D686FC1AB2949C0009B44A /* WikiGlyphButton.m 
in Sources */,
                                C98990341A699DE000AF44FC /* 
WMFShareCardViewController.m in Sources */,
diff --git a/Wikipedia/Networking/Fetchers/SearchResultFetcher.m 
b/Wikipedia/Networking/Fetchers/SearchResultFetcher.m
index 8600b91..0e6ce3e 100644
--- a/Wikipedia/Networking/Fetchers/SearchResultFetcher.m
+++ b/Wikipedia/Networking/Fetchers/SearchResultFetcher.m
@@ -51,9 +51,7 @@
                                 language:(NSString*)language
                               maxResults:(NSUInteger)maxResults
                              
withManager:(AFHTTPRequestOperationManager*)manager
-                      thenNotifyDelegate:(id <FetchFinishedDelegate>)delegate{
-    
-    
+                      thenNotifyDelegate:(id <FetchFinishedDelegate>)delegate {
     self.searchResults         = @[];
     self.searchSuggestion      = nil;
     self.searchTerm            = searchTerm ? searchTerm : @"";
@@ -63,13 +61,11 @@
     self.fetchFinishedDelegate = delegate;
     self.maxSearchResults      = maxResults;
     self.spaceCollapsingRegex  =
-    [NSRegularExpression regularExpressionWithPattern:@"\\s{2,}+" 
options:NSRegularExpressionCaseInsensitive error:nil];
+        [NSRegularExpression regularExpressionWithPattern:@"\\s{2,}+" 
options:NSRegularExpressionCaseInsensitive error:nil];
     return [self searchWithManager:manager];
-
 }
 
-
-- (AFHTTPRequestOperation* 
)searchWithManager:(AFHTTPRequestOperationManager*)manager {
+- 
(AFHTTPRequestOperation*)searchWithManager:(AFHTTPRequestOperationManager*)manager
 {
     NSString* url = [[SessionSingleton sharedInstance] 
searchApiUrlForLanguage:self.language];
 
     NSDictionary* params = [self getParams];
@@ -110,7 +106,6 @@
                 }
             }
             self.articleTitleToImageMap = map;
-            
         }
 
         [self finishWithError:error
diff --git a/Wikipedia/UI-V5/Global.h b/Wikipedia/UI-V5/Global.h
index 212e0bb..96b7c13 100644
--- a/Wikipedia/UI-V5/Global.h
+++ b/Wikipedia/UI-V5/Global.h
@@ -10,6 +10,7 @@
 
 #import "WMFGCDHelpers.h"
 #import <BlocksKit/BlocksKit.h>
+#import "NSError+WMFExtensions.h"
 
 #import "RootViewController.h"
 #import "CenterNavController.h"
diff --git a/Wikipedia/UI-V5/TGLStackedViewController/TGLStackedLayout.m 
b/Wikipedia/UI-V5/TGLStackedViewController/TGLStackedLayout.m
index f0566e4..1f29d7b 100644
--- a/Wikipedia/UI-V5/TGLStackedViewController/TGLStackedLayout.m
+++ b/Wikipedia/UI-V5/TGLStackedViewController/TGLStackedLayout.m
@@ -326,14 +326,12 @@
     return [super 
finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath];
 }
 
-- (void)prepareForTransitionToLayout:(UICollectionViewLayout *)newLayout{
- 
+- (void)prepareForTransitionToLayout:(UICollectionViewLayout*)newLayout {
     [self.collectionView removeGestureRecognizer:self.moveGestureRecognizer];
     [self.collectionView removeGestureRecognizer:self.deletePanGesture];
     self.moveGestureRecognizer = nil;
-    self.deletePanGesture = nil;
+    self.deletePanGesture      = nil;
 }
-
 
 #pragma mark - Update Attributes
 
diff --git a/Wikipedia/UI-V5/UICollectionView+WMFExtensions.h 
b/Wikipedia/UI-V5/UICollectionView+WMFExtensions.h
index 98798a9..321ecef 100644
--- a/Wikipedia/UI-V5/UICollectionView+WMFExtensions.h
+++ b/Wikipedia/UI-V5/UICollectionView+WMFExtensions.h
@@ -11,6 +11,6 @@
  *  Like other UIKit methods, the completion isn't called if you pass animated 
= false.
  *  This method ensures the completion block is always called.
  */
-- (void)wmf_setCollectionViewLayout:(UICollectionViewLayout *)layout 
animated:(BOOL)animated alwaysFireCompletion:(void (^)(BOOL 
finished))completion;
+- (void)wmf_setCollectionViewLayout:(UICollectionViewLayout*)layout 
animated:(BOOL)animated alwaysFireCompletion:(void (^)(BOOL 
finished))completion;
 
 @end
diff --git a/Wikipedia/UI-V5/UICollectionView+WMFExtensions.m 
b/Wikipedia/UI-V5/UICollectionView+WMFExtensions.m
index 785101a..eabd833 100644
--- a/Wikipedia/UI-V5/UICollectionView+WMFExtensions.m
+++ b/Wikipedia/UI-V5/UICollectionView+WMFExtensions.m
@@ -37,19 +37,16 @@
  *  Like other UIKit methods, the completion isn't called if you pass animated 
= false.
  *  This method ensures the completion block is always called.
  */
-- (void)wmf_setCollectionViewLayout:(UICollectionViewLayout *)layout 
animated:(BOOL)animated alwaysFireCompletion:(void (^)(BOOL 
finished))completion{
-    
+- (void)wmf_setCollectionViewLayout:(UICollectionViewLayout*)layout 
animated:(BOOL)animated alwaysFireCompletion:(void (^)(BOOL 
finished))completion {
     [self setCollectionViewLayout:layout animated:animated completion:^(BOOL 
finished) {
-        if(animated && completion){
+        if (animated && completion) {
             completion(finished);
         }
     }];
-    
-    if(!animated && completion){
+
+    if (!animated && completion) {
         completion(YES);
     }
-    
 }
-
 
 @end
diff --git a/Wikipedia/UI-V5/UIStoryboard+WMFExtensions.m 
b/Wikipedia/UI-V5/UIStoryboard+WMFExtensions.m
index 0786998..a1c758b 100644
--- a/Wikipedia/UI-V5/UIStoryboard+WMFExtensions.m
+++ b/Wikipedia/UI-V5/UIStoryboard+WMFExtensions.m
@@ -9,10 +9,8 @@
     return [UIStoryboard storyboardWithName:WMFDefaultStoryBoardName 
bundle:nil];
 }
 
-- 
(id)wmf_instnatiateViewControllerWithIdentifierFromClassName:(Class)viewControllerClass{
-    
+- 
(id)wmf_instnatiateViewControllerWithIdentifierFromClassName:(Class)viewControllerClass
 {
     return [self 
instantiateViewControllerWithIdentifier:NSStringFromClass(viewControllerClass)];
 }
-
 
 @end
diff --git a/Wikipedia/UI-V5/WMFAppViewController.m 
b/Wikipedia/UI-V5/WMFAppViewController.m
index 377a07b..02b2950 100644
--- a/Wikipedia/UI-V5/WMFAppViewController.m
+++ b/Wikipedia/UI-V5/WMFAppViewController.m
@@ -10,8 +10,8 @@
 #import <Masonry/Masonry.h>
 
 @interface WMFAppViewController ()<WMFSearchViewControllerDelegate>
-@property (strong, nonatomic) IBOutlet UIView *searchContainerView;
-@property (strong, nonatomic) IBOutlet UIView *articleListContainerView;
+@property (strong, nonatomic) IBOutlet UIView* searchContainerView;
+@property (strong, nonatomic) IBOutlet UIView* articleListContainerView;
 
 @property (nonatomic, strong) IBOutlet UIView* splashView;
 @property (nonatomic, strong) WMFArticleListCollectionViewController* 
listViewController;
@@ -19,20 +19,18 @@
 
 @property (nonatomic, strong) SessionSingleton* session;
 
-@property (nonatomic, strong) MASConstraint *articleListVisibleConstraint;
-@property (nonatomic, strong) MASConstraint *articleListMinimizedConstraint;
+@property (nonatomic, strong) MASConstraint* articleListVisibleConstraint;
+@property (nonatomic, strong) MASConstraint* articleListMinimizedConstraint;
 
 @end
 
 @implementation WMFAppViewController
 
-- (SessionSingleton*)session{
-    
-    if(!_session){
-        
+- (SessionSingleton*)session {
+    if (!_session) {
         _session = [SessionSingleton sharedInstance];
     }
-    
+
     return _session;
 }
 
@@ -43,7 +41,6 @@
 }
 
 - (void)launchAppInWindow:(UIWindow*)window {
-    
     WMFStyleManager* manager = [WMFStyleManager new];
     [manager applyStyleToWindow:window];
     [WMFStyleManager setSharedStyleManager:manager];
@@ -53,12 +50,11 @@
 }
 
 - (void)loadMainUI {
-    
     [self updateListViewBasedOnSearchState:self.searchViewController.state];
 
     self.searchViewController.searchSite = [self.session searchSite];
-    self.searchViewController.dataStore = [self.session dataStore];
-    self.listViewController.dataSource = [[WMFSavedPagesDataSource alloc] 
initWithUserDataStore:[self userDataStore]];;
+    self.searchViewController.dataStore  = [self.session dataStore];
+    self.listViewController.dataSource   = [[WMFSavedPagesDataSource alloc] 
initWithUserDataStore:[self userDataStore]];;
 }
 
 - (void)resumeApp {
@@ -90,7 +86,7 @@
 
 - (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender {
     if ([segue.destinationViewController 
isKindOfClass:[WMFSearchViewController class]]) {
-        self.searchViewController = segue.destinationViewController;
+        self.searchViewController          = segue.destinationViewController;
         self.searchViewController.delegate = self;
     }
     if ([segue.destinationViewController 
isKindOfClass:[WMFArticleListCollectionViewController class]]) {
@@ -155,44 +151,35 @@
 
 #pragma mark - WMFSearchViewControllerDelegate
 
-- (void)searchController:(WMFSearchViewController*)controller 
searchStateDidChange:(WMFSearchState)state{
-
+- (void)searchController:(WMFSearchViewController*)controller 
searchStateDidChange:(WMFSearchState)state {
     [self updateListViewBasedOnSearchState:state];
 }
 
-- (void)updateListViewBasedOnSearchState:(WMFSearchState)state{
-    
+- (void)updateListViewBasedOnSearchState:(WMFSearchState)state {
     switch (state) {
-        case WMFSearchStateInactive:{
-          
+        case WMFSearchStateInactive: {
             [self.articleListMinimizedConstraint uninstall];
-            [self.articleListContainerView 
mas_makeConstraints:^(MASConstraintMaker *make) {
+            [self.articleListContainerView 
mas_makeConstraints:^(MASConstraintMaker* make) {
                 self.articleListVisibleConstraint = 
make.top.equalTo(self.view.mas_top).with.offset(64.0);
             }];
             [self.view layoutIfNeeded];
-            
-            [self.listViewController setListMode:WMFArticleListModeNormal 
animated:YES completion:NULL];
-            
-        }
-            break;
-        case WMFSearchStateActive:{
-            
-            __weak __typeof(self)weakSelf = self;
-            [self.listViewController 
setListMode:WMFArticleListModeBottomStacked animated:YES completion:^{
 
-                __strong __typeof(weakSelf)strongSelf = weakSelf;
+            [self.listViewController setListMode:WMFArticleListModeNormal 
animated:YES completion:NULL];
+        }
+        break;
+        case WMFSearchStateActive: {
+            __weak __typeof(self) weakSelf = self;
+            [self.listViewController 
setListMode:WMFArticleListModeBottomStacked animated:YES completion:^{
+                __strong __typeof(weakSelf) strongSelf = weakSelf;
                 [strongSelf.articleListVisibleConstraint uninstall];
-                [strongSelf.articleListContainerView 
mas_makeConstraints:^(MASConstraintMaker *make) {
+                [strongSelf.articleListContainerView 
mas_makeConstraints:^(MASConstraintMaker* make) {
                     strongSelf.articleListMinimizedConstraint = 
make.top.equalTo(strongSelf.view.mas_bottom).with.offset(-50.0);
                 }];
                 [strongSelf.view layoutIfNeeded];
             }];
-
         }
-            break;
+        break;
     }
 }
-
-
 
 @end
diff --git a/Wikipedia/UI-V5/WMFArticleListCollectionViewController.h 
b/Wikipedia/UI-V5/WMFArticleListCollectionViewController.h
index e394c88..57d2c25 100644
--- a/Wikipedia/UI-V5/WMFArticleListCollectionViewController.h
+++ b/Wikipedia/UI-V5/WMFArticleListCollectionViewController.h
@@ -4,8 +4,7 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-typedef NS_ENUM(NSUInteger, WMFArticleListMode) {
-    
+typedef NS_ENUM (NSUInteger, WMFArticleListMode) {
     WMFArticleListModeNormal = 0,
     WMFArticleListModeBottomStacked
 };
diff --git a/Wikipedia/UI-V5/WMFArticleListCollectionViewController.m 
b/Wikipedia/UI-V5/WMFArticleListCollectionViewController.m
index 5357007..891b6ab 100644
--- a/Wikipedia/UI-V5/WMFArticleListCollectionViewController.m
+++ b/Wikipedia/UI-V5/WMFArticleListCollectionViewController.m
@@ -24,69 +24,64 @@
 
 @implementation WMFArticleListCollectionViewController
 
-- (void)setDataSource:(id<WMFArticleListDataSource> __nullable)dataSource{
-    
-    if([_dataSource isEqual:dataSource]){
+- (void)setDataSource:(id<WMFArticleListDataSource> __nullable)dataSource {
+    if ([_dataSource isEqual:dataSource]) {
         return;
     }
-    
+
     _dataSource = dataSource;
-    
+
     self.title = [_dataSource displayTitle];
 
-    if([self isViewLoaded]){
+    if ([self isViewLoaded]) {
         [self.collectionView reloadData];
     }
 }
 
 #pragma mark - List Mode
 
-- (void)setListMode:(WMFArticleListMode)mode animated:(BOOL)animated 
completion:(nullable dispatch_block_t)completion{
-    
-    if(_mode == mode){
+- (void)setListMode:(WMFArticleListMode)mode animated:(BOOL)animated 
completion:(nullable dispatch_block_t)completion {
+    if (_mode == mode) {
         return;
     }
-    
+
     _mode = mode;
-    
-    if([self isViewLoaded]){
+
+    if ([self isViewLoaded]) {
         [self updateListForMode:_mode animated:animated completion:completion];
     }
 }
 
-- (void)updateListForMode:(WMFArticleListMode)mode animated:(BOOL)animated 
completion:(nullable dispatch_block_t)completion{
-
-
+- (void)updateListForMode:(WMFArticleListMode)mode animated:(BOOL)animated 
completion:(nullable dispatch_block_t)completion {
     UICollectionViewLayout* layout;
-    
-    switch (mode) {
-        case WMFArticleListModeBottomStacked:{
-            self.bottomStackLayout.itemSize = self.view.bounds.size;
-            layout = self.bottomStackLayout;
-            
-        }
-            break;
-        case WMFArticleListModeNormal:
-        default:{
-            self.stackedLayout.itemSize = self.view.bounds.size;
-            layout = self.stackedLayout;
-        }
-            break;
-    }
-    
 
-    __weak __typeof(self)weakSelf = self;
+    switch (mode) {
+        case WMFArticleListModeBottomStacked: {
+            self.bottomStackLayout.itemSize = self.view.bounds.size;
+            layout                          = self.bottomStackLayout;
+        }
+        break;
+        case WMFArticleListModeNormal:
+        default: {
+            self.stackedLayout.itemSize = self.view.bounds.size;
+            layout                      = self.stackedLayout;
+        }
+        break;
+    }
+
+
+    __weak __typeof(self) weakSelf = self;
     [self setOffsecreenLayoutAnimated:animated completion:^(BOOL finished) {
-        __strong __typeof(weakSelf)strongSelf = weakSelf;
+        __strong __typeof(weakSelf) strongSelf = weakSelf;
         [strongSelf.collectionView wmf_setCollectionViewLayout:layout 
animated:animated alwaysFireCompletion:^(BOOL finished) {
-            __strong __typeof(weakSelf)strongSelf = weakSelf;
-            if(mode == WMFArticleListModeBottomStacked){
+            __strong __typeof(weakSelf) strongSelf = weakSelf;
+            if (mode == WMFArticleListModeBottomStacked) {
                 strongSelf.collectionView.scrollEnabled = NO;
-            }else{
+            } else {
                 strongSelf.collectionView.scrollEnabled = YES;
             }
-            
-            if(completion){
+
+            if (completion) {
                 completion();
             }
         }];
@@ -99,38 +94,35 @@
  * The only solution I could find was to switch to an intermdeiate layout
  * first. This moves the items off screen and then brings them back.
  */
-- (void)setOffsecreenLayoutAnimated:(BOOL)animated completion:(void (^)(BOOL 
finished))completion{
-
+- (void)setOffsecreenLayoutAnimated:(BOOL)animated completion:(void (^)(BOOL 
finished))completion {
     WMFOffScreenFlowLayout* offscreen = [[WMFOffScreenFlowLayout alloc] init];
     offscreen.itemSize = self.view.bounds.size;
-    
+
     [self.collectionView wmf_setCollectionViewLayout:offscreen 
animated:animated alwaysFireCompletion:completion];
 }
-
 
 #pragma mark - Accessors
 
 - (TGLStackedLayout*)stackedLayout {
-    if(!_stackedLayout){
+    if (!_stackedLayout) {
         TGLStackedLayout* stacked = [[TGLStackedLayout alloc] init];
         stacked.fillHeight   = YES;
         stacked.alwaysBounce = YES;
         stacked.delegate     = self;
-        stacked.itemSize = self.view.bounds.size;
-        _stackedLayout = stacked;
+        stacked.itemSize     = self.view.bounds.size;
+        _stackedLayout       = stacked;
     }
-    
+
     return _stackedLayout;
 }
 
 - (WMFBottomStackLayout*)bottomStackLayout {
-    
-    if(!_bottomStackLayout){
+    if (!_bottomStackLayout) {
         WMFBottomStackLayout* stack = [[WMFBottomStackLayout alloc] init];
-        stack.itemSize = self.view.bounds.size;
+        stack.itemSize     = self.view.bounds.size;
         _bottomStackLayout = stack;
     }
-    
+
     return _bottomStackLayout;
 }
 
@@ -138,7 +130,7 @@
 
 - (void)viewDidLoad {
     [super viewDidLoad];
-    
+
     self.collectionView.backgroundColor = [UIColor clearColor];
 
     [self updateListForMode:self.mode animated:NO completion:NULL];
@@ -187,7 +179,7 @@
 #pragma mark - Update Cell Size
 
 - (void)updateCellSizeBasedOnViewFrame {
-    self.stackedLayout.itemSize = self.view.bounds.size;
+    self.stackedLayout.itemSize     = self.view.bounds.size;
     self.bottomStackLayout.itemSize = self.view.bounds.size;
 }
 
@@ -255,9 +247,8 @@
 }
 
 - (void)stackLayout:(TGLStackedLayout*)layout 
deleteItemAtIndexPath:(NSIndexPath*)indexPath {
-    
-    if([self.dataSource 
respondsToSelector:@selector(deleteArticleAtIndexPath:)]){
-        [self.dataSource deleteArticleAtIndexPath:indexPath];        
+    if ([self.dataSource 
respondsToSelector:@selector(deleteArticleAtIndexPath:)]) {
+        [self.dataSource deleteArticleAtIndexPath:indexPath];
     }
 }
 
diff --git a/Wikipedia/UI-V5/WMFArticleListDataSource.h 
b/Wikipedia/UI-V5/WMFArticleListDataSource.h
index e5d8a83..a469ffe 100644
--- a/Wikipedia/UI-V5/WMFArticleListDataSource.h
+++ b/Wikipedia/UI-V5/WMFArticleListDataSource.h
@@ -7,7 +7,7 @@
 
 - (nullable NSString*)displayTitle;
 
-- (NSUInteger)articleCount;
+- (NSUInteger) articleCount;
 - (MWKArticle*)articleForIndexPath:(NSIndexPath*)indexPath;
 
 - (BOOL)canDeleteItemAtIndexpath:(NSIndexPath*)indexPath;
diff --git a/Wikipedia/UI-V5/WMFBottomStackLayout.m 
b/Wikipedia/UI-V5/WMFBottomStackLayout.m
index a6ac2d8..42bc1e0 100644
--- a/Wikipedia/UI-V5/WMFBottomStackLayout.m
+++ b/Wikipedia/UI-V5/WMFBottomStackLayout.m
@@ -13,8 +13,7 @@
 
 #pragma mark - Setup
 
-- (instancetype)init
-{
+- (instancetype)init {
     self = [super init];
     if (self) {
         [self setupDefualts];
@@ -22,8 +21,7 @@
     return self;
 }
 
-- (instancetype)initWithCoder:(NSCoder *)coder
-{
+- (instancetype)initWithCoder:(NSCoder*)coder {
     self = [super initWithCoder:coder];
     if (self) {
         [self setupDefualts];
@@ -31,14 +29,13 @@
     return self;
 }
 
-- (void)setupDefualts{
-    
+- (void)setupDefualts {
     self.minimumLineSpacing      = 0.0f;
     self.minimumInteritemSpacing = 0.0f;
     self.scrollDirection         = UICollectionViewScrollDirectionVertical;
 
     _topCardExposedHeight = 40.0;
-    _overlapSpacing = 4;
+    _overlapSpacing       = 4;
 }
 
 #pragma mark - Accessors
@@ -50,7 +47,7 @@
     }
 }
 
-- (void)setTopCardExposedHeight:(CGFloat)topCardExposedHeight{
+- (void)setTopCardExposedHeight:(CGFloat)topCardExposedHeight {
     if (_topCardExposedHeight != topCardExposedHeight) {
         _topCardExposedHeight = topCardExposedHeight;
         [self invalidateLayout];
@@ -59,49 +56,42 @@
 
 #pragma mark - UICollectionViewLayout
 
-- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
-    
-    NSArray* items = [self.visibleIndexPaths bk_map:^id(id obj) {
-        
+- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
+    NSArray* items = [self.visibleIndexPaths bk_map:^id (id obj) {
         return [self layoutAttributesForItemAtIndexPath:obj];
     }];
 
     return items;
 }
 
-- (UICollectionViewLayoutAttributes 
*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
-    
+- 
(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath
 {
     UICollectionViewLayoutAttributes* item = [super 
layoutAttributesForItemAtIndexPath:indexPath];
     [self adjustLayoutAttributes:item];
     return item;
-    
 }
 
-- (void)adjustLayoutAttributes:(UICollectionViewLayoutAttributes*)attributes{
-    
+- (void)adjustLayoutAttributes:(UICollectionViewLayoutAttributes*)attributes {
     CGFloat spacingForIndexPath;
-    
+
     //Stagger the first 2 cards, then stack the rest behind
-    if([self.visibleIndexPaths indexOfObject:attributes.indexPath] < 2){
-        spacingForIndexPath = (self.overlapSpacing * [self.visibleIndexPaths 
indexOfObject:attributes.indexPath]);
-    }else{
+    if ([self.visibleIndexPaths indexOfObject:attributes.indexPath] < 2) {
+        spacingForIndexPath = (self.overlapSpacing* [self.visibleIndexPaths 
indexOfObject:attributes.indexPath]);
+    } else {
         spacingForIndexPath = (self.overlapSpacing * 2);
     }
-    
-    CGFloat topCardYOffset = 
CGRectGetHeight(self.collectionView.bounds)-self.topCardExposedHeight;
-    CGRect frame = attributes.frame;
-    frame.origin.y = topCardYOffset + spacingForIndexPath;
-    attributes.frame = frame;
+
+    CGFloat topCardYOffset = CGRectGetHeight(self.collectionView.bounds) - 
self.topCardExposedHeight;
+    CGRect frame           = attributes.frame;
+    frame.origin.y    = topCardYOffset + spacingForIndexPath;
+    attributes.frame  = frame;
     attributes.zIndex = attributes.indexPath.item;
 }
 
-- (CGSize)collectionViewContentSize{
-    
+- (CGSize)collectionViewContentSize {
     return self.collectionView.bounds.size;
 }
 
-- (void)prepareForTransitionFromLayout:(UICollectionViewLayout *)oldLayout{
-    
+- (void)prepareForTransitionFromLayout:(UICollectionViewLayout*)oldLayout {
     self.visibleIndexPaths = [self.collectionView indexPathsForVisibleItems];
 }
 
diff --git a/Wikipedia/UI-V5/WMFOffScreenFlowLayout.m 
b/Wikipedia/UI-V5/WMFOffScreenFlowLayout.m
index 7d1f2c2..e296885 100644
--- a/Wikipedia/UI-V5/WMFOffScreenFlowLayout.m
+++ b/Wikipedia/UI-V5/WMFOffScreenFlowLayout.m
@@ -6,8 +6,7 @@
 
 #pragma mark - Setup
 
-- (instancetype)init
-{
+- (instancetype)init {
     self = [super init];
     if (self) {
         [self setupDefualts];
@@ -15,8 +14,7 @@
     return self;
 }
 
-- (instancetype)initWithCoder:(NSCoder *)coder
-{
+- (instancetype)initWithCoder:(NSCoder*)coder {
     self = [super initWithCoder:coder];
     if (self) {
         [self setupDefualts];
@@ -24,8 +22,7 @@
     return self;
 }
 
-- (void)setupDefualts{
-    
+- (void)setupDefualts {
     self.minimumLineSpacing      = 0.0f;
     self.minimumInteritemSpacing = 0.0f;
     self.scrollDirection         = UICollectionViewScrollDirectionVertical;
@@ -33,38 +30,31 @@
 
 #pragma mark - UICollectionViewLayout
 
-- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
-    
+- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
     NSArray* items = [super layoutAttributesForElementsInRect:rect];
-    
-    [items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
-        
+
+    [items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* stop) {
         [self adjustLayoutAttributes:obj];
     }];
-    
+
     return items;
 }
 
-- (UICollectionViewLayoutAttributes 
*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
-    
+- 
(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath
 {
     UICollectionViewLayoutAttributes* item = [super 
layoutAttributesForItemAtIndexPath:indexPath];
     [self adjustLayoutAttributes:item];
     return item;
-    
 }
 
-- (void)adjustLayoutAttributes:(UICollectionViewLayoutAttributes*)attributes{
-    
+- (void)adjustLayoutAttributes:(UICollectionViewLayoutAttributes*)attributes {
     CGRect frame = attributes.frame;
-    frame.origin.y = CGRectGetHeight(self.collectionView.bounds);
-    attributes.frame = frame;
+    frame.origin.y    = CGRectGetHeight(self.collectionView.bounds);
+    attributes.frame  = frame;
     attributes.zIndex = attributes.indexPath.item;
 }
 
-- (CGSize)collectionViewContentSize{
-    
+- (CGSize)collectionViewContentSize {
     return self.collectionView.bounds.size;
 }
-
 
 @end
diff --git a/Wikipedia/UI-V5/WMFSavedPagesDataSource.m 
b/Wikipedia/UI-V5/WMFSavedPagesDataSource.m
index 830f233..ef0c798 100644
--- a/Wikipedia/UI-V5/WMFSavedPagesDataSource.m
+++ b/Wikipedia/UI-V5/WMFSavedPagesDataSource.m
@@ -22,8 +22,8 @@
     }
     return self;
 }
-    
-- (nullable NSString*)displayTitle{
+
+- (nullable NSString*)displayTitle {
     return MWLocalizedString(@"saved-pages-title", nil);
 }
 
diff --git a/Wikipedia/UI-V5/WMFSearchFetcher.h 
b/Wikipedia/UI-V5/WMFSearchFetcher.h
index 2fb435e..a8a5226 100644
--- a/Wikipedia/UI-V5/WMFSearchFetcher.h
+++ b/Wikipedia/UI-V5/WMFSearchFetcher.h
@@ -3,6 +3,7 @@
 #import "PromiseKit.h"
 
 @class MWKSite;
+@class WMFSearchResults;
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -17,6 +18,8 @@
 
 - (AnyPromise*)searchArticleTitlesForSearchTerm:(NSString*)searchTerm;
 
+- (AnyPromise*)searchFullArticleTextForSearchTerm:(NSString*)searchTerm 
appendToPreviousResults:(WMFSearchResults*)results;
+
 @end
 
 NS_ASSUME_NONNULL_END
\ No newline at end of file
diff --git a/Wikipedia/UI-V5/WMFSearchFetcher.m 
b/Wikipedia/UI-V5/WMFSearchFetcher.m
index 399093a..17548bc 100644
--- a/Wikipedia/UI-V5/WMFSearchFetcher.m
+++ b/Wikipedia/UI-V5/WMFSearchFetcher.m
@@ -26,41 +26,35 @@
 
 @implementation WMFSearchFetcher
 
-- (instancetype)initWithSearchSite:(MWKSite*)site 
dataStore:(MWKDataStore*)dataStore{
-
+- (instancetype)initWithSearchSite:(MWKSite*)site 
dataStore:(MWKDataStore*)dataStore {
     self = [super init];
     if (self) {
-        self.searchSite = site;
-        self.dataStore = dataStore;
+        self.searchSite       = site;
+        self.dataStore        = dataStore;
         self.maxSearchResults = kWMFmaxSearchResults;
         AFHTTPRequestOperationManager* manager = 
[AFHTTPRequestOperationManager wmf_createDefaultManager];
         manager.responseSerializer = [AFHTTPResponseSerializer serializer];
-        self.operationManager = manager;
+        self.operationManager      = manager;
     }
     return self;
 }
 
-- (AnyPromise*)searchArticleTitlesForSearchTerm:(NSString*)searchTerm 
searchType:(SearchType)type{
-    
+- (AnyPromise*)searchArticleTitlesForSearchTerm:(NSString*)searchTerm 
searchType:(SearchType)type {
     [self.operation cancel];
-    
+
     return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
-        
         self.resolver = resolve;
-        
+
         self.fetcher = [[SearchResultFetcher alloc] init];
         self.operation = [self.fetcher searchForTerm:searchTerm 
searchType:type searchReason:SEARCH_REASON_UNKNOWN 
language:self.searchSite.language maxResults:self.maxSearchResults 
withManager:self.operationManager thenNotifyDelegate:self];
     }];
 }
 
-- (AnyPromise*)searchArticleTitlesForSearchTerm:(NSString*)searchTerm{
-    
+- (AnyPromise*)searchArticleTitlesForSearchTerm:(NSString*)searchTerm {
     return [self searchArticleTitlesForSearchTerm:searchTerm 
searchType:SEARCH_TYPE_TITLES];
 }
 
-
-- (AnyPromise*)searchFullArticleTextForSearchTerm:(NSString*)searchTerm 
appendToPreviousResults:(WMFSearchResults*)results{
-    
+- (AnyPromise*)searchFullArticleTextForSearchTerm:(NSString*)searchTerm 
appendToPreviousResults:(WMFSearchResults*)results {
     self.previousResults = results;
     return [self searchArticleTitlesForSearchTerm:searchTerm 
searchType:SEARCH_TYPE_IN_ARTICLES];
 }
@@ -68,38 +62,49 @@
 - (void)fetchFinished:(id)sender
           fetchedData:(id)fetchedData
                status:(FetchFinalStatus)status
-                error:(NSError*)error{
-    
-    if(self.resolver){
-
-        if(!error){
+                error:(NSError*)error {
+    if (self.resolver) {
+        if (!error) {
             self.resolver([self searchResultsFromFetcher:sender]);
-        }else{
+        } else {
             self.resolver(error);
         }
         self.operation = nil;
-        self.resolver = nil;
+        self.resolver  = nil;
     }
 }
 
-- 
(WMFSearchResults*)searchResultsFromFetcher:(SearchResultFetcher*)resultsFetcher{
-    
-    NSArray* articles = [resultsFetcher.searchResults bk_map:^id(NSDictionary* 
obj) {
-        
+- 
(WMFSearchResults*)searchResultsFromFetcher:(SearchResultFetcher*)resultsFetcher
 {
+    NSArray* articles = [resultsFetcher.searchResults bk_map:^id 
(NSDictionary* obj) {
         MWKTitle* title = [MWKTitle titleWithString:obj[@"title"] 
site:self.searchSite];
         MWKArticle* article = [[MWKArticle alloc] initWithTitle:title 
dataStore:self.dataStore searchResultsDict:obj];
         article.thumbnailURL = 
resultsFetcher.articleTitleToImageMap[title.text];
         [article loadThumbnailFromDisk];
-        
+
         return article;
     }];
-    
-    WMFSearchResults* results = [[WMFSearchResults alloc] 
initWithSearchTerm:resultsFetcher.searchTerm articles:articles 
searchSuggestion:resultsFetcher.searchSuggestion];
+
+    WMFSearchResults* results = nil;
+
+    if (self.previousResults) {
+        articles = [articles bk_reject:^BOOL (MWKArticle* obj) {
+            if ([self.previousResults.articles containsObject:obj]) {
+                return YES;
+            }
+            return NO;
+        }];
+
+        articles             = [[NSArray arrayWithArray:[self.previousResults 
articles]] arrayByAddingObjectsFromArray:articles];
+        results              = [[WMFSearchResults alloc] 
initWithSearchTerm:self.previousResults.searchTerm articles:articles 
searchSuggestion:self.previousResults.searchSuggestion];
+        self.previousResults = nil;
+    } else {
+        results = [[WMFSearchResults alloc] 
initWithSearchTerm:resultsFetcher.searchTerm articles:articles 
searchSuggestion:resultsFetcher.searchSuggestion];
+    }
+
+
 
     return results;
 }
-
-
 
 @end
 
diff --git a/Wikipedia/UI-V5/WMFSearchResults.h 
b/Wikipedia/UI-V5/WMFSearchResults.h
index a671e80..5715708 100644
--- a/Wikipedia/UI-V5/WMFSearchResults.h
+++ b/Wikipedia/UI-V5/WMFSearchResults.h
@@ -7,7 +7,7 @@
 @interface WMFSearchResults : MTLModel<WMFArticleListDataSource>
 
 @property (nonatomic, copy, readonly) NSString* searchTerm;
-@property (nonatomic, strong, nullable, readonly) NSArray* resultArticles;
+@property (nonatomic, strong, nullable, readonly) NSArray* articles;
 @property (nonatomic, copy, nullable, readonly) NSString* searchSuggestion;
 
 - (instancetype)initWithSearchTerm:(NSString*)searchTerm articles:(nullable 
NSArray*)articles searchSuggestion:(nullable NSString*)suggestion;
diff --git a/Wikipedia/UI-V5/WMFSearchResults.m 
b/Wikipedia/UI-V5/WMFSearchResults.m
index 984473c..1475feb 100644
--- a/Wikipedia/UI-V5/WMFSearchResults.m
+++ b/Wikipedia/UI-V5/WMFSearchResults.m
@@ -6,49 +6,45 @@
 @interface WMFSearchResults ()
 
 @property (nonatomic, copy, readwrite) NSString* searchTerm;
-@property (nonatomic, strong, nullable, readwrite) NSArray* resultArticles;
+@property (nonatomic, strong, nullable, readwrite) NSArray* articles;
 @property (nonatomic, copy, nullable, readwrite) NSString* searchSuggestion;
 
 @end
 
 @implementation WMFSearchResults
 
-- (instancetype)initWithSearchTerm:(NSString*)searchTerm articles:(nullable 
NSArray*)articles searchSuggestion:(nullable NSString*)suggestion{
-
+- (instancetype)initWithSearchTerm:(NSString*)searchTerm articles:(nullable 
NSArray*)articles searchSuggestion:(nullable NSString*)suggestion {
     self = [super init];
     if (self) {
-        self.searchTerm = searchTerm;
-        self.resultArticles = articles;
+        self.searchTerm       = searchTerm;
+        self.articles         = articles;
         self.searchSuggestion = suggestion;
     }
     return self;
 }
 
-- (nullable NSString*)displayTitle{
+- (nullable NSString*)displayTitle {
     return self.searchTerm;
 }
 
-- (NSUInteger)articleCount{
-    return [self.resultArticles count];
+- (NSUInteger)articleCount {
+    return [self.articles count];
 }
 
 - (MWKArticle*)articleForIndexPath:(NSIndexPath*)indexPath {
-    return self.resultArticles[indexPath.row];
+    return self.articles[indexPath.row];
 }
 
-- (BOOL)canDeleteItemAtIndexpath:(NSIndexPath*)indexPath{
+- (BOOL)canDeleteItemAtIndexpath:(NSIndexPath*)indexPath {
     return NO;
 }
 
-
-- (BOOL)noResults{
-    
-    if(self.searchTerm && [self.resultArticles count] == 0){
+- (BOOL)noResults {
+    if (self.searchTerm && [self.articles count] == 0) {
         return YES;
     }
     return NO;
 }
-
 
 @end
 
diff --git a/Wikipedia/UI-V5/WMFSearchViewController.h 
b/Wikipedia/UI-V5/WMFSearchViewController.h
index f17947d..6dea657 100644
--- a/Wikipedia/UI-V5/WMFSearchViewController.h
+++ b/Wikipedia/UI-V5/WMFSearchViewController.h
@@ -3,8 +3,7 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-typedef NS_ENUM(NSUInteger, WMFSearchState) {
-    
+typedef NS_ENUM (NSUInteger, WMFSearchState) {
     WMFSearchStateInactive,
     WMFSearchStateActive
 };
diff --git a/Wikipedia/UI-V5/WMFSearchViewController.m 
b/Wikipedia/UI-V5/WMFSearchViewController.m
index 8040942..57a0a1d 100644
--- a/Wikipedia/UI-V5/WMFSearchViewController.m
+++ b/Wikipedia/UI-V5/WMFSearchViewController.m
@@ -6,31 +6,41 @@
 #import "WMFSearchResults.h"
 
 #import "SearchDidYouMeanButton.h"
+#import <Masonry/Masonry.h>
+
+static NSUInteger const kWMFMinResultsBeforeAutoFullTextSearch = 12;
 
 @interface WMFSearchViewController ()
 
 @property (nonatomic, strong) WMFArticleListCollectionViewController* 
resultsListController;
-@property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
-@property (strong, nonatomic) IBOutlet UIButton *searchSuggestionButton;
+@property (strong, nonatomic) IBOutlet UISearchBar* searchBar;
+@property (strong, nonatomic) IBOutlet UIButton* searchSuggestionButton;
+@property (strong, nonatomic) IBOutlet UIView* resultsListContainerView;
 
 @property (nonatomic, strong) WMFSearchFetcher* fetcher;
 
 @property (nonatomic, assign, readwrite) WMFSearchState state;
 
+@property (nonatomic, strong) MASConstraint* suggestionButtonVisibleConstraint;
+@property (nonatomic, strong) MASConstraint* suggestionButtonHiddenConstraint;
+
 @end
 
 @implementation WMFSearchViewController
 
-- (NSString*)currentSearchTerm{
+- (NSString*)currentSearchTerm {
     return [(WMFSearchResults*)self.resultsListController.dataSource 
searchTerm];
 }
 
-- (void)updateSearchStateAndNotifyDelegate:(WMFSearchState)state{
-    
-    if(self.state == state){
+- (NSString*)searchSuggestion {
+    return [(WMFSearchResults*)self.resultsListController.dataSource 
searchSuggestion];
+}
+
+- (void)updateSearchStateAndNotifyDelegate:(WMFSearchState)state {
+    if (self.state == state) {
         return;
     }
-    
+
     self.state = state;
 
     [self.delegate searchController:self searchStateDidChange:self.state];
@@ -40,8 +50,7 @@
 
 - (void)viewDidLoad {
     [super viewDidLoad];
-    
-    self.searchSuggestionButton.hidden = YES;
+    [self updateUIWithResults:nil];
 }
 
 - (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender {
@@ -52,92 +61,107 @@
 
 #pragma mark - UISearchBarDelegate
 
-- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
-    
+- (void)searchBarTextDidBeginEditing:(UISearchBar*)searchBar {
     [self updateSearchStateAndNotifyDelegate:WMFSearchStateActive];
-    
+
     [self.searchBar setShowsCancelButton:YES animated:YES];
-    
+
     self.fetcher = [[WMFSearchFetcher alloc] 
initWithSearchSite:self.searchSite dataStore:self.dataStore];
-    
-    if([self.searchBar.text length] > 2){
-        
-        if(![[self currentSearchTerm] isEqualToString:self.searchBar.text]){
+
+    if ([self.searchBar.text length] > 2) {
+        if (![[self currentSearchTerm] isEqualToString:self.searchBar.text]) {
             [self searchForSearchTerm:self.searchBar.text];
         }
-
-    }else{
-        
+    } else {
         self.resultsListController.dataSource = nil;
     }
 }
 
-- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString 
*)searchText{
-    
-    if(searchText.length > 2){
-        
-        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * 
NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-            
-            if([searchText isEqualToString:self.searchBar.text]){
-                [self searchForSearchTerm:searchText];
-            }
-        });
-    }
+- (void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)searchText {
+    dispatchOnMainQueueAfterDelayInSeconds(0.4, ^{
+        if ([searchText isEqualToString:self.searchBar.text]) {
+            [self searchForSearchTerm:searchText];
+        }
+    });
 }
 
-
-- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar{
-    
-    
+- (void)searchBarTextDidEndEditing:(UISearchBar*)searchBar {
 }
 
-- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
-    
-    
+- (void)searchBarSearchButtonClicked:(UISearchBar*)searchBar {
 }
 
-- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
-    
+- (void)searchBarCancelButtonClicked:(UISearchBar*)searchBar {
     [self updateSearchStateAndNotifyDelegate:WMFSearchStateInactive];
-
+    self.searchBar.text = nil;
     [self.searchBar setShowsCancelButton:NO animated:YES];
     [self.searchBar resignFirstResponder];
 }
 
-
 #pragma mark - Search
 
-- (void)searchForSearchTerm:(NSString*)searchTerm{
-    
-    [self.fetcher 
searchArticleTitlesForSearchTerm:searchTerm].then(^(WMFSearchResults* results){
-        
-        self.title = results.searchTerm;
-        
-        [self updateSearchButtonWithResults:results];
-        
+- (void)searchForSearchTerm:(NSString*)searchTerm {
+    dispatch_promise(^{
+        return (searchTerm.length > 2 ? searchTerm : [NSError 
wmf_errorWithType:WMFErrorTypeStringLength userInfo:nil]);
+    }).then(^(NSString* searchTerm){
+        return [self.fetcher searchArticleTitlesForSearchTerm:searchTerm];
+    }).then((id) ^ (WMFSearchResults * results){
+        [UIView animateWithDuration:0.25 animations:^{
+            [self updateUIWithResults:results];
+        }];
+
         self.resultsListController.dataSource = results;
 
+        if ([results.articles count] < kWMFMinResultsBeforeAutoFullTextSearch) 
{
+            return [self.fetcher searchFullArticleTextForSearchTerm:searchTerm 
appendToPreviousResults:results];
+        }
+
+        return [AnyPromise promiseWithValue:results];
+    }).then(^(WMFSearchResults* results){
+        self.resultsListController.dataSource = results;
     }).catch(^(NSError* error){
-        
         NSLog(@"%@", [error description]);
     });
-    
 }
 
-- (void)updateSearchButtonWithResults:(WMFSearchResults*)results{
-    
-//    if(![results noResults] && [results.searchSuggestion length]){
-//        
-//        self.searchSuggestionButton.hidden = NO;
-//        
-//        [self.searchSuggestionButton setTitle:[NSString 
stringWithFormat:@"%@:%@", MWLocalizedString(@"search-did-you-mean", nil), 
results.searchSuggestion] forState:UIControlStateNormal];
-//        
-//    }else{
-//        
-//        self.searchSuggestionButton.hidden = YES;
-//    }
-
+- (void)updateUIWithResults:(WMFSearchResults*)results {
+    self.title = results.searchTerm;
+    [self updateSearchButtonWithResults:results.searchSuggestion];
 }
 
+- (void)updateSearchButtonWithResults:(NSString*)searchSuggestion {
+    if ([searchSuggestion length]) {
+        [self.searchSuggestionButton setTitle:[NSString 
stringWithFormat:@"%@:%@", MWLocalizedString(@"search-did-you-mean", nil), 
searchSuggestion] forState:UIControlStateNormal];
+
+        if (!self.suggestionButtonVisibleConstraint) {
+            [self.suggestionButtonHiddenConstraint uninstall];
+            self.suggestionButtonHiddenConstraint = nil;
+            [self.resultsListContainerView 
mas_makeConstraints:^(MASConstraintMaker* make) {
+                self.suggestionButtonVisibleConstraint = 
make.top.equalTo(self.searchSuggestionButton.mas_bottom).with.offset(6.0);
+            }];
+            [self.view layoutIfNeeded];
+        }
+    } else {
+        [self.searchSuggestionButton setTitle:nil 
forState:UIControlStateNormal];
+
+        if (!self.suggestionButtonHiddenConstraint) {
+            [self.suggestionButtonVisibleConstraint uninstall];
+            self.suggestionButtonVisibleConstraint = nil;
+            [self.resultsListContainerView 
mas_makeConstraints:^(MASConstraintMaker* make) {
+                self.suggestionButtonHiddenConstraint = 
make.top.equalTo(self.searchBar.mas_bottom);
+            }];
+            [self.view layoutIfNeeded];
+        }
+    }
+}
+
+- (IBAction)searchForSuggestion:(id)sender {
+    self.searchBar.text = [self searchSuggestion];
+    [UIView animateWithDuration:0.25 animations:^{
+        [self updateSearchButtonWithResults:nil];
+    }];
+
+    [self searchForSearchTerm:self.searchBar.text];
+}
 
 @end
diff --git a/Wikipedia/UI-V5/iPhone_Root.storyboard 
b/Wikipedia/UI-V5/iPhone_Root.storyboard
index 0f11e9e..89893f5 100644
--- a/Wikipedia/UI-V5/iPhone_Root.storyboard
+++ b/Wikipedia/UI-V5/iPhone_Root.storyboard
@@ -114,24 +114,27 @@
                                 </connections>
                             </searchBar>
                             <containerView opaque="NO" 
contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" 
id="Ia7-49-Gwu">
-                                <rect key="frame" x="0.0" y="44" width="600" 
height="536"/>
+                                <rect key="frame" x="0.0" y="84" width="600" 
height="496"/>
                                 <animations/>
                                 <connections>
                                     <segue destination="qVm-oc-aaW" 
kind="embed" id="2dT-rC-ziD"/>
                                 </connections>
                             </containerView>
                             <button opaque="NO" contentMode="scaleToFill" 
contentHorizontalAlignment="center" contentVerticalAlignment="center" 
buttonType="roundedRect" lineBreakMode="middleTruncation" 
translatesAutoresizingMaskIntoConstraints="NO" id="ukX-0p-5ey">
-                                <rect key="frame" x="277" y="79" width="46" 
height="30"/>
+                                <rect key="frame" x="277" y="48" width="46" 
height="30"/>
                                 <animations/>
                                 <state key="normal" title="Button">
                                     <color key="titleShadowColor" white="0.5" 
alpha="1" colorSpace="calibratedWhite"/>
                                 </state>
+                                <connections>
+                                    <action selector="searchForSuggestion:" 
destination="tkf-8P-b2O" eventType="touchUpInside" id="0Md-vC-UXr"/>
+                                </connections>
                             </button>
                         </subviews>
                         <animations/>
                         <color key="backgroundColor" white="1" alpha="1" 
colorSpace="calibratedWhite"/>
                         <constraints>
-                            <constraint firstItem="ukX-0p-5ey" 
firstAttribute="top" secondItem="ZNj-Jo-URc" secondAttribute="bottom" 
constant="35" id="32n-FT-n9y"/>
+                            <constraint firstItem="ukX-0p-5ey" 
firstAttribute="top" secondItem="ZNj-Jo-URc" secondAttribute="bottom" 
constant="4" id="32n-FT-n9y"/>
                             <constraint firstAttribute="centerY" 
secondItem="ZNj-Jo-URc" secondAttribute="centerY" id="7um-O6-iBm"/>
                             <constraint firstItem="Ia7-49-Gwu" 
firstAttribute="leading" secondItem="xp5-j8-6jN" secondAttribute="leading" 
id="AdT-tS-YIU"/>
                             <constraint firstItem="ZNj-Jo-URc" 
firstAttribute="top" secondItem="CKX-gH-RjL" secondAttribute="bottom" 
id="HTd-6H-IdL"/>
@@ -139,6 +142,7 @@
                             <constraint firstItem="Ia7-49-Gwu" 
firstAttribute="top" secondItem="ZNj-Jo-URc" secondAttribute="bottom" 
id="VR7-y0-CDG"/>
                             <constraint firstItem="8Yb-zt-F5o" 
firstAttribute="top" secondItem="Ia7-49-Gwu" secondAttribute="bottom" 
id="XlJ-cb-ymV"/>
                             <constraint firstAttribute="centerX" 
secondItem="ZNj-Jo-URc" secondAttribute="centerX" id="cxv-4Q-C8N"/>
+                            <constraint firstItem="Ia7-49-Gwu" 
firstAttribute="top" secondItem="ukX-0p-5ey" secondAttribute="bottom" 
constant="6" placeholder="YES" id="fdO-Tl-2cD"/>
                             <constraint firstAttribute="centerX" 
secondItem="ukX-0p-5ey" secondAttribute="centerX" id="h5k-7F-xym"/>
                             <constraint firstItem="ZNj-Jo-URc" 
firstAttribute="leading" secondItem="xp5-j8-6jN" secondAttribute="leading" 
id="lud-F9-Eww"/>
                             <constraint firstAttribute="trailing" 
secondItem="ZNj-Jo-URc" secondAttribute="trailing" id="zhb-KY-6d8"/>
@@ -147,11 +151,13 @@
                             <mask key="constraints">
                                 <exclude reference="7um-O6-iBm"/>
                                 <exclude reference="cxv-4Q-C8N"/>
+                                <exclude reference="VR7-y0-CDG"/>
                             </mask>
                         </variation>
                     </view>
                     <toolbarItems/>
                     <connections>
+                        <outlet property="resultsListContainerView" 
destination="Ia7-49-Gwu" id="xdS-en-9mw"/>
                         <outlet property="searchBar" destination="ZNj-Jo-URc" 
id="Y5b-g5-7Mc"/>
                         <outlet property="searchSuggestionButton" 
destination="ukX-0p-5ey" id="O0X-WP-Nym"/>
                     </connections>
@@ -165,7 +171,7 @@
             <objects>
                 <collectionViewController 
storyboardIdentifier="WMFArticleListCollectionViewController" 
useStoryboardIdentifierAsRestorationIdentifier="YES" id="qVm-oc-aaW" 
customClass="WMFArticleListCollectionViewController" 
sceneMemberID="viewController">
                     <collectionView key="view" clipsSubviews="YES" 
multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" 
dataMode="prototypes" id="cbI-aA-luO">
-                        <rect key="frame" x="0.0" y="0.0" width="600" 
height="536"/>
+                        <rect key="frame" x="0.0" y="0.0" width="600" 
height="496"/>
                         <autoresizingMask key="autoresizingMask" 
widthSizable="YES" heightSizable="YES"/>
                         <animations/>
                         <collectionViewLayout key="collectionViewLayout" 
id="OM6-RR-VUO" customClass="TGLStackedLayout"/>

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I748da6d9bf6c2bffe733ec49d44d5f057fec5e65
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