Mhurd has uploaded a new change for review.

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

Change subject: Anonymous editing killswitch.
......................................................................

Anonymous editing killswitch.

Syncs with config/ios.json at most once a day. Adjusts saving
interface to hide anon saving option if ios.json has flag for
disabling anon editing.

The periodic sync code is done in generic fashion to make
future sync between server and bundled app json files
painless.

Change-Id: Ia64c060806c14cbf08cacb3168af8f471c8de048
---
M Wikipedia.xcodeproj/project.pbxproj
A wikipedia/BundledJson/BundledJson.h
A wikipedia/BundledJson/BundledJson.m
A wikipedia/BundledJson/BundledJsonEnum.h
A wikipedia/BundledPaths/BundledPaths.h
A wikipedia/BundledPaths/BundledPaths.m
A wikipedia/BundledPaths/BundledPathsEnum.h
A wikipedia/Data/Operations/ConfigFileSyncOp.h
A wikipedia/Data/Operations/ConfigFileSyncOp.m
M wikipedia/Queues/QueuesSingleton.h
M wikipedia/Queues/QueuesSingleton.m
M wikipedia/Session/SessionSingleton.h
M wikipedia/Session/SessionSingleton.m
M wikipedia/View Controllers/Languages/LanguagesTableVC.m
M wikipedia/View Controllers/Preview/PreviewChoicesMenuView.m
M wikipedia/View Controllers/Preview/PreviewChoicesMenuView.xib
M wikipedia/View Controllers/TopNav/NavController.m
M wikipedia/View Controllers/WebView/WebViewController.m
18 files changed, 382 insertions(+), 43 deletions(-)


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

diff --git a/Wikipedia.xcodeproj/project.pbxproj 
b/Wikipedia.xcodeproj/project.pbxproj
index 262a856..04abf62 100644
--- a/Wikipedia.xcodeproj/project.pbxproj
+++ b/Wikipedia.xcodeproj/project.pbxproj
@@ -43,6 +43,10 @@
                043DAC4B1901C3EE001CD17C /* CreditsViewController.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = 043DAC4A1901C3EE001CD17C /* 
CreditsViewController.m */; };
                043F18E118D9691D00D8489A /* TopActionSheetLabel.m in Sources */ 
= {isa = PBXBuildFile; fileRef = 043F18DC18D9691D00D8489A /* 
TopActionSheetLabel.m */; };
                043F18E518D9691D00D8489A /* 
UINavigationController+TopActionSheet.m in Sources */ = {isa = PBXBuildFile; 
fileRef = 043F18E018D9691D00D8489A /* UINavigationController+TopActionSheet.m 
*/; };
+               044213C5191C3A91006C03BF /* config in Resources */ = {isa = 
PBXBuildFile; fileRef = 044213C4191C3A91006C03BF /* config */; };
+               044213C8191C3C2A006C03BF /* ConfigFileSyncOp.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 044213C7191C3C2A006C03BF /* ConfigFileSyncOp.m 
*/; };
+               044213D0191D6F43006C03BF /* BundledPaths.m in Sources */ = {isa 
= PBXBuildFile; fileRef = 044213CF191D6F43006C03BF /* BundledPaths.m */; };
+               044213D4191D70E9006C03BF /* BundledJson.m in Sources */ = {isa 
= PBXBuildFile; fileRef = 044213D3191D70E9006C03BF /* BundledJson.m */; };
                0442F57B19006DCC00F55DF9 /* PageHistoryLabel.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 0442F57A19006DCC00F55DF9 /* PageHistoryLabel.m 
*/; };
                0442F57E190071A100F55DF9 /* WikiFont.ttf in Resources */ = {isa 
= PBXBuildFile; fileRef = 0442F57D190071A100F55DF9 /* WikiFont.ttf */; };
                0447862F185145090050563B /* HistoryResultCell.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 04478621185145090050563B /* HistoryResultCell.m 
*/; };
@@ -230,6 +234,15 @@
                043F18DF18D9691D00D8489A /* 
UINavigationController+TopActionSheet.h */ = {isa = PBXFileReference; 
fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
"UINavigationController+TopActionSheet.h"; sourceTree = "<group>"; };
                043F18E018D9691D00D8489A /* 
UINavigationController+TopActionSheet.m */ = {isa = PBXFileReference; 
fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = 
"UINavigationController+TopActionSheet.m"; sourceTree = "<group>"; };
                043F18F118DCDD3A00D8489A /* WMF_Colors.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WMF_Colors.h; sourceTree = "<group>"; };
+               044213C4191C3A91006C03BF /* config */ = {isa = 
PBXFileReference; lastKnownFileType = folder; path = config; sourceTree = 
"<group>"; };
+               044213C6191C3C2A006C03BF /* ConfigFileSyncOp.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
ConfigFileSyncOp.h; sourceTree = "<group>"; };
+               044213C7191C3C2A006C03BF /* ConfigFileSyncOp.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= ConfigFileSyncOp.m; sourceTree = "<group>"; };
+               044213CE191D6F43006C03BF /* BundledPaths.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
BundledPaths.h; sourceTree = "<group>"; };
+               044213CF191D6F43006C03BF /* BundledPaths.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= BundledPaths.m; sourceTree = "<group>"; };
+               044213D2191D70E9006C03BF /* BundledJson.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
BundledJson.h; sourceTree = "<group>"; };
+               044213D3191D70E9006C03BF /* BundledJson.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= BundledJson.m; sourceTree = "<group>"; };
+               044213D5191D7FEA006C03BF /* BundledJsonEnum.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
BundledJsonEnum.h; sourceTree = "<group>"; };
+               044213D6191D7FFC006C03BF /* BundledPathsEnum.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
BundledPathsEnum.h; sourceTree = "<group>"; };
                0442F57919006DCC00F55DF9 /* PageHistoryLabel.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
PageHistoryLabel.h; sourceTree = "<group>"; };
                0442F57A19006DCC00F55DF9 /* PageHistoryLabel.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= PageHistoryLabel.m; sourceTree = "<group>"; };
                0442F57D190071A100F55DF9 /* WikiFont.ttf */ = {isa = 
PBXFileReference; lastKnownFileType = file; path = WikiFont.ttf; sourceTree = 
"<group>"; };
@@ -708,6 +721,26 @@
                        path = TopActionSheet;
                        sourceTree = "<group>";
                };
+               044213CD191D6F43006C03BF /* BundledPaths */ = {
+                       isa = PBXGroup;
+                       children = (
+                               044213D6191D7FFC006C03BF /* BundledPathsEnum.h 
*/,
+                               044213CE191D6F43006C03BF /* BundledPaths.h */,
+                               044213CF191D6F43006C03BF /* BundledPaths.m */,
+                       );
+                       path = BundledPaths;
+                       sourceTree = "<group>";
+               };
+               044213D1191D70BC006C03BF /* BundledJson */ = {
+                       isa = PBXGroup;
+                       children = (
+                               044213D5191D7FEA006C03BF /* BundledJsonEnum.h 
*/,
+                               044213D2191D70E9006C03BF /* BundledJson.h */,
+                               044213D3191D70E9006C03BF /* BundledJson.m */,
+                       );
+                       path = BundledJson;
+                       sourceTree = "<group>";
+               };
                0442F57C1900718600F55DF9 /* Fonts */ = {
                        isa = PBXGroup;
                        children = (
@@ -999,6 +1032,8 @@
                04D149E5188889CA006B4104 /* Operations */ = {
                        isa = PBXGroup;
                        children = (
+                               044213C6191C3C2A006C03BF /* ConfigFileSyncOp.h 
*/,
+                               044213C7191C3C2A006C03BF /* ConfigFileSyncOp.m 
*/,
                                04F27B7918FE19B700EDD838 /* PageHistoryOp.h */,
                                04F27B7A18FE19B700EDD838 /* PageHistoryOp.m */,
                                0406CEF418F8C390007EE43E /* LogEventOp.h */,
@@ -1197,7 +1232,10 @@
                                D469889318B52DA200DBE014 /* Main_iPhone.strings 
*/,
                                D46CD8C218A1AC4F0042959E /* Localizable.strings 
*/,
                                045A9F0C18F6090E0057EA85 /* assets */,
+                               044213D1191D70BC006C03BF /* BundledJson */,
+                               044213CD191D6F43006C03BF /* BundledPaths */,
                                04C43AB7183442FC006C643B /* Categories */,
+                               044213C4191C3A91006C03BF /* config */,
                                040E5C50184673F2007AFE6F /* Data */,
                                04292FFB185FC026002A13FC /* Defines */,
                                0442F57C1900718600F55DF9 /* Fonts */,
@@ -1401,6 +1439,7 @@
                                04CF1CB6187C8F4400E9516F /* Languages in 
Resources */,
                                0466F44F183A30CC00EA1FD7 /* 
logo-search-placeholder.png in Resources */,
                                D46CD8C418A1AC4F0042959E /* InfoPlist.strings 
in Resources */,
+                               044213C5191C3A91006C03BF /* config in Resources 
*/,
                                D4991454181D51DE00E6073C /* Images.xcassets in 
Resources */,
                                D499144C181D51DE00E6073C /* 
Main_iPhone.storyboard in Resources */,
                                D46CD8C518A1AC4F0042959E /* Localizable.strings 
in Resources */,
@@ -1457,6 +1496,7 @@
                                044BD6B618849AD000FFE4BE /* 
SectionEditorViewController.m in Sources */,
                                04D34DAB1863D2D600610A87 /* TFHpple.m in 
Sources */,
                                0429301018604898002A13FC /* 
SavedPagesViewController.m in Sources */,
+                               044213D4191D70E9006C03BF /* BundledJson.m in 
Sources */,
                                04D149DF18877343006B4104 /* 
UIViewController+Alert.m in Sources */,
                                04FD6C7A184EBFCD002CA02F /* 
ArticleData.xcdatamodeld in Sources */,
                                048A26771906268100395F53 /* PaddedLabel.m in 
Sources */,
@@ -1492,6 +1532,7 @@
                                040E533C1885FB4E00AFBFE9 /* ImageData.m in 
Sources */,
                                04DB0BE618BC2E1E00B4BCF3 /* CaptchaResetOp.m in 
Sources */,
                                0415581C18ADFA5D00B81A59 /* UIImage+ColorMask.m 
in Sources */,
+                               044213C8191C3C2A006C03BF /* ConfigFileSyncOp.m 
in Sources */,
                                04A70FD7185BB6C300E24515 /* URLCache.m in 
Sources */,
                                04992BC018B687AF00A6C22B /* SearchOp.m in 
Sources */,
                                041A3B5E18E11ED90079FF1C /* LanguagesCell.m in 
Sources */,
@@ -1552,6 +1593,7 @@
                                0442F57B19006DCC00F55DF9 /* PageHistoryLabel.m 
in Sources */,
                                0447862F185145090050563B /* HistoryResultCell.m 
in Sources */,
                                04B0EA45190AFDD8007458AF /* ArticleImporter.m 
in Sources */,
+                               044213D0191D6F43006C03BF /* BundledPaths.m in 
Sources */,
                                0406CEF618F8C390007EE43E /* LogEventOp.m in 
Sources */,
                                0476967C18BBFC9400071963 /* AccountCreationOp.m 
in Sources */,
                        );
diff --git a/wikipedia/BundledJson/BundledJson.h 
b/wikipedia/BundledJson/BundledJson.h
new file mode 100644
index 0000000..1935ae1
--- /dev/null
+++ b/wikipedia/BundledJson/BundledJson.h
@@ -0,0 +1,15 @@
+//  Created by Monte Hurd on 5/9/14.
+//  Copyright (c) 2013 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
+
+#import "BundledPathsEnum.h"
+#import "BundledJsonEnum.h"
+
+@interface BundledJson : NSObject
+
++ (NSMutableDictionary *)dictionaryFromBundledJsonFile:(BundledJsonFile)file;
+
++ (NSMutableArray *)arrayFromBundledJsonFile:(BundledJsonFile)file;
+
++ (BOOL)isRefreshNeededForBundledJsonFile:(BundledJsonFile)file 
maxAge:(CGFloat)maxAge;
+
+@end
diff --git a/wikipedia/BundledJson/BundledJson.m 
b/wikipedia/BundledJson/BundledJson.m
new file mode 100644
index 0000000..8ed7271
--- /dev/null
+++ b/wikipedia/BundledJson/BundledJson.m
@@ -0,0 +1,58 @@
+//  Created by Monte Hurd on 5/9/14.
+//  Copyright (c) 2013 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
+
+#import "BundledJson.h"
+#import "BundledPaths.h"
+
+@implementation BundledJson
+
++ (NSMutableDictionary *)dictionaryFromBundledJsonFile:(BundledJsonFile)file
+{
+    NSError *error = nil;
+    NSData *fileData = [NSData dataWithContentsOfFile:[BundledPaths 
bundledJsonFilePath:file] options:0 error:&error];
+    if (error) return @{}.mutableCopy;
+    error = nil;
+    NSMutableDictionary *result = [NSJSONSerialization 
JSONObjectWithData:fileData options:0 error:&error];
+    return (error) ? @{}.mutableCopy: [result mutableCopy];
+}
+
++ (NSMutableArray *)arrayFromBundledJsonFile:(BundledJsonFile)file
+{
+    NSError *error = nil;
+    NSData *fileData = [NSData dataWithContentsOfFile:[BundledPaths 
bundledJsonFilePath:file] options:0 error:&error];
+    if (error) return [@[] mutableCopy];
+    error = nil;
+    NSArray *result = [NSJSONSerialization JSONObjectWithData:fileData 
options:0 error:&error];
+    return (error) ? [@[] mutableCopy]: [result mutableCopy];
+}
+
+// Returns YES if the local version of the config file doesn't exist or is 
older than maxAge.
++ (BOOL)isRefreshNeededForBundledJsonFile:(BundledJsonFile)file 
maxAge:(CGFloat)maxAge
+{
+    NSString *path = [BundledPaths bundledJsonFilePath:file];
+    
+    BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:path 
isDirectory:NO];
+    if (!fileExists){
+        NSLog(@"REFRESH NEEDED");
+        return YES;
+    }
+    
+    NSDate *lastModified = nil;
+    NSError *error = nil;
+    NSURL *url = [NSURL fileURLWithPath:path];
+    [url getResourceValue: &lastModified
+                   forKey: NSURLContentModificationDateKey
+                    error: &error];
+    if (!error){
+        NSTimeInterval currentAge = [[NSDate date] 
timeIntervalSinceDate:lastModified];
+        NSLog(@"currentAge = %f maxAge = %f", currentAge, maxAge);
+        if (currentAge > maxAge){
+            NSLog(@"REFRESH NEEDED");
+            return YES;
+        }
+    }
+    NSLog(@"NO REFRESH NEEDED");
+    return NO;
+}
+
+@end
diff --git a/wikipedia/BundledJson/BundledJsonEnum.h 
b/wikipedia/BundledJson/BundledJsonEnum.h
new file mode 100644
index 0000000..e301b98
--- /dev/null
+++ b/wikipedia/BundledJson/BundledJsonEnum.h
@@ -0,0 +1,7 @@
+
+typedef NS_ENUM(NSUInteger, BundledJsonFile) {
+    BUNDLED_JSON_UNDEFINED = 0,
+    BUNDLED_JSON_CONFIG = 1,
+    BUNDLED_JSON_LANGUAGES = 2,
+    BUNDLED_JSON_MAINPAGES = 3
+};
diff --git a/wikipedia/BundledPaths/BundledPaths.h 
b/wikipedia/BundledPaths/BundledPaths.h
new file mode 100644
index 0000000..7601df1
--- /dev/null
+++ b/wikipedia/BundledPaths/BundledPaths.h
@@ -0,0 +1,12 @@
+//  Created by Monte Hurd on 5/9/14.
+//  Copyright (c) 2013 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
+
+#import "BundledPathsEnum.h"
+#import "BundledJsonEnum.h"
+
+@interface BundledPaths : NSObject
+
++ (NSString *)bundledJsonFilePath:(BundledJsonFile)file;
++ (NSURL *)bundledJsonFileRemoteUrl:(BundledJsonFile)file;
+
+@end
diff --git a/wikipedia/BundledPaths/BundledPaths.m 
b/wikipedia/BundledPaths/BundledPaths.m
new file mode 100644
index 0000000..2d95c55
--- /dev/null
+++ b/wikipedia/BundledPaths/BundledPaths.m
@@ -0,0 +1,92 @@
+//  Created by Monte Hurd on 5/9/14.
+//  Copyright (c) 2013 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
+
+#import "BundledPaths.h"
+#import "BundledJson.h"
+
+@implementation BundledPaths
+
++ (NSString *)nameForFile:(BundledJsonFile)bundledJsonFile
+{
+    switch (bundledJsonFile) {
+        case BUNDLED_JSON_CONFIG:
+            return @"ios.json";
+            break;
+        case BUNDLED_JSON_LANGUAGES:
+            return @"languages.json";
+            break;
+        case BUNDLED_JSON_MAINPAGES:
+            return @"mainpages.json";
+            break;
+        default:
+            return BUNDLED_JSON_UNDEFINED;
+            break;
+    }
+}
+
++ (NSString *)nameForPath:(BundledPath)bundledPath
+{
+    switch (bundledPath) {
+        case BUNDLED_PATH_CONFIG:
+            return @"config";
+            break;
+        case BUNDLED_PATH_LANGUAGES:
+        case BUNDLED_PATH_MAINPAGES:
+            return @"Languages";
+            break;
+        default:
+            return BUNDLED_PATH_UNDEFINED;
+            break;
+    }
+}
+
++ (BundledPath)bundledPathForFile:(BundledJsonFile)file
+{
+    switch (file) {
+        case BUNDLED_JSON_CONFIG:
+            return BUNDLED_PATH_CONFIG;
+            break;
+        case BUNDLED_JSON_LANGUAGES:
+            return BUNDLED_PATH_LANGUAGES;
+            break;
+        case BUNDLED_JSON_MAINPAGES:
+            return BUNDLED_PATH_MAINPAGES;
+            break;
+        default:
+            return BUNDLED_PATH_UNDEFINED;
+            break;
+    }
+}
+
++ (NSString *)remoteUrlForFile:(BundledJsonFile)bundledJsonFile
+{
+    // For now only the config file is remote synced.
+    switch (bundledJsonFile) {
+        case BUNDLED_JSON_CONFIG:
+            return 
@"https://bits.wikimedia.org/static-current/extensions/MobileApp/config/ios.json";;
+            break;
+        default:
+            return @"";
+            break;
+    }
+}
+
++(NSString *)pathForFolder:(BundledPath)folder file:(BundledJsonFile)file
+{
+    NSString *folderName = [self nameForPath:folder];
+    NSString *fileName = [self nameForFile:file];
+    return [[[[NSBundle mainBundle] bundlePath] 
stringByAppendingPathComponent:folderName] 
stringByAppendingPathComponent:fileName];
+}
+
++ (NSString *)bundledJsonFilePath:(BundledJsonFile)file
+{
+    BundledPath bundledPath = [self bundledPathForFile:file];
+    return [self pathForFolder:bundledPath file:file];
+}
+
++ (NSURL *)bundledJsonFileRemoteUrl:(BundledJsonFile)file
+{
+    return [NSURL URLWithString:[self remoteUrlForFile:file]];
+}
+
+@end
diff --git a/wikipedia/BundledPaths/BundledPathsEnum.h 
b/wikipedia/BundledPaths/BundledPathsEnum.h
new file mode 100644
index 0000000..189a518
--- /dev/null
+++ b/wikipedia/BundledPaths/BundledPathsEnum.h
@@ -0,0 +1,7 @@
+
+typedef NS_ENUM(NSUInteger, BundledPath) {
+    BUNDLED_PATH_UNDEFINED = 0,
+    BUNDLED_PATH_CONFIG = 1,
+    BUNDLED_PATH_LANGUAGES = 2,
+    BUNDLED_PATH_MAINPAGES = 3
+};
diff --git a/wikipedia/Data/Operations/ConfigFileSyncOp.h 
b/wikipedia/Data/Operations/ConfigFileSyncOp.h
new file mode 100644
index 0000000..a27fc90
--- /dev/null
+++ b/wikipedia/Data/Operations/ConfigFileSyncOp.h
@@ -0,0 +1,22 @@
+//  Created by Monte Hurd on 5/8/14.
+//  Copyright (c) 2013 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
+
+#import "MWNetworkOp.h"
+
+#import "BundledJsonEnum.h"
+
+@interface ConfigFileSyncOp : MWNetworkOp
+
+// Syncs any bundled app json file with a remote file.
+
+// Only does so if age of app file exceeds maxAge or if the file isn't found 
in app.
+
+// Nice because we can sync any bundled files with any periodicity
+// required just by firing these operations off occasionally.
+
+// They self-cancel if maxAge has not been exceeded, so fire away.
+
+- (id)initForBundledJsonFile: (BundledJsonFile)file
+                      maxAge: (CGFloat)maxAge;
+
+@end
diff --git a/wikipedia/Data/Operations/ConfigFileSyncOp.m 
b/wikipedia/Data/Operations/ConfigFileSyncOp.m
new file mode 100644
index 0000000..87fc1c2
--- /dev/null
+++ b/wikipedia/Data/Operations/ConfigFileSyncOp.m
@@ -0,0 +1,63 @@
+//  Created by Monte Hurd on 5/8/14.
+//  Copyright (c) 2013 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
+
+#import "ConfigFileSyncOp.h"
+#import "MWNetworkActivityIndicatorManager.h"
+#import "NSURLRequest+DictionaryRequest.h"
+
+#import "BundledJson.h"
+#import "BundledPaths.h"
+
+@implementation ConfigFileSyncOp
+
+- (id)initForBundledJsonFile: (BundledJsonFile)file
+                      maxAge: (CGFloat)maxAge
+{
+    self = [super init];
+    if (self) {
+
+        self.request = [NSURLRequest getRequestWithURL: [BundledPaths 
bundledJsonFileRemoteUrl:file]
+                                            parameters: nil];
+        
+        __weak ConfigFileSyncOp *weakSelf = self;
+        self.aboutToStart = ^{
+            
+            // Cancel the operation if the existing file hasn't aged enough.
+            BOOL shouldRefresh = [BundledJson 
isRefreshNeededForBundledJsonFile:file maxAge:maxAge];
+
+            if (!shouldRefresh) {
+                [weakSelf cancel];
+                return;
+            }
+
+            [[MWNetworkActivityIndicatorManager sharedManager] push];
+        };
+        self.completionBlock = ^(){
+            [[MWNetworkActivityIndicatorManager sharedManager] pop];
+            
+            if(weakSelf.isCancelled){
+                return;
+            }
+            
+            if (weakSelf.error) {
+                return;
+            }
+
+            // If it got this far, then a refresh was needed and has completed.
+            if (weakSelf.dataRetrieved) {
+                NSString *jsonString = [[NSString alloc] 
initWithData:weakSelf.dataRetrieved encoding:NSUTF8StringEncoding];
+                //NSLog(@"jsonString = %@", jsonString);
+                if (!jsonString) return;
+                NSString *filePath = [BundledPaths bundledJsonFilePath:file];
+                NSError *error = nil;
+                [jsonString writeToFile:filePath atomically:YES 
encoding:NSUTF8StringEncoding error:&error];
+                if (error) {
+                    NSLog(@"%@", error.localizedDescription);
+                }
+            }
+        };
+    }
+    return self;
+}
+
+@end
diff --git a/wikipedia/Queues/QueuesSingleton.h 
b/wikipedia/Queues/QueuesSingleton.h
index 1607054..9618d2c 100644
--- a/wikipedia/Queues/QueuesSingleton.h
+++ b/wikipedia/Queues/QueuesSingleton.h
@@ -22,6 +22,8 @@
 @property (strong, nonatomic) NSOperationQueue *eventLoggingQ;
 @property (strong, nonatomic) NSOperationQueue *pageHistoryQ;
 
+@property (strong, nonatomic) NSOperationQueue *bundledFileSyncQ;
+
 + (QueuesSingleton *)sharedInstance;
 
 @end
diff --git a/wikipedia/Queues/QueuesSingleton.m 
b/wikipedia/Queues/QueuesSingleton.m
index 6289a5a..bbf87c2 100644
--- a/wikipedia/Queues/QueuesSingleton.m
+++ b/wikipedia/Queues/QueuesSingleton.m
@@ -32,6 +32,7 @@
         self.randomArticleQ = [[NSOperationQueue alloc] init];
         self.eventLoggingQ = [[NSOperationQueue alloc] init];
         self.pageHistoryQ = [[NSOperationQueue alloc] init];
+        self.bundledFileSyncQ = [[NSOperationQueue alloc] init];
         //[self setupQMonitorLogging];
     }
     return self;
diff --git a/wikipedia/Session/SessionSingleton.h 
b/wikipedia/Session/SessionSingleton.h
index 55c03be..33e7897 100644
--- a/wikipedia/Session/SessionSingleton.h
+++ b/wikipedia/Session/SessionSingleton.h
@@ -28,7 +28,6 @@
 @property (strong, atomic) NSArray *unsupportedCharactersLanguageIds;
 
 -(NSURL *)urlForDomain:(NSString *)domain;
--(NSMutableArray *)getBundledLanguagesJson;
 -(NSString *)domainNameForCode:(NSString *)code;
 
 -(NSString *)mainArticleTitleForCode:(NSString *)code;
diff --git a/wikipedia/Session/SessionSingleton.m 
b/wikipedia/Session/SessionSingleton.m
index d10fe95..278c6a5 100644
--- a/wikipedia/Session/SessionSingleton.m
+++ b/wikipedia/Session/SessionSingleton.m
@@ -2,6 +2,8 @@
 //  Copyright (c) 2013 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
 
 #import "SessionSingleton.h"
+#import "BundledPaths.h"
+#import "BundledJson.h"
 
 @implementation SessionSingleton
 
@@ -117,12 +119,8 @@
 
 -(NSString *)domainNameForCode:(NSString *)code
 {
-    NSError *error = nil;
-    NSData *fileData = [NSData dataWithContentsOfFile:[self 
bundledLanguagesJsonPath] options:0 error:&error];
-    if (error) return nil;
-    error = nil;
-    NSArray *result = [NSJSONSerialization JSONObjectWithData:fileData 
options:0 error:&error];
-    if (!error) {
+    NSArray *result = [BundledJson 
arrayFromBundledJsonFile:BUNDLED_JSON_LANGUAGES];
+    if (result.count > 0) {
         for (NSDictionary *d in result) {
             if ([d[@"code"] isEqualToString:code]) {
                 return d[@"name"];
@@ -134,39 +132,9 @@
     }
 }
 
-- (NSString *)bundledLanguagesJsonPath
-{
-    return [[[NSBundle mainBundle] bundlePath] 
stringByAppendingString:@"/Languages/languages.json"];
-}
-
--(NSMutableArray *)getBundledLanguagesJson
-{
-    NSError *error = nil;
-    NSData *fileData = [NSData dataWithContentsOfFile:[[SessionSingleton 
sharedInstance] bundledLanguagesJsonPath] options:0 error:&error];
-    if (error) return [@[] mutableCopy];
-    error = nil;
-    NSArray *result = [NSJSONSerialization JSONObjectWithData:fileData 
options:0 error:&error];
-    return (error) ? [@[] mutableCopy]: [result mutableCopy];
-}
-
-- (NSString *)bundledMainArticleTitlesJsonPath
-{
-    return [[[NSBundle mainBundle] bundlePath] 
stringByAppendingString:@"/Languages/mainpages.json"];
-}
-
--(NSMutableDictionary *)getBundledMainArticleTitlesJson
-{
-    NSError *error = nil;
-    NSData *fileData = [NSData dataWithContentsOfFile:[[SessionSingleton 
sharedInstance] bundledMainArticleTitlesJsonPath] options:0 error:&error];
-    if (error) return @{}.mutableCopy;
-    error = nil;
-    NSDictionary *result = [NSJSONSerialization JSONObjectWithData:fileData 
options:0 error:&error];
-    return (error) ? @{}.mutableCopy: [result mutableCopy];
-}
-
 -(NSString *)mainArticleTitleForCode:(NSString *)code
 {
-    NSMutableDictionary *mainPageNames = [self 
getBundledMainArticleTitlesJson];
+    NSMutableDictionary *mainPageNames = [BundledJson 
dictionaryFromBundledJsonFile:BUNDLED_JSON_MAINPAGES];
     return mainPageNames[code];
 }
 
diff --git a/wikipedia/View Controllers/Languages/LanguagesTableVC.m 
b/wikipedia/View Controllers/Languages/LanguagesTableVC.m
index 1f31fa4..a6cadea 100644
--- a/wikipedia/View Controllers/Languages/LanguagesTableVC.m
+++ b/wikipedia/View Controllers/Languages/LanguagesTableVC.m
@@ -10,6 +10,7 @@
 #import "LanguagesSectionHeadingLabel.h"
 #import "NavController.h"
 #import "Defines.h"
+#import "BundledJson.h"
 
 #import "UIViewController+Alert.h"
 
@@ -70,7 +71,7 @@
     if(self.downloadLanguagesForCurrentArticle){
         [self downloadLangLinkData];
     }else{
-        self.languagesData = [[SessionSingleton sharedInstance] 
getBundledLanguagesJson];
+        self.languagesData = [BundledJson 
arrayFromBundledJsonFile:BUNDLED_JSON_LANGUAGES];
             self.headerView.hidden = NO;
         [self reloadTableDataFiltered];
     }
@@ -292,7 +293,7 @@
     DownloadLangLinksOp *langLinksOp =
     [[DownloadLangLinksOp alloc] initForPageTitle: [SessionSingleton 
sharedInstance].currentArticleTitle
                                            domain: [SessionSingleton 
sharedInstance].currentArticleDomain
-                                     allLanguages: [[SessionSingleton 
sharedInstance] getBundledLanguagesJson]
+                                     allLanguages: [BundledJson 
arrayFromBundledJsonFile:BUNDLED_JSON_LANGUAGES]
                                   completionBlock: ^(NSArray *result){
                                       
                                       [[NSOperationQueue mainQueue] 
addOperationWithBlock: ^ {
diff --git a/wikipedia/View Controllers/Preview/PreviewChoicesMenuView.m 
b/wikipedia/View Controllers/Preview/PreviewChoicesMenuView.m
index ae0b7f9..770ffbe 100644
--- a/wikipedia/View Controllers/Preview/PreviewChoicesMenuView.m
+++ b/wikipedia/View Controllers/Preview/PreviewChoicesMenuView.m
@@ -5,6 +5,7 @@
 #import "PaddedLabel.h"
 #import "WikipediaAppUtils.h"
 #import "NSString+FormattedAttributedString.h"
+#import "BundledJson.h"
 
 #define PREVIEW_BLUE_COLOR [UIColor colorWithRed:0.13 green:0.42 blue:0.68 
alpha:1.0]
 
@@ -14,6 +15,8 @@
 @interface PreviewChoicesMenuView(){
 
 }
+
+@property (weak, nonatomic) IBOutlet UIView *topRowContainer;
 
 @end
 
@@ -52,7 +55,6 @@
     self.signInView.backgroundColor = PREVIEW_BLUE_COLOR;
     
     [self underlineLabelText: self.signInTitleLabel];
-    [self underlineLabelText: self.saveAnonTitleLabel];
 
     /*
     self.signInTitleLabel.text = [@" abc " randomlyRepeatMaxTimes:100];
@@ -61,6 +63,21 @@
     self.saveAnonSubTitleLabel.text = [@" abc " randomlyRepeatMaxTimes:100];
     [self randomlyColorSubviews];
     */
+
+    if ([self isAnonymousEditingDisabled]) {
+        [self.saveAnonView removeFromSuperview];
+        // The right side of the signInView had been constrained to the left 
side of the
+        // saveAnonView, but now that the saveAnonView is gone the right side 
of the
+        // signInView needs to be constrained to the right side of the 
topRowContainer.
+        [self.topRowContainer addConstraints:
+         [NSLayoutConstraint constraintsWithVisualFormat: @"H:[signInView]|"
+                                                 options: 0
+                                                 metrics: nil
+                                                   views: @{@"signInView" : 
self.signInView}]
+         ];
+    }else{
+        [self underlineLabelText: self.saveAnonTitleLabel];
+    }
 }
 
 -(void)underlineLabelText:(UILabel *)label
@@ -79,4 +96,14 @@
     label.attributedText = aString;
 }
 
+-(BOOL)isAnonymousEditingDisabled
+{
+    NSDictionary *iosConfigJson = [BundledJson 
dictionaryFromBundledJsonFile:BUNDLED_JSON_CONFIG];
+    NSNumber *disableAnonEditing = iosConfigJson[@"disableAnonEditing"];
+    if (disableAnonEditing && (disableAnonEditing.boolValue == YES)) {
+        return YES;
+    }
+    return NO;
+}
+
 @end
diff --git a/wikipedia/View Controllers/Preview/PreviewChoicesMenuView.xib 
b/wikipedia/View Controllers/Preview/PreviewChoicesMenuView.xib
index 2ad687f..57d3cd9 100644
--- a/wikipedia/View Controllers/Preview/PreviewChoicesMenuView.xib
+++ b/wikipedia/View Controllers/Preview/PreviewChoicesMenuView.xib
@@ -102,6 +102,7 @@
                 <outlet property="signInSubTitleLabel" 
destination="dVR-8O-7eG" id="hus-QR-GXZ"/>
                 <outlet property="signInTitleLabel" destination="PPh-Eu-usA" 
id="LO3-x5-pCZ"/>
                 <outlet property="signInView" destination="JYT-4n-1ej" 
id="k1q-zU-i4A"/>
+                <outlet property="topRowContainer" destination="2HE-pz-gbX" 
id="8XN-KB-zcG"/>
             </connections>
         </view>
     </objects>
diff --git a/wikipedia/View Controllers/TopNav/NavController.m b/wikipedia/View 
Controllers/TopNav/NavController.m
index f6b3b0b..4eaa78f 100644
--- a/wikipedia/View Controllers/TopNav/NavController.m
+++ b/wikipedia/View Controllers/TopNav/NavController.m
@@ -473,7 +473,7 @@
         case NAVBAR_MODE_EDIT_WIKITEXT_LOGIN_OR_SAVE_ANONYMOUSLY:
             self.label.text = @"";
             self.navBarSubViewsHorizontalVFLString =
-                
@"H:|[NAVBAR_BUTTON_PENCIL(50)][NAVBAR_VERTICAL_LINE_1(singlePixel)]-(10)-[NAVBAR_LABEL]-(10)-[NAVBAR_VERTICAL_LINE_2(singlePixel)][NAVBAR_BUTTON_CHECK(50)]|";
+                
@"H:|[NAVBAR_BUTTON_PENCIL(50)][NAVBAR_VERTICAL_LINE_1(singlePixel)]-(10)-[NAVBAR_LABEL]|";
             break;
         case NAVBAR_MODE_EDIT_WIKITEXT_SAVE:
             self.label.text = 
MWLocalizedString(@"navbar-title-mode-edit-wikitext-save", nil);
diff --git a/wikipedia/View Controllers/WebView/WebViewController.m 
b/wikipedia/View Controllers/WebView/WebViewController.m
index 4e299a7..86598ba 100644
--- a/wikipedia/View Controllers/WebView/WebViewController.m
+++ b/wikipedia/View Controllers/WebView/WebViewController.m
@@ -39,6 +39,8 @@
 #import "DataMigrator.h"
 #import "ArticleImporter.h"
 
+#import "ConfigFileSyncOp.h"
+
 #define TOC_TOGGLE_ANIMATION_DURATION 0.3f
 #define NAV ((NavController *)self.navigationController)
 
@@ -174,7 +176,12 @@
 -(void)viewDidAppear:(BOOL)animated
 {
     [super viewDidAppear:animated];
-    
+
+    // Don't move this to viewDidLoad - this is because viewDidLoad may only 
get
+    // called very occasionally as app suspend/resume probably doesn't cause
+    // viewDidLoad to fire.
+    [self sycnConfigIosJsonIfNecessary];
+
     //[self.view randomlyColorSubviews];
 }
 
@@ -191,6 +198,21 @@
     [super viewWillDisappear:animated];
 }
 
+#pragma mark Sync bundled config/ios.json if necessary
+
+-(void)sycnConfigIosJsonIfNecessary
+{
+    // Sync config/ios.json at most once per day.
+    CGFloat maxAge = 60 * 60 * 24;
+
+    ConfigFileSyncOp *configSyncOp =
+    [[ConfigFileSyncOp alloc] initForBundledJsonFile: BUNDLED_JSON_CONFIG
+                                              maxAge: maxAge];
+    
+    [[QueuesSingleton sharedInstance].bundledFileSyncQ cancelAllOperations];
+    [[QueuesSingleton sharedInstance].bundledFileSyncQ 
addOperation:configSyncOp];
+}
+
 #pragma mark Edit section
 
 -(void)showSectionEditor

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia64c060806c14cbf08cacb3168af8f471c8de048
Gerrit-PatchSet: 1
Gerrit-Project: apps/ios/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Mhurd <mh...@wikimedia.org>

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

Reply via email to