Fjalapeno has uploaded a new change for review.
https://gerrit.wikimedia.org/r/191359
Change subject: Implement new refresh saved pages logic and UI.
......................................................................
Implement new refresh saved pages logic and UI.
Add progress bar to nav bar.
Add cancel button to nav bar.
Show informative alert when user first taps cancel refresh
Add saved pages fetch controller.
Make the article fetcher use background queue (otherwise blocks UI during
refresh)
Add masonry pod for auto layout syntax.
Change-Id: I0d03cec85081738211bb120593cd2777ba8518d8
---
M Podfile
M Podfile.lock
M Wikipedia.xcodeproj/project.pbxproj
A wikipedia/Custom Views/WMFBorderButton.h
A wikipedia/Custom Views/WMFBorderButton.m
A wikipedia/Custom Views/WMFProgressLineView.h
A wikipedia/Custom Views/WMFProgressLineView.m
M wikipedia/Networking/Fetchers/ArticleFetcher.m
A wikipedia/Networking/Fetchers/SavedArticlesFetcher.h
A wikipedia/Networking/Fetchers/SavedArticlesFetcher.m
M wikipedia/View Controllers/Navigation/Top/TopMenuViewController.h
M wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m
M wikipedia/View Controllers/SavedPages/SavedPagesViewController.h
M wikipedia/View Controllers/SavedPages/SavedPagesViewController.m
M wikipedia/en.lproj/Localizable.strings
M wikipedia/qqq.lproj/Localizable.strings
16 files changed, 736 insertions(+), 88 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/apps/ios/wikipedia
refs/changes/59/191359/1
diff --git a/Podfile b/Podfile
index 28cadab..2e24612 100644
--- a/Podfile
+++ b/Podfile
@@ -4,6 +4,7 @@
pod 'AFNetworking', '< 2.6'
pod 'hpple', '< 0.3'
pod 'blockskit/Core', '< 2.3'
+pod 'Masonry', '< 0.7'
target 'WikipediaUnitTests', :exclusive => false do
pod 'OCMockito', '< 1.5'
diff --git a/Podfile.lock b/Podfile.lock
index 3286146..c19da5e 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -22,6 +22,7 @@
- AFNetworking/NSURLSession
- BlocksKit/Core (2.2.5)
- hpple (0.2.0)
+ - Masonry (0.6.1)
- OCHamcrest (4.1.1)
- OCMockito (1.4.0):
- OCHamcrest (~> 4.0)
@@ -30,6 +31,7 @@
- AFNetworking (< 2.6)
- blockskit/Core (< 2.3)
- hpple (< 0.3)
+ - Masonry (< 0.7)
- OCHamcrest (< 4.2)
- OCMockito (< 1.5)
@@ -37,6 +39,7 @@
AFNetworking: 0f54cb5d16ce38c1b76948faffb8d5fb705021c7
BlocksKit: 4439e7f30a9f90743462ca63545a15c1f4304cef
hpple: f4eb7c21a8db83ec264e5d614ec7509e10e5adec
+ Masonry: 2cb49fd14d203d2db5ca6bb017135b235dde9980
OCHamcrest: af1c7c5ea345de69ea6c9c2958f65f3044e5c420
OCMockito: 991936bb775cc4c27f063d38f5e17b9161fbd21c
diff --git a/Wikipedia.xcodeproj/project.pbxproj
b/Wikipedia.xcodeproj/project.pbxproj
index 379bc48..4fbf156 100644
--- a/Wikipedia.xcodeproj/project.pbxproj
+++ b/Wikipedia.xcodeproj/project.pbxproj
@@ -276,6 +276,9 @@
BCB66A0C1A85183000C7B1FE /* NSString+WMFHTMLParsing.m in
Sources */ = {isa = PBXBuildFile; fileRef = BCB66A0B1A85183000C7B1FE /*
NSString+WMFHTMLParsing.m */; };
BCB66A0D1A85183000C7B1FE /* NSString+WMFHTMLParsing.m in
Sources */ = {isa = PBXBuildFile; fileRef = BCB66A0B1A85183000C7B1FE /*
NSString+WMFHTMLParsing.m */; };
BCB66A101A851C9B00C7B1FE /* MWKImageListTests.m in Sources */ =
{isa = PBXBuildFile; fileRef = BCB66A0F1A851C9B00C7B1FE /* MWKImageListTests.m
*/; };
+ C42D947E1A937DAC00A4871A /* SavedArticlesFetcher.m in Sources
*/ = {isa = PBXBuildFile; fileRef = C42D947D1A937DAC00A4871A /*
SavedArticlesFetcher.m */; };
+ C42D94861A937DE000A4871A /* WMFBorderButton.m in Sources */ =
{isa = PBXBuildFile; fileRef = C42D94831A937DE000A4871A /* WMFBorderButton.m
*/; };
+ C42D94871A937DE000A4871A /* WMFProgressLineView.m in Sources */
= {isa = PBXBuildFile; fileRef = C42D94851A937DE000A4871A /*
WMFProgressLineView.m */; };
C46FBA4B1A8530EE00C5730F /* Pods-acknowledgements.plist in
Resources */ = {isa = PBXBuildFile; fileRef = C46FBA4A1A8530EE00C5730F /*
Pods-acknowledgements.plist */; };
C90799BA1A8564C60044E13C /* WMFShareOptionsViewController.m in
Sources */ = {isa = PBXBuildFile; fileRef = C90799B91A8564C60044E13C /*
WMFShareOptionsViewController.m */; };
C9180EC418AED30C006C1DCA /* WikipediaAppUtils.m in Sources */ =
{isa = PBXBuildFile; fileRef = C9180EC318AED30C006C1DCA /* WikipediaAppUtils.m
*/; };
@@ -774,6 +777,12 @@
BCB66A0A1A85183000C7B1FE /* NSString+WMFHTMLParsing.h */ = {isa
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path
= "NSString+WMFHTMLParsing.h"; sourceTree = "<group>"; };
BCB66A0B1A85183000C7B1FE /* NSString+WMFHTMLParsing.m */ = {isa
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc;
path = "NSString+WMFHTMLParsing.m"; sourceTree = "<group>"; };
BCB66A0F1A851C9B00C7B1FE /* MWKImageListTests.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path
= MWKImageListTests.m; sourceTree = "<group>"; };
+ C42D947C1A937DAC00A4871A /* SavedArticlesFetcher.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path =
SavedArticlesFetcher.h; sourceTree = "<group>"; };
+ C42D947D1A937DAC00A4871A /* SavedArticlesFetcher.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path
= SavedArticlesFetcher.m; sourceTree = "<group>"; };
+ C42D94821A937DE000A4871A /* WMFBorderButton.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path =
WMFBorderButton.h; sourceTree = "<group>"; };
+ C42D94831A937DE000A4871A /* WMFBorderButton.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path
= WMFBorderButton.m; sourceTree = "<group>"; };
+ C42D94841A937DE000A4871A /* WMFProgressLineView.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path =
WMFProgressLineView.h; sourceTree = "<group>"; };
+ C42D94851A937DE000A4871A /* WMFProgressLineView.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path
= WMFProgressLineView.m; sourceTree = "<group>"; };
C46FBA4A1A8530EE00C5730F /* Pods-acknowledgements.plist */ =
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml;
name = "Pods-acknowledgements.plist"; path = "../../../Pods/Target Support
Files/Pods/Pods-acknowledgements.plist"; sourceTree = "<group>"; };
C90799B81A8564C60044E13C /* WMFShareOptionsViewController.h */
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType =
sourcecode.c.h; name = WMFShareOptionsViewController.h; path =
ShareCard/WMFShareOptionsViewController.h; sourceTree = "<group>"; };
C90799B91A8564C60044E13C /* WMFShareOptionsViewController.m */
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType =
sourcecode.c.objc; name = WMFShareOptionsViewController.m; path =
ShareCard/WMFShareOptionsViewController.m; sourceTree = "<group>"; };
@@ -1406,6 +1415,8 @@
0487045C19F8262600B7D307 /* AccountLogin.m */,
0487045D19F8262600B7D307 /* ArticleFetcher.h */,
0487045E19F8262600B7D307 /* ArticleFetcher.m */,
+ C42D947C1A937DAC00A4871A /*
SavedArticlesFetcher.h */,
+ C42D947D1A937DAC00A4871A /*
SavedArticlesFetcher.m */,
0487045F19F8262600B7D307 /* AssetsFileFetcher.h
*/,
0487046019F8262600B7D307 /* AssetsFileFetcher.m
*/,
0487046419F8262600B7D307 /* CaptchaResetter.h
*/,
@@ -2000,6 +2011,17 @@
path = ../MediaWikiKit/MediaWikiKitTests;
sourceTree = "<group>";
};
+ C42D94811A937DE000A4871A /* Custom Views */ = {
+ isa = PBXGroup;
+ children = (
+ C42D94821A937DE000A4871A /* WMFBorderButton.h
*/,
+ C42D94831A937DE000A4871A /* WMFBorderButton.m
*/,
+ C42D94841A937DE000A4871A /*
WMFProgressLineView.h */,
+ C42D94851A937DE000A4871A /*
WMFProgressLineView.m */,
+ );
+ path = "Custom Views";
+ sourceTree = "<group>";
+ };
C9180EC118AED30C006C1DCA /* mw-utils */ = {
isa = PBXGroup;
children = (
@@ -2102,6 +2124,7 @@
0463639518A844380049EE4F /* Keychain */,
04B60509193522650007185A /* MenuButton */,
04B6050D1935236C0007185A /* MenuLabel */,
+ C42D94811A937DE000A4871A /* Custom Views */,
0487041519F824D700B7D307 /* Networking */,
048A26741906268100395F53 /* PaddedLabel */,
0447866C1852B5010050563B /* Session */,
@@ -2728,6 +2751,7 @@
045374881A35834D00CE1A56 /*
LeadImageTitleAttributedString.m in Sources */,
04292FF2185FBA70002A13FC /* SearchResultCell.m
in Sources */,
04F0E2EA186EDC1A00468738 /*
UIWebView+ElementLocation.m in Sources */,
+ C42D94871A937DE000A4871A /*
WMFProgressLineView.m in Sources */,
0447866F1852B5010050563B /* SessionSingleton.m
in Sources */,
BCB669AA1A83F6C400C7B1FE /* MWKImage.m in
Sources */,
D4E8A8A4190835C100DA4765 /* DataMigrator.m in
Sources */,
@@ -2762,6 +2786,7 @@
BCB669AE1A83F6C400C7B1FE /* MWKHistoryEntry.m
in Sources */,
0433542618A093C5009305F0 /*
UIView+RemoveConstraints.m in Sources */,
C98990341A699DE000AF44FC /*
WMFShareCardViewController.m in Sources */,
+ C42D94861A937DE000A4871A /* WMFBorderButton.m
in Sources */,
047801BE18AE987900DBB747 /*
UIButton+ColorMask.m in Sources */,
BC86B93D1A929CC500B4C039 /*
UICollectionViewFlowLayout+NSCopying.m in Sources */,
0429300A18604898002A13FC /*
SavedPagesResultCell.m in Sources */,
@@ -2835,6 +2860,7 @@
BCB669AC1A83F6C400C7B1FE /* MWKSavedPageEntry.m
in Sources */,
049B640C18AAF36200D98BD4 /*
UIViewController+SearchChildViewControllers.m in Sources */,
04A97E8718B81D5D0046B166 /*
AccountCreationViewController.m in Sources */,
+ C42D947E1A937DAC00A4871A /*
SavedArticlesFetcher.m in Sources */,
04530AF81935C07500022512 /*
ModalContentViewController.m in Sources */,
0487048219F8262600B7D307 /* AssetsFileFetcher.m
in Sources */,
BC955BC71A82BEFD000EF9E4 /*
MWKImageInfoFetcher.m in Sources */,
diff --git a/wikipedia/Custom Views/WMFBorderButton.h b/wikipedia/Custom
Views/WMFBorderButton.h
new file mode 100644
index 0000000..46898c6
--- /dev/null
+++ b/wikipedia/Custom Views/WMFBorderButton.h
@@ -0,0 +1,30 @@
+
+#import <UIKit/UIKit.h>
+
+@interface WMFBorderButton : UIButton
+
+@property (nonatomic) CGFloat borderWidth;
+@property (nonatomic) CGFloat cornerRadius;
+@property (nonatomic, strong) UIColor* borderColor;
+
+/**
+ * Create a bordered button
+ *
+ * @param width The width of the border
+ * @param radius The corner radius of the border
+ * @param color The color of the border
+ *
+ * @return A new bordered button
+ */
++ (WMFBorderButton *)buttonWithBorderWidth:(CGFloat)width
cornerRadius:(CGFloat)radius color:(UIColor*)color;
+
+/**
+ * Returns a button with default options for width, color, radius
+ *
+ * @return A new default configured Button
+ */
++ (WMFBorderButton *)standardBorderButton;
+
+
+
+@end
diff --git a/wikipedia/Custom Views/WMFBorderButton.m b/wikipedia/Custom
Views/WMFBorderButton.m
new file mode 100644
index 0000000..43043da
--- /dev/null
+++ b/wikipedia/Custom Views/WMFBorderButton.m
@@ -0,0 +1,84 @@
+
+#import "WMFBorderButton.h"
+#import <objc/objc-runtime.h>
+
+static CGFloat const kWMFBorderButtonWidthPadding = 20.0;
+static CGFloat const kWMFBorderButtonHeightPadding = 10.0;
+@implementation WMFBorderButton
+
+@dynamic borderWidth, cornerRadius;
+
+#pragma mark - Convienence
+
++ (WMFBorderButton *)standardBorderButton{
+
+ return [WMFBorderButton buttonWithBorderWidth:1.0 cornerRadius:4.0
color:[UIColor colorWithRed:0.051 green:0.482 blue:0.984 alpha:1]];
+}
+
++ (WMFBorderButton *)buttonWithBorderWidth:(CGFloat)width
cornerRadius:(CGFloat)radius color:(UIColor*)color;
+{
+ WMFBorderButton* button = [WMFBorderButton
buttonWithType:UIButtonTypeCustom];
+ button.layer.masksToBounds = YES;
+ button.borderWidth = width;
+ button.cornerRadius = radius;
+ button.borderColor = color;
+ [button setTitleColor:color forState:UIControlStateNormal];
+ [button.titleLabel setFont:[UIFont systemFontOfSize:14.0]];
+ [button setAdjustsImageWhenHighlighted:NO];
+
+ return button;
+}
+
+#pragma mark - Runtime
+
+- (id)forwardingTargetForSelector:(SEL)aSelector{
+
+ if(sel_isEqual(aSelector, @selector(setBorderWidth:)) ||
+ sel_isEqual(aSelector, @selector(borderWidth)) ||
+ sel_isEqual(aSelector, @selector(setCornerRadius:)) ||
+ sel_isEqual(aSelector, @selector(cornerRadius))
+ ){
+
+ [self setNeedsDisplay];
+ [self setNeedsLayout];
+ [self setNeedsUpdateConstraints];
+ return self.layer;
+ }
+
+ return [super forwardingTargetForSelector:aSelector];
+}
+
+#pragma mark - Accessors
+
+- (void)setBorderColor:(UIColor *)borderColor{
+
+ self.layer.borderColor = borderColor.CGColor;
+ [self setNeedsDisplay];
+ [self setNeedsLayout];
+ [self setNeedsUpdateConstraints];
+}
+
+- (UIColor*)borderColor{
+
+ return [UIColor colorWithCGColor:self.layer.borderColor];
+}
+
+#pragma mark - UIView
+
+- (void)sizeToFit{
+
+ [super sizeToFit];
+ CGRect f = self.frame;
+ f.size.width += kWMFBorderButtonWidthPadding;
+ f.size.height += kWMFBorderButtonHeightPadding;
+}
+
+- (CGSize)intrinsicContentSize{
+
+ CGSize s = [super intrinsicContentSize];
+ s.width += kWMFBorderButtonWidthPadding;
+ s.height += kWMFBorderButtonHeightPadding;
+ return s;
+}
+
+@end
diff --git a/wikipedia/Custom Views/WMFProgressLineView.h b/wikipedia/Custom
Views/WMFProgressLineView.h
new file mode 100644
index 0000000..b839739
--- /dev/null
+++ b/wikipedia/Custom Views/WMFProgressLineView.h
@@ -0,0 +1,24 @@
+
+#import <UIKit/UIKit.h>
+
+@interface WMFProgressLineView : UIView
+
+
+/**
+ * Set the color of the progress.
+ * Default = [UIColor colorWithRed:0.106 green:0.678 blue:0.533 alpha:1]
+ * (Default Background Color = [UIColor colorWithRed:0.071 green:0.514
blue:0.404 alpha:1])
+ */
+@property (nonatomic, strong) UIColor* progressColor;
+
+/**
+ * The current progress shown by the receiver.
+ * The progress value ranges from 0 to 1. The default value is 0.
+ */
+@property (nonatomic, assign) float progress;
+
+- (void)setProgress:(float)progress animated:(BOOL)animated;
+
+- (void)setProgress:(float)progress animated:(BOOL)animated
completion:(dispatch_block_t)completion;
+
+@end
diff --git a/wikipedia/Custom Views/WMFProgressLineView.m b/wikipedia/Custom
Views/WMFProgressLineView.m
new file mode 100644
index 0000000..7658d47
--- /dev/null
+++ b/wikipedia/Custom Views/WMFProgressLineView.m
@@ -0,0 +1,94 @@
+
+
+#import "WMFProgressLineView.h"
+
+@interface WMFProgressLineView ()
+
+@property (nonatomic, strong) UIView *progressBar;
+
+@end
+
+@implementation WMFProgressLineView
+
+
+#pragma mark - UIView
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ if (self = [super initWithFrame:frame]) {
+ self.frame = frame;
+ self.clipsToBounds = YES;
+ self.backgroundColor = [UIColor clearColor];
+ self.tintAdjustmentMode = UIViewTintAdjustmentModeNormal;
+ self.progressBar = [[UIView alloc] init];
+ self.progressBar.backgroundColor = [UIColor colorWithRed:0.106
green:0.682 blue:0.541 alpha:1];
+ self.progress = 0.0;
+ [self addSubview:self.progressBar];
+ }
+ return self;
+}
+
+- (void)setFrame:(CGRect)frame
+{
+ //whole pixels for non-retina screens
+ frame.origin.y = ceilf(frame.origin.y);
+ frame.size.height = floorf(frame.size.height);
+ [super setFrame:frame];
+
+ __weak typeof(self)weakSelf = self;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ weakSelf.progress = weakSelf.progress;
+ });
+}
+
+#pragma mark - Progress
+
+- (void)setProgressColor:(UIColor *)progressColor{
+ self.progressBar.backgroundColor = progressColor;
+}
+
+- (void)setProgress:(float)progress {
+ [self setProgress:progress animated:NO];
+}
+
+- (void)setProgress:(float)progress animated:(BOOL)animated{
+
+ [self setProgress:progress animated:animated completion:NULL];
+}
+
+- (void)setProgress:(float)progress animated:(BOOL)animated
completion:(dispatch_block_t)completion{
+
+ _progress = (progress < 0) ? 0 :
+ (progress > 1) ? 1 :
+ progress;
+
+ CGRect slice, remainder;
+ CGRectDivide(self.bounds, &slice, &remainder, CGRectGetWidth(self.bounds)
* _progress, CGRectMinXEdge);
+
+ [CATransaction begin];
+
+ [CATransaction setCompletionBlock:completion];
+
+ if (!CGRectEqualToRect(self.progressBar.frame, slice)) {
+
+
+ if(animated){
+
+ [UIView animateWithDuration:0.2 animations:^{
+
+ self.progressBar.frame = slice;
+ }];
+
+ }else{
+
+ self.progressBar.frame = slice;
+
+ }
+ }
+
+ [CATransaction commit];
+}
+
+
+
+@end
diff --git a/wikipedia/Networking/Fetchers/ArticleFetcher.m
b/wikipedia/Networking/Fetchers/ArticleFetcher.m
index 8688929..d2e6c62 100644
--- a/wikipedia/Networking/Fetchers/ArticleFetcher.m
+++ b/wikipedia/Networking/Fetchers/ArticleFetcher.m
@@ -45,6 +45,7 @@
-(void)fetchWithManager:(AFHTTPRequestOperationManager *)manager
{
+
NSString *title = self.article.title.prefixedText;
NSString *subdomain = self.article.title.site.language;
@@ -77,43 +78,56 @@
[self addMCCMNCHeaderToRequestSerializer:manager.requestSerializer
ifAppropriateForURL:url];
[manager GET:url.absoluteString parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) {
- //NSLog(@"JSON: %@", responseObject);
- [[MWNetworkActivityIndicatorManager sharedManager] pop];
-
- // Convert the raw NSData response to a dictionary.
- responseObject = [self dictionaryFromDataResponse:responseObject];
-
- // Clear any MCCMNC header - needed because manager is a singleton.
- [self
removeMCCMNCHeaderFromRequestSerializer:manager.requestSerializer];
- //NSDictionary *leadSectionResults = [self
prepareResultsFromResponse:responseObject forTitle:title];
- if (self.article.needsRefresh) {
- [self.article remove];
- }
- @try {
- [self.article importMobileViewJSON:responseObject[@"mobileview"]];
+ __block id localResponseObject = responseObject;
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,
0), ^{
+
+ //NSLog(@"JSON: %@", responseObject);
+ [[MWNetworkActivityIndicatorManager sharedManager] pop];
+
+ // Convert the raw NSData response to a dictionary.
+ localResponseObject = [self
dictionaryFromDataResponse:localResponseObject];
+
+ // Clear any MCCMNC header - needed because manager is a singleton.
+ [self
removeMCCMNCHeaderFromRequestSerializer:manager.requestSerializer];
+
+ //NSDictionary *leadSectionResults = [self
prepareResultsFromResponse:responseObject forTitle:title];
+ if (self.article.needsRefresh) {
+ [self.article remove];
+ }
+ @try {
+ [self.article
importMobileViewJSON:localResponseObject[@"mobileview"]];
+ [self.article save];
+ }
+ @catch (NSException *e) {
+ NSLog(@"%@", e);
+ NSError *err = [NSError errorWithDomain:@"ArticleFetcher"
code:666 userInfo:@{@"exception": e}];
+ [self finishWithError: err
+ fetchedData: nil];
+ return;
+ }
+
+ //[self applyResultsForLeadSection:leadSectionResults];
+ for (int n = 0; n < [self.article.sections count]; n++) {
+ (void)self.article.sections[n].images; // hack
+ [self createImageRecordsForSection:n];
+ }
+
+ [self associateThumbFromTempDirWithArticle];
+
[self.article save];
- }
- @catch (NSException *e) {
- NSLog(@"%@", e);
- NSError *err = [NSError errorWithDomain:@"ArticleFetcher" code:666
userInfo:@{@"exception": e}];
- [self finishWithError: err
- fetchedData: nil];
- return;
- }
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ [self finishWithError: nil
+ fetchedData: nil];
+
+ });
+
+ });
- //[self applyResultsForLeadSection:leadSectionResults];
- for (int n = 0; n < [self.article.sections count]; n++) {
- (void)self.article.sections[n].images; // hack
- [self createImageRecordsForSection:n];
- }
-
- [self associateThumbFromTempDirWithArticle];
-
- [self.article save];
-
- [self finishWithError: nil
- fetchedData: nil];
+
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
diff --git a/wikipedia/Networking/Fetchers/SavedArticlesFetcher.h
b/wikipedia/Networking/Fetchers/SavedArticlesFetcher.h
new file mode 100644
index 0000000..841ed2d
--- /dev/null
+++ b/wikipedia/Networking/Fetchers/SavedArticlesFetcher.h
@@ -0,0 +1,30 @@
+
+#import "FetcherBase.h"
+
+@class MWKArticle, MWKSavedPageList, AFHTTPRequestOperationManager;
+@class SavedArticlesFetcher;
+
+@protocol SavedArticlesFetcherDelegate <FetchFinishedDelegate>
+
+- (void)savedArticlesFetcher: (SavedArticlesFetcher*)savedArticlesFetcher
+ didFetchArticle: (MWKArticle*)article
+ remainingArticles: (NSInteger)remaining
+ totalArticles: (NSInteger)total
+ status: (FetchFinalStatus)status
+ error: (NSError *)error;
+
+@end
+
+@interface SavedArticlesFetcher : FetcherBase
+
+@property (strong, nonatomic, readonly) MWKSavedPageList *savedPageList;
+@property (nonatomic, strong, readonly) MWKDataStore *dataStore;
+
+@property (nonatomic, weak) id <SavedArticlesFetcherDelegate>
fetchFinishedDelegate;
+
+- (instancetype)initAndFetchArticlesForSavedPageList: (MWKSavedPageList
*)savedPageList
+ inDataStore: (MWKDataStore *)dataStore
+ withManager:
(AFHTTPRequestOperationManager *)manager
+ thenNotifyDelegate: (id
<SavedArticlesFetcherDelegate>) delegate;
+
+@end
diff --git a/wikipedia/Networking/Fetchers/SavedArticlesFetcher.m
b/wikipedia/Networking/Fetchers/SavedArticlesFetcher.m
new file mode 100644
index 0000000..90b647f
--- /dev/null
+++ b/wikipedia/Networking/Fetchers/SavedArticlesFetcher.m
@@ -0,0 +1,106 @@
+
+#import "SavedArticlesFetcher.h"
+#import "ArticleFetcher.h"
+#import "AFHTTPRequestOperationManager.h"
+
+@interface SavedArticlesFetcher()<FetchFinishedDelegate>
+
+@property (nonatomic, strong, readwrite) MWKSavedPageList *savedPageList;
+@property (nonatomic, strong, readwrite) MWKDataStore *dataStore;
+
+@property (nonatomic, strong) NSMutableDictionary *fetchersByArticleTitle;
+@property (nonatomic, strong) NSMutableDictionary *errorsByArticleTitle;
+
+@property (nonatomic, strong) NSMutableArray *fetchedArticles;
+
+@end
+
+@implementation SavedArticlesFetcher
+
+- (instancetype)initAndFetchArticlesForSavedPageList: (MWKSavedPageList
*)savedPageList
+ inDataStore: (MWKDataStore *)dataStore
+ withManager:
(AFHTTPRequestOperationManager *)manager
+ thenNotifyDelegate: (id
<SavedArticlesFetcherDelegate>) delegate{
+
+ self = [super init];
+ assert(savedPageList != nil);
+ assert(dataStore != nil);
+ assert(manager != nil);
+ assert(delegate != nil);
+ if (self) {
+ self.savedPageList = savedPageList;
+ self.dataStore = dataStore;
+ self.fetchFinishedDelegate = delegate;
+ [self fetchWithManager:manager];
+ }
+ return self;
+
+}
+
+
+- (void)fetchWithManager:(AFHTTPRequestOperationManager *)manager{
+
+ [manager.operationQueue cancelAllOperations];
+
+ self.fetchersByArticleTitle = [NSMutableDictionary dictionary];
+ self.errorsByArticleTitle = [NSMutableDictionary dictionary];
+ self.fetchedArticles = [NSMutableArray array];
+
+ for (MWKSavedPageEntry* entry in self.savedPageList) {
+
+ MWKArticle *article = [self.dataStore articleWithTitle:entry.title];
+ article.needsRefresh = YES;
+
+ self.fetchersByArticleTitle[entry.title] = [[ArticleFetcher alloc]
initAndFetchSectionsForArticle:article withManager:manager
thenNotifyDelegate:self];
+
+ }
+}
+
+- (void)fetchFinished:(id)sender fetchedData:(id)fetchedData
status:(FetchFinalStatus)status error:(NSError *)error{
+
+ __block id completedFetcherKey;
+
+ [self.fetchersByArticleTitle enumerateKeysAndObjectsUsingBlock:^(id key,
id obj, BOOL *stop) {
+
+ if([sender isEqual:obj]){
+ completedFetcherKey = key;
+ *stop = YES;
+ }
+ }];
+
+ if(error){
+
+ self.errorsByArticleTitle[completedFetcherKey] = error;
+ }
+
+ [self.fetchersByArticleTitle removeObjectForKey:completedFetcherKey];
+
+ MWKArticle *article = [self.dataStore
articleWithTitle:completedFetcherKey];
+
+ [self.fetchedArticles addObject:article];
+
+ [self.fetchFinishedDelegate savedArticlesFetcher:self
didFetchArticle:article remainingArticles:[self.fetchersByArticleTitle count]
totalArticles:self.savedPageList.length status:status error:error];
+
+ if([self.fetchersByArticleTitle count] == 0){
+ [self notifyDelegate];
+ }
+
+}
+
+
+- (void)notifyDelegate{
+
+ NSError* reportedError;
+ if([self.errorsByArticleTitle count] > 0)
+ reportedError = [[self.errorsByArticleTitle allValues] firstObject];
+
+ [self finishWithError: reportedError
+ fetchedData: nil];
+
+
+}
+
+
+
+
+@end
diff --git a/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.h
b/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.h
index 85d48af..99a6dca 100644
--- a/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.h
+++ b/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.h
@@ -12,6 +12,7 @@
NAVBAR_BUTTON_LOGO_W,
NAVBAR_BUTTON_TOC,
NAVBAR_BUTTON_MAGNIFY,
+ NAVBAR_BUTTON_RELOAD,
NAVBAR_BUTTON_BLANK,
NAVBAR_BUTTON_CANCEL,
NAVBAR_BUTTON_NEXT,
diff --git a/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m
b/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m
index 731de08..e6c2802 100644
--- a/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m
+++ b/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m
@@ -44,6 +44,7 @@
@property (strong, nonatomic) WikiGlyphButton *buttonArrowLeft;
@property (strong, nonatomic) WikiGlyphButton *buttonArrowRight;
@property (strong, nonatomic) WikiGlyphButton *buttonMagnify;
+@property (strong, nonatomic) WikiGlyphButton *buttonReload;
@property (strong, nonatomic) WikiGlyphButton *buttonBlank;
@property (strong, nonatomic) WikiGlyphButton *buttonCancel;
@property (strong, nonatomic) WikiGlyphButton *buttonTrash;
@@ -253,6 +254,7 @@
self.buttonW = getWikiGlyphButton(WIKIGLYPH_W,
MWLocalizedString(@"menu-w-accessibility-label", nil),
NAVBAR_BUTTON_LOGO_W, size, 2.0f);
self.buttonTOC = getWikiGlyphButton(WIKIGLYPH_TOC_COLLAPSED,
MWLocalizedString(@"menu-toc-accessibility-label", nil), NAVBAR_BUTTON_TOC,
size, 2.0f);
self.buttonMagnify = getWikiGlyphButton(WIKIGLYPH_MAGNIFY,
MWLocalizedString(@"menu-search-accessibility-label", nil),
NAVBAR_BUTTON_MAGNIFY, size, 1.0f);
+ self.buttonReload = getWikiGlyphButton(WIKIGLYPH_RELOAD,
MWLocalizedString(@"menu-reload-accessibility-label", nil),
NAVBAR_BUTTON_RELOAD, size, 1.0f);
self.buttonBlank = getWikiGlyphButton(@"", @"",
NAVBAR_BUTTON_BLANK, size, 0.0f);
self.buttonCancel = getWikiGlyphButton(@"",
MWLocalizedString(@"menu-cancel-accessibility-label", nil),
NAVBAR_BUTTON_CANCEL, size, 2.0f);
self.buttonTrash = getWikiGlyphButton(WIKIGLYPH_TRASH,
MWLocalizedString(@"menu-trash-accessibility-label", nil),
NAVBAR_BUTTON_TRASH, size, 2.0f);
@@ -314,6 +316,7 @@
[self.navBarContainer addSubview:self.buttonW];
[self.navBarContainer addSubview:self.buttonTOC];
[self.navBarContainer addSubview:self.buttonMagnify];
+ [self.navBarContainer addSubview:self.buttonReload];
[self.navBarContainer addSubview:self.buttonBlank];
[self.navBarContainer addSubview:self.buttonCancel];
[self.navBarContainer addSubview:self.buttonTrash];
@@ -360,6 +363,7 @@
@"NAVBAR_BUTTON_LOGO_W": self.buttonW,
@"NAVBAR_BUTTON_TOC": self.buttonTOC,
@"NAVBAR_BUTTON_MAGNIFY": self.buttonMagnify,
+ @"NAVBAR_BUTTON_RELOAD": self.buttonReload,
@"NAVBAR_BUTTON_BLANK": self.buttonBlank,
@"NAVBAR_BUTTON_CANCEL": self.buttonCancel,
@"NAVBAR_BUTTON_NEXT": self.buttonNext,
@@ -475,10 +479,13 @@
@"H:|-(6)-[NAVBAR_BUTTON_ARROW_LEFT(50)][NAVBAR_LABEL]-(56)-|";
break;
case NAVBAR_MODE_PAGES_HISTORY:
- case NAVBAR_MODE_PAGES_SAVED:
self.navBarSubViewsHorizontalVFLString =
@"H:|-(6)-[NAVBAR_BUTTON_X(50)]-(10)-[NAVBAR_LABEL]-(10)-[NAVBAR_BUTTON_TRASH(50@250)]-(6)-|";
break;
+ case NAVBAR_MODE_PAGES_SAVED:
+ self.navBarSubViewsHorizontalVFLString =
+
@"H:|-(6)-[NAVBAR_BUTTON_X(50)]-(10)-[NAVBAR_LABEL]-(10)-[NAVBAR_BUTTON_RELOAD(50@250)]-(6)-|";
+ break;
case NAVBAR_MODE_X_WITH_TEXT_FIELD:
self.navBarSubViewsHorizontalVFLString =
@"H:|-(6)-[NAVBAR_BUTTON_X(50)][NAVBAR_TEXT_FIELD]-(16)-|";
diff --git a/wikipedia/View Controllers/SavedPages/SavedPagesViewController.h
b/wikipedia/View Controllers/SavedPages/SavedPagesViewController.h
index 325b4b8..a1f1ba6 100644
--- a/wikipedia/View Controllers/SavedPages/SavedPagesViewController.h
+++ b/wikipedia/View Controllers/SavedPages/SavedPagesViewController.h
@@ -5,7 +5,7 @@
#import "TopMenuViewController.h"
#import "PullToRefreshViewController.h"
-@interface SavedPagesViewController : PullToRefreshViewController
<UITableViewDataSource, UITableViewDelegate, UIAlertViewDelegate>
+@interface SavedPagesViewController : UIViewController <UITableViewDataSource,
UITableViewDelegate, UIAlertViewDelegate>
@property (nonatomic) NavBarMode navBarMode;
@property (weak, nonatomic) IBOutlet UIView *emptyOverlay;
diff --git a/wikipedia/View Controllers/SavedPages/SavedPagesViewController.m
b/wikipedia/View Controllers/SavedPages/SavedPagesViewController.m
index f864400..11209b3 100644
--- a/wikipedia/View Controllers/SavedPages/SavedPagesViewController.m
+++ b/wikipedia/View Controllers/SavedPages/SavedPagesViewController.m
@@ -18,13 +18,22 @@
#import "SavedPagesFunnel.h"
#import "NSObject+ConstraintsScale.h"
#import "PaddedLabel.h"
+#import "QueuesSingleton.h"
+#import "SavedArticlesFetcher.h"
+#import "WMFBorderButton.h"
+#import "WMFProgressLineView.h"
+#import <Masonry/Masonry.h>
#define SAVED_PAGES_TITLE_TEXT_COLOR [UIColor colorWithWhite:0.0f alpha:0.7f]
#define SAVED_PAGES_TEXT_COLOR [UIColor colorWithWhite:0.0f alpha:1.0f]
#define SAVED_PAGES_LANGUAGE_COLOR [UIColor colorWithWhite:0.0f alpha:0.4f]
#define SAVED_PAGES_RESULT_HEIGHT (116.0 * MENUS_SCALE_MULTIPLIER)
-@interface SavedPagesViewController ()
+static NSString* const WMFSavedPagesDidShowCancelRefreshAlert =
@"WMFSavedPagesDidShowCancelRefreshAlert";
+
+static SavedArticlesFetcher* _sharedFetcher = nil;
+
+@interface SavedPagesViewController ()<SavedArticlesFetcherDelegate>
{
MWKSavedPageList *savedPageList;
MWKUserDataStore *userDataStore;
@@ -40,9 +49,34 @@
@property (strong, nonatomic) IBOutlet UIView *emptyContainerView;
+@property (strong, nonatomic) WMFProgressLineView *progressView;
+@property (strong, nonatomic) WMFBorderButton *cancelButton;
+
@end
@implementation SavedPagesViewController
+
+#pragma mark - Shared Access
+
++ (SavedArticlesFetcher*)sharedFetcher{
+
+ return _sharedFetcher;
+}
+
++ (void)setSharedFetcher:(SavedArticlesFetcher*)fetcher{
+
+ _sharedFetcher = fetcher;
+}
+
+#pragma mark - Lifecycle
+
+- (void)dealloc{
+
+ [[self class] sharedFetcher].fetchFinishedDelegate = nil;
+}
+
+#pragma mark - NavBar
+
-(NavBarMode)navBarMode
{
@@ -53,6 +87,37 @@
{
return MWLocalizedString(@"saved-pages-title", nil);
}
+
+- (MenuButton*)reloadButton{
+
+ return (MenuButton *)[self.topMenuViewController
getNavBarItem:NAVBAR_BUTTON_RELOAD];
+}
+
+- (WMFBorderButton*)cancelButton{
+
+ if(!_cancelButton){
+
+ WMFBorderButton* button = [WMFBorderButton standardBorderButton];
+ [button setTitle:MWLocalizedString(@"saved-pages-clear-cancel", nil)
forState:UIControlStateNormal];
+ [button addTarget:self action:@selector(cancelRefresh)
forControlEvents:UIControlEventTouchUpInside];
+
+ _cancelButton = button;
+ }
+
+ return _cancelButton;
+}
+
+- (WMFProgressLineView*)progressView{
+
+ if(!_progressView){
+
+ WMFProgressLineView* progress = [[WMFProgressLineView alloc]
initWithFrame:CGRectZero];
+ _progressView = progress;
+ }
+
+ return _progressView;
+}
+
#pragma mark - Memory
@@ -72,12 +137,11 @@
switch (tappedItem.tag) {
case NAVBAR_BUTTON_X:
- case NAVBAR_LABEL:
[self popModal];
-
+ case NAVBAR_LABEL:
break;
- case NAVBAR_BUTTON_TRASH:
- [self showDeleteAllDialog];
+ case NAVBAR_BUTTON_RELOAD:
+ [self startRefresh];
break;
default:
break;
@@ -89,7 +153,7 @@
return NO;
}
-#pragma mark - View lifecycle
+#pragma mark - UIViewController
-(void)viewWillDisappear:(BOOL)animated
{
@@ -110,6 +174,17 @@
selector:
@selector(navItemTappedNotification:)
name: @"NavItemTapped"
object: nil];
+
+
+ SavedArticlesFetcher* fetcher = [[self class] sharedFetcher];
+
+ if(fetcher){
+
+ fetcher.fetchFinishedDelegate = self;
+ [self showCancelButton];
+ [self showProgressView];
+ }
+
}
- (void)viewDidLoad
@@ -122,13 +197,9 @@
self.funnel = [[SavedPagesFunnel alloc] init];
self.navigationItem.hidesBackButton = YES;
-
- // Uncomment the following line to preserve selection between
presentations.
- // self.clearsSelectionOnViewWillAppear = NO;
-
- // Uncomment the following line to display an Edit button in the
navigation bar for this view controller.
- // self.navigationItem.rightBarButtonItem = self.editButtonItem;
-
+
+ self.tableView.rowHeight = SAVED_PAGES_RESULT_HEIGHT;
+
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10.0 *
MENUS_SCALE_MULTIPLIER, 5.0 * MENUS_SCALE_MULTIPLIER)];
self.tableView.tableHeaderView = headerView;
@@ -146,10 +217,11 @@
self.emptyTitle.font = [UIFont boldSystemFontOfSize:17.0 *
MENUS_SCALE_MULTIPLIER];
self.emptyDescription.font = [UIFont systemFontOfSize:14.0 *
MENUS_SCALE_MULTIPLIER];
+
}
-#pragma mark - Table view data source
+#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
@@ -221,24 +293,6 @@
return cell;
}
-- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
- MWKSavedPageEntry *savedEntry = [savedPageList entryAtIndex:indexPath.row];
-
- [NAV loadArticleWithTitle: savedEntry.title
- animated: YES
- discoveryMethod: MWK_DISCOVERY_METHOD_SAVED
- popToWebVC: NO];
-
- [self popModalToRoot];
-}
-
-- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- return SAVED_PAGES_RESULT_HEIGHT;
-}
-
-#pragma mark - Delete
-
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath
*)indexPath {
return YES;
}
@@ -250,13 +304,108 @@
}
}
+
+#pragma mark - UITableViewDelegate
+
+- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+ MWKSavedPageEntry *savedEntry = [savedPageList entryAtIndex:indexPath.row];
+
+ [NAV loadArticleWithTitle: savedEntry.title
+ animated: YES
+ discoveryMethod: MWK_DISCOVERY_METHOD_SAVED
+ popToWebVC: NO];
+
+ [self popModalToRoot];
+}
+
+#pragma mark - UI Updates
+
+- (void)showCancelButton{
+
+ self.cancelButton.alpha = 1.0;
+ [self.topMenuViewController.view addSubview:self.cancelButton];
+
+ MenuButton *reloadButton = [self reloadButton];
+
+ [self.cancelButton mas_remakeConstraints:^(MASConstraintMaker *make) {
+
+ make.right.equalTo(reloadButton.mas_right);
+ make.centerY.equalTo(reloadButton.mas_centerY);
+ }];
+}
+
+- (void)hideCancelButton{
+
+ self.cancelButton.alpha = 0.0;
+}
+
+- (void)showRefreshButton{
+
+ MenuButton *reloadButton = [self reloadButton];
+ reloadButton.alpha = 1.0;
+}
+
+- (void)hideRefreshButton{
+
+ MenuButton *reloadButton = [self reloadButton];
+ reloadButton.clipsToBounds = NO;
+ reloadButton.alpha = 0.0;
+}
+
+- (void)showProgressView{
+
+ self.progressView.alpha = 1.0;
+ [self.topMenuViewController.view addSubview:self.progressView];
+
+ [self.progressView mas_remakeConstraints:^(MASConstraintMaker *make) {
+
+ make.top.equalTo(self.topMenuViewController.view.mas_bottom);
+ make.left.equalTo(self.topMenuViewController.view.mas_left);
+ make.right.equalTo(self.topMenuViewController.view.mas_right);
+ make.height.equalTo(@2.0);
+ }];
+}
+
+- (void)hideProgressView{
+
+ self.progressView.alpha = 0.0;
+}
+
+-(void)setEmptyOverlayAndTrashIconVisibility
+{
+ BOOL savedPageFound = (savedPageList.length > 0);
+
+ self.emptyOverlay.hidden = savedPageFound;
+
+ MenuButton *reloadButton = [self reloadButton];
+ reloadButton.alpha = savedPageFound ? 1.0 : 0.0;
+}
+
+- (void)showCancelRefreshAlertIfFirstTime{
+
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+
+ BOOL didShowAlert = [defaults
boolForKey:WMFSavedPagesDidShowCancelRefreshAlert];
+
+ if(!didShowAlert){
+
+ UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:MWLocalizedString(@"saved-pages-refresh-cancel-alert-title", nil)
message:MWLocalizedString(@"saved-pages-refresh-cancel-alert-message", nil)
delegate:nil
cancelButtonTitle:MWLocalizedString(@"saved-pages-refresh-cancel-alert-button",
nil) otherButtonTitles:nil];
+
+ [alert show];
+
+ [defaults setBool:YES forKey:WMFSavedPagesDidShowCancelRefreshAlert];
+ }
+}
+
+#pragma mrk - Delete
+
-(void)deleteSavedPageForIndexPath:(NSIndexPath *)indexPath
{
MWKSavedPageEntry *savedEntry = [savedPageList entryAtIndex:indexPath.row];
if (savedEntry) {
[self.tableView beginUpdates];
-
+
[self.tableView deleteRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
// Delete the saved record.
@@ -264,12 +413,12 @@
[userDataStore save];
[self.tableView endUpdates];
-
+
[self setEmptyOverlayAndTrashIconVisibility];
[self.funnel logDelete];
}
-
+
// Remove any orphaned images.
DataHousekeeping *dataHouseKeeping = [[DataHousekeeping alloc] init];
[dataHouseKeeping performHouseKeeping];
@@ -281,7 +430,7 @@
{
[savedPageList removeAllEntries];
[userDataStore save];
-
+
// Remove any orphaned images.
DataHousekeeping *dataHouseKeeping = [[DataHousekeeping alloc] init];
[dataHouseKeeping performHouseKeeping];
@@ -291,16 +440,6 @@
[self setEmptyOverlayAndTrashIconVisibility];
[NAV loadTodaysArticleIfNoCoreDataForCurrentArticle];
-}
-
--(void)setEmptyOverlayAndTrashIconVisibility
-{
- BOOL savedPageFound = (savedPageList.length > 0);
-
- self.emptyOverlay.hidden = savedPageFound;
-
- MenuButton *trashButton = (MenuButton *)[self.topMenuViewController
getNavBarItem:NAVBAR_BUTTON_TRASH];
- trashButton.alpha = savedPageFound ? 1.0 : 0.0;
}
- (void)alertView:(UIAlertView *)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex
@@ -321,11 +460,93 @@
[dialog show];
}
-#pragma mark - Pull to refresh
-- (UIScrollView *)refreshScrollView
-{
- return self.tableView;
+#pragma mark - Refresh
+
+- (void)startRefresh{
+
+ [[QueuesSingleton sharedInstance].savedPagesFetchManager.operationQueue
cancelAllOperations];
+
+ SavedArticlesFetcher* fetcher = [[SavedArticlesFetcher alloc]
initAndFetchArticlesForSavedPageList:savedPageList
inDataStore:userDataStore.dataStore withManager:[QueuesSingleton
sharedInstance].savedPagesFetchManager thenNotifyDelegate:self];
+
+ [[self class] setSharedFetcher:fetcher];
+
+ self.progressView.progress = 0.0;
+
+ [UIView animateWithDuration:0.25 animations:^{
+
+ [self hideRefreshButton];
+ [self showProgressView];
+
+ } completion:^(BOOL finished) {
+
+ [UIView animateWithDuration:0.25 animations:^{
+
+ [self showCancelButton];
+ }];
+ }];
}
+- (void)resumeRefresh{
+
+ self.progressView.progress = 0.0;
+ [self showProgressView];
+ [self showCancelButton];
+}
+
+- (void)finishRefresh{
+
+ [[self class] sharedFetcher].fetchFinishedDelegate = nil;
+ [[self class] setSharedFetcher:nil];
+
+ [UIView animateWithDuration:0.25 animations:^{
+
+ [self hideProgressView];
+ [self hideCancelButton];
+
+ } completion:^(BOOL finished) {
+
+ [UIView animateWithDuration:0.25 animations:^{
+
+ [self showRefreshButton];
+ }];
+
+ self.progressView.progress = 0.0;
+ }];
+}
+
+- (void)cancelRefresh{
+
+ [[QueuesSingleton sharedInstance].savedPagesFetchManager.operationQueue
cancelAllOperations];
+
+ [self finishRefresh];
+
+ [self showCancelRefreshAlertIfFirstTime];
+}
+
+#pragma mark - SavedArticlesFetcherDelegate
+
+- (void)savedArticlesFetcher:(SavedArticlesFetcher *)savedArticlesFetcher
didFetchArticle:(MWKArticle *)article remainingArticles:(NSInteger)remaining
totalArticles:(NSInteger)total status:(FetchFinalStatus)status error:(NSError
*)error{
+
+ CGFloat progress = 1.0-(CGFloat)((CGFloat)remaining/(CGFloat)total);
+ [self.progressView setProgress:progress animated:YES];
+
+}
+
+- (void)fetchFinished:(id)sender fetchedData:(id)fetchedData
status:(FetchFinalStatus)status error:(NSError *)error{
+
+ __weak __typeof(self)weakSelf = self;
+
+ [self.progressView setProgress:1.0 animated:YES completion:^{
+
+ __strong __typeof(weakSelf)strongSelf = weakSelf;
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 *
NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ [strongSelf finishRefresh];
+ });
+
+ }];
+}
+
+
@end
diff --git a/wikipedia/en.lproj/Localizable.strings
b/wikipedia/en.lproj/Localizable.strings
index 65e3048..1314d30 100644
--- a/wikipedia/en.lproj/Localizable.strings
+++ b/wikipedia/en.lproj/Localizable.strings
@@ -130,7 +130,10 @@
"saved-pages-clear-confirmation-heading" = "Delete all saved items?";
"saved-pages-clear-confirmation-sub-heading" = "This action cannot be undone!";
"saved-pages-clear-cancel" = "Cancel";
-"saved-pages-clear-delete-all" = "Delete All";
+"saved-pages-refresh-cancel-alert-title" = "Update cancelled";
+"saved-pages-refresh-cancel-alert-message" = "Wikipedia articles are updated
all the time. Tap refresh to get the latest versions of all the articles.";
+"saved-pages-refresh-cancel-alert-button" = "Got it";
+
"page-history-title" = "Article history";
"page-history-downloading" = "Loading article history...";
@@ -250,6 +253,7 @@
"menu-w-accessibility-label" = "Menu";
"menu-toc-accessibility-label" = "Contents";
"menu-search-accessibility-label" = "Search";
+"menu-reload-accessibility-label" = "Reload";
"menu-cancel-accessibility-label" = "Cancel";
"menu-share-accessibility-label" = "Share";
"menu-more-accessibility-label" = "More settings";
diff --git a/wikipedia/qqq.lproj/Localizable.strings
b/wikipedia/qqq.lproj/Localizable.strings
index 62d1c78..191f2bf 100644
--- a/wikipedia/qqq.lproj/Localizable.strings
+++ b/wikipedia/qqq.lproj/Localizable.strings
@@ -126,7 +126,9 @@
"saved-pages-clear-confirmation-heading" = "Heading text of delete all
confirmation dialog";
"saved-pages-clear-confirmation-sub-heading" = "Sub-heading text of delete all
confirmation dialog";
"saved-pages-clear-cancel" = "Button text for cancelling delete all
action\n{{Identical|Cancel}}";
-"saved-pages-clear-delete-all" = "Button text for confirming delete all
action\n{{Identical|Delete all}}";
+"saved-pages-refresh-cancel-alert-title" = "Title of alert shown when a user
first cancels a refresh of saved pages";
+"saved-pages-refresh-cancel-alert-message" = "Message of alert shown when a
user first cancels a refresh of saved pages";
+"saved-pages-refresh-cancel-alert-button" = "Butto confirmation text of alert
shown when a user first cancels a refresh of saved pages";
"page-history-title" = "Header text for Page History
interface.\n{{Identical|Page history}}";
"page-history-downloading" = "Alert text shown when obtaining revision history
of an article";
"navbar-title-mode-edit-wikitext" = "Header text shown when wikitext is being
edited.\n{{Identical|Edit}}";
@@ -225,6 +227,7 @@
"menu-w-accessibility-label" = "Accessible label text for toolbar 'W' menu
icon button\n{{Identical|Menu}}";
"menu-toc-accessibility-label" = "Accessible label text for toolbar table of
contents icon button\n{{Identical|Content}}";
"menu-search-accessibility-label" = "Accessible label text for toolbar search
icon button\n{{Identical|Search}}";
+"menu-reload-accessibility-label" = "Accessible label text for toolbar reload
icon button";
"menu-cancel-accessibility-label" = "Accessible label text for toolbar cancel
button\n{{Identical|Cancel}}";
"menu-share-accessibility-label" = "Accessible label text for toolbar share
button\n{{Identical|Share}}";
"menu-more-accessibility-label" = "Accessible label for more/... button in 'W'
menu";
--
To view, visit https://gerrit.wikimedia.org/r/191359
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0d03cec85081738211bb120593cd2777ba8518d8
Gerrit-PatchSet: 1
Gerrit-Project: apps/ios/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Fjalapeno <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits