Brion VIBBER has submitted this change and it was merged. Change subject: Restyle abuse filter warning/disallow screen. ......................................................................
Restyle abuse filter warning/disallow screen. Change-Id: I056ed6110745c0b95b3e12dcb1166f1ad170486c --- M Wikipedia.xcodeproj/project.pbxproj M wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m A wikipedia/View Controllers/Preview/AbuseFilterAlert.h A wikipedia/View Controllers/Preview/AbuseFilterAlert.m M wikipedia/View Controllers/Preview/PreviewAndSaveViewController.m M wikipedia/en.lproj/Localizable.strings M wikipedia/qqq.lproj/Localizable.strings 7 files changed, 365 insertions(+), 44 deletions(-) Approvals: Brion VIBBER: Verified; Looks good to me, approved diff --git a/Wikipedia.xcodeproj/project.pbxproj b/Wikipedia.xcodeproj/project.pbxproj index 47da97e..f122cff 100644 --- a/Wikipedia.xcodeproj/project.pbxproj +++ b/Wikipedia.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 0400EB0318AAEEC60043ECE2 /* UINavigationController+SearchNavStack.m in Sources */ = {isa = PBXBuildFile; fileRef = 0400EB0218AAEEC60043ECE2 /* UINavigationController+SearchNavStack.m */; }; + 04062607197DC1D1000BC084 /* AbuseFilterAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 04062606197DC1D1000BC084 /* AbuseFilterAlert.m */; }; 0406CEF618F8C390007EE43E /* LogEventOp.m in Sources */ = {isa = PBXBuildFile; fileRef = 0406CEF518F8C390007EE43E /* LogEventOp.m */; }; 04082B5318ADA25A00FAF3D6 /* text_field_x_circle_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 04082B5118ADA25A00FAF3D6 /* text_field_x_circle_gray.png */; }; 04082B5518ADA25A00FAF3D6 /* text_field_x_circle_g...@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 04082B5218ADA25A00FAF3D6 /* text_field_x_circle_g...@2x.png */; }; @@ -186,6 +187,8 @@ /* Begin PBXFileReference section */ 0400EB0118AAEEC60043ECE2 /* UINavigationController+SearchNavStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UINavigationController+SearchNavStack.h"; sourceTree = "<group>"; }; 0400EB0218AAEEC60043ECE2 /* UINavigationController+SearchNavStack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UINavigationController+SearchNavStack.m"; sourceTree = "<group>"; }; + 04062605197DC1D1000BC084 /* AbuseFilterAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbuseFilterAlert.h; sourceTree = "<group>"; }; + 04062606197DC1D1000BC084 /* AbuseFilterAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AbuseFilterAlert.m; sourceTree = "<group>"; }; 0406CEF418F8C390007EE43E /* LogEventOp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogEventOp.h; sourceTree = "<group>"; }; 0406CEF518F8C390007EE43E /* LogEventOp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LogEventOp.m; sourceTree = "<group>"; }; 04082B5118ADA25A00FAF3D6 /* text_field_x_circle_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = text_field_x_circle_gray.png; sourceTree = "<group>"; }; @@ -1338,6 +1341,8 @@ 04B0EA46190B2319007458AF /* PreviewLicenseView.xib */, 04B0EA48190B2348007458AF /* PreviewLicenseView.h */, 04B0EA49190B2348007458AF /* PreviewLicenseView.m */, + 04062605197DC1D1000BC084 /* AbuseFilterAlert.h */, + 04062606197DC1D1000BC084 /* AbuseFilterAlert.m */, ); path = Preview; sourceTree = "<group>"; @@ -1906,6 +1911,7 @@ 04F39590186CF80100B0D6FC /* TOCViewController.m in Sources */, 04D75824189248E900CE2040 /* DownloadLangLinksOp.m in Sources */, 04B91AA718E34BBC00FFAA1C /* UIView+TemporaryAnimatedXF.m in Sources */, + 04062607197DC1D1000BC084 /* AbuseFilterAlert.m in Sources */, D4B0AE0819366A0A00F0AC90 /* CreateAccountFunnel.m in Sources */, 04F27B7818FE0F2E00EDD838 /* PageHistoryViewController.m in Sources */, 049B640C18AAF36200D98BD4 /* UIViewController+SearchChildViewControllers.m in Sources */, diff --git a/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m b/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m index 2e9c411..99b35af 100644 --- a/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m +++ b/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m @@ -427,14 +427,14 @@ @"H:|-(4)-[NAVBAR_BUTTON_X(50)]-(16)-[NAVBAR_LABEL]-(10)-[NAVBAR_BUTTON_DONE(50@250)]|"; break; case NAVBAR_MODE_EDIT_WIKITEXT_WARNING: - self.label.text = MWLocalizedString(@"navbar-title-mode-edit-wikitext-warning", nil); + //self.label.text = MWLocalizedString(@"navbar-title-mode-edit-wikitext-warning", nil); self.navBarSubViewsHorizontalVFLString = - @"H:|-(4)-[NAVBAR_BUTTON_X(50)]-(16)-[NAVBAR_LABEL]-(10)-[NAVBAR_BUTTON_CHECK(60)]|"; + @"H:|-(4)-[NAVBAR_BUTTON_ARROW_LEFT(50)]-(16)-[NAVBAR_LABEL]-(10)-[NAVBAR_BUTTON_SAVE(50@250)]|"; break; case NAVBAR_MODE_EDIT_WIKITEXT_DISALLOW: - self.label.text = MWLocalizedString(@"navbar-title-mode-edit-wikitext-disallow", nil); + //self.label.text = MWLocalizedString(@"navbar-title-mode-edit-wikitext-disallow", nil); self.navBarSubViewsHorizontalVFLString = - @"H:|-(4)-[NAVBAR_BUTTON_X(50)]-(10)-[NAVBAR_LABEL]-(60)-|"; + @"H:|-(4)-[NAVBAR_BUTTON_ARROW_LEFT(50)]-(10)-[NAVBAR_LABEL]-(60)-|"; break; case NAVBAR_MODE_EDIT_WIKITEXT_PREVIEW: self.label.text = @""; diff --git a/wikipedia/View Controllers/Preview/AbuseFilterAlert.h b/wikipedia/View Controllers/Preview/AbuseFilterAlert.h new file mode 100644 index 0000000..38feb7b --- /dev/null +++ b/wikipedia/View Controllers/Preview/AbuseFilterAlert.h @@ -0,0 +1,17 @@ +// Created by Monte Hurd on 7/21/14. +// Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; please copy and modify! + +#import "TabularScrollView.h" + +typedef NS_ENUM(NSInteger, AbuseFilterAlertType) { + ABUSE_FILTER_WARNING, + ABUSE_FILTER_DISALLOW +}; + +@interface AbuseFilterAlert : TabularScrollView + +- (id)initWithType: (AbuseFilterAlertType) alertType; + +@property (nonatomic, readonly) AbuseFilterAlertType alertType; + +@end diff --git a/wikipedia/View Controllers/Preview/AbuseFilterAlert.m b/wikipedia/View Controllers/Preview/AbuseFilterAlert.m new file mode 100644 index 0000000..0b931bc --- /dev/null +++ b/wikipedia/View Controllers/Preview/AbuseFilterAlert.m @@ -0,0 +1,294 @@ +// Created by Monte Hurd on 7/21/14. +// Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; please copy and modify! + +#import "AbuseFilterAlert.h" +#import "PaddedLabel.h" +#import "Defines.h" +#import "WikiGlyphLabel.h" +#import "WikiGlyph_Chars.h" +#import "WMF_Colors.h" +#import "WikipediaAppUtils.h" + +typedef NS_ENUM(NSInteger, ViewType) { + VIEW_TYPE_ICON, + VIEW_TYPE_HEADING, + VIEW_TYPE_SUBHEADING, + VIEW_TYPE_ITEM +}; + +@interface AbuseFilterAlert () + +@property (nonatomic, strong) NSMutableArray *subViews; + +@property (nonatomic, strong) NSMutableArray *subViewData; + +@end + +@implementation AbuseFilterAlert + +- (id)initWithType: (AbuseFilterAlertType) alertType +{ + self = [super init]; + if (self) { + self.subViews = @[].mutableCopy; + self.subViewData = @[].mutableCopy; + self.backgroundColor = [UIColor whiteColor]; //CHROME_COLOR; + self.translatesAutoresizingMaskIntoConstraints = NO; + _alertType = alertType; + [self setupSubViewData]; + [self makeSubViews]; + self.minSubviewHeight = 40; + [self setTabularSubviews:self.subViews]; + } + return self; +} + +-(void) setupSubViewData +{ + [self.subViewData addObject: + @{ + @"type": @(VIEW_TYPE_ICON), + @"string": ((self.alertType == ABUSE_FILTER_DISALLOW) ? WIKIGLYPH_X : WIKIGLYPH_FLAG), + @"backgroundColor": ((self.alertType == ABUSE_FILTER_DISALLOW) ? WMF_COLOR_RED : WMF_COLOR_ORANGE), + @"fontColor": [UIColor whiteColor], + @"fontSize": @((self.alertType == ABUSE_FILTER_DISALLOW) ? 74 : 70), + @"baselineOffset": @((self.alertType == ABUSE_FILTER_DISALLOW) ? 2.0 : 0.0) + } + ]; + + switch (self.alertType) { + case ABUSE_FILTER_WARNING: + + [self.subViewData addObjectsFromArray: + @[ + @{ + @"type": @(VIEW_TYPE_HEADING), + @"string": MWLocalizedString(@"abuse-filter-warning-heading", nil), + @"backgroundColor": [UIColor whiteColor], + @"fontColor": [UIColor darkGrayColor], + @"fontSize": @(23), + @"baselineOffset": @(0) + }, + @{ + @"type": @(VIEW_TYPE_SUBHEADING), + @"string": MWLocalizedString(@"abuse-filter-warning-subheading", nil), + @"backgroundColor": [UIColor whiteColor], + @"fontColor": [UIColor lightGrayColor], + @"fontSize": @(16), + @"baselineOffset": @(0) + }, + @{ + @"type": @(VIEW_TYPE_ITEM), + @"string": MWLocalizedString(@"abuse-filter-warning-caps", nil), + @"backgroundColor": [UIColor whiteColor], + @"fontColor": [UIColor blackColor], + @"fontSize": @(16), + @"baselineOffset": @(0) + }, + @{ + @"type": @(VIEW_TYPE_ITEM), + @"string": MWLocalizedString(@"abuse-filter-warning-blanking", nil), + @"backgroundColor": [UIColor whiteColor], + @"fontColor": [UIColor blackColor], + @"fontSize": @(16), + @"baselineOffset": @(0) + }, + @{ + @"type": @(VIEW_TYPE_ITEM), + @"string": MWLocalizedString(@"abuse-filter-warning-irrelevant", nil), + @"backgroundColor": [UIColor whiteColor], + @"fontColor": [UIColor blackColor], + @"fontSize": @(16), + @"baselineOffset": @(0) + }, + @{ + @"type": @(VIEW_TYPE_ITEM), + @"string": MWLocalizedString(@"abuse-filter-warning-repeat", nil), + @"backgroundColor": [UIColor whiteColor], + @"fontColor": [UIColor blackColor], + @"fontSize": @(16), + @"baselineOffset": @(0) + } + ]]; + + break; + case ABUSE_FILTER_DISALLOW: + + [self.subViewData addObjectsFromArray: + @[ + @{ + @"type": @(VIEW_TYPE_HEADING), + @"string": MWLocalizedString(@"abuse-filter-disallow-heading", nil), + @"backgroundColor": [UIColor whiteColor], + @"fontColor": [UIColor darkGrayColor], + @"fontSize": @(23), + @"baselineOffset": @(0) + }, + @{ + @"type": @(VIEW_TYPE_ITEM), + @"string": MWLocalizedString(@"abuse-filter-disallow-unconstructive", nil), + @"backgroundColor": [UIColor whiteColor], + @"fontColor": [UIColor blackColor], + @"fontSize": @(16), + @"baselineOffset": @(0) + }, + @{ + @"type": @(VIEW_TYPE_ITEM), + @"string": MWLocalizedString(@"abuse-filter-disallow-notable", nil), + @"backgroundColor": [UIColor whiteColor], + @"fontColor": [UIColor blackColor], + @"fontSize": @(16), + @"baselineOffset": @(0) + } + ]]; + + break; + default: + break; + } +} + +-(void)makeSubViews +{ + for (NSDictionary *viewData in self.subViewData) { + NSNumber *type = viewData[@"type"]; + switch (type.integerValue) { + case VIEW_TYPE_ICON: + { + UIView *view = [[UIView alloc] init]; + view.backgroundColor = CHROME_COLOR; + + WikiGlyphLabel *label = [[WikiGlyphLabel alloc] init]; + label.translatesAutoresizingMaskIntoConstraints = NO; + label.textAlignment = NSTextAlignmentCenter; + + label.backgroundColor = viewData[@"backgroundColor"]; + NSNumber *fontSize = viewData[@"fontSize"]; + NSNumber *baselineOffset = viewData[@"baselineOffset"]; + + [label setWikiText: viewData[@"string"] + color: viewData[@"fontColor"] + size: fontSize.floatValue + baselineOffset: baselineOffset.floatValue]; + + CGFloat iconHeight = 78.0; + label.layer.cornerRadius = iconHeight / 2.0; + label.clipsToBounds = YES; + + [view addSubview:label]; + + NSDictionary *views = @{@"label": label, @"v1": view}; + NSDictionary *metrics = @{@"iconHeight": @(iconHeight)}; + + [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"V:[v1(125)]" + options: 0 + metrics: nil + views: views]]; + + [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"V:[label(iconHeight)]" + options: 0 + metrics: metrics + views: views]]; + + [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"H:[label(iconHeight)]" + options: 0 + metrics: metrics + views: views]]; + + [view addConstraint: [NSLayoutConstraint constraintWithItem: label + attribute: NSLayoutAttributeCenterX + relatedBy: NSLayoutRelationEqual + toItem: view + attribute: NSLayoutAttributeCenterX + multiplier: 1 + constant: 0]]; + + [view addConstraint: [NSLayoutConstraint constraintWithItem: label + attribute: NSLayoutAttributeCenterY + relatedBy: NSLayoutRelationEqual + toItem: view + attribute: NSLayoutAttributeCenterY + multiplier: 1 + constant: 0]]; + [self.subViews addObject:view]; + } + break; + default: + { + PaddedLabel *label = [[PaddedLabel alloc] init]; + label.numberOfLines = 0; + label.lineBreakMode = NSLineBreakByWordWrapping; + label.translatesAutoresizingMaskIntoConstraints = NO; + label.backgroundColor = viewData[@"backgroundColor"]; + + CGFloat nonHeadingBottomSpacing = (self.alertType == ABUSE_FILTER_DISALLOW) ? 22 : 8; + + label.padding = (type.integerValue == VIEW_TYPE_HEADING) ? + UIEdgeInsetsMake(21, 22, 21, 16) + : + UIEdgeInsetsMake(8, 22, nonHeadingBottomSpacing, 16); + + [self setText:MWLocalizedString(viewData[@"string"], nil) forLabel:label subViewData:viewData]; + + [self.subViews addObject:label]; + } + break; + } + } +} + +-(void)setText:(NSString *)text forLabel:(UILabel *)label subViewData:(NSDictionary *)viewData +{ + + NSNumber *type = viewData[@"type"]; + NSNumber *size = viewData[@"fontSize"]; + UIColor *color = viewData[@"fontColor"]; + UIFont *font = (type.integerValue == VIEW_TYPE_HEADING) ? + [UIFont boldSystemFontOfSize:size.floatValue] + : + [UIFont systemFontOfSize:size.floatValue]; + NSNumber *offset = viewData[@"baselineOffset"]; + + CGFloat kearning = 0.0; + + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + + switch (type.integerValue) { + case VIEW_TYPE_HEADING: + paragraphStyle.lineSpacing = 3; + kearning = 0.4; + break; + case VIEW_TYPE_SUBHEADING: + paragraphStyle.lineSpacing = 2; + kearning = 0.0; + break; + default: + paragraphStyle.lineSpacing = 6; + kearning = 0.0; + break; + } + + NSDictionary *attributes = + @{ + NSFontAttributeName: font, + NSForegroundColorAttributeName : color, + NSBaselineOffsetAttributeName: offset, + NSKernAttributeName : @(kearning), + NSParagraphStyleAttributeName : paragraphStyle + }; + + label.attributedText = + [[NSAttributedString alloc] initWithString: text + attributes: attributes]; +} + +/* + // Only override drawRect: if you perform custom drawing. + // An empty implementation adversely affects performance during animation. + - (void)drawRect:(CGRect)rect + { + // Drawing code + } + */ + +@end diff --git a/wikipedia/View Controllers/Preview/PreviewAndSaveViewController.m b/wikipedia/View Controllers/Preview/PreviewAndSaveViewController.m index ff72324..fcd403f 100644 --- a/wikipedia/View Controllers/Preview/PreviewAndSaveViewController.m +++ b/wikipedia/View Controllers/Preview/PreviewAndSaveViewController.m @@ -31,6 +31,7 @@ #import "PreviewLicenseView.h" #import "LoginViewController.h" #import "UIScrollView+ScrollSubviewToLocation.h" +#import "AbuseFilterAlert.h" typedef enum { CANNED_SUMMARY_TYPOS = 0, @@ -628,12 +629,11 @@ // Hides the license panel. Needed if logged in and a disallow is triggered. [self.navigationController topActionSheetHide]; - NSString *restyledWarningHtml = [self restyleAbuseFilterWarningHtml:warningHtml]; [self fadeAlert]; - [self showHTMLAlert: restyledWarningHtml - bannerImage: [UIImage imageNamed:bannerImage] - bannerColor: bannerColor - ]; + AbuseFilterAlertType alertType = + (error.code == WIKITEXT_UPLOAD_ERROR_ABUSEFILTER_DISALLOWED) ? ABUSE_FILTER_DISALLOW : ABUSE_FILTER_WARNING; + [self showAbuseFilterAlertOfType:alertType]; + }); } break; @@ -710,6 +710,25 @@ [QueuesSingleton sharedInstance].sectionWikiTextUploadQ.suspended = NO; } +-(void)showAbuseFilterAlertOfType:(AbuseFilterAlertType)alertType +{ + AbuseFilterAlert *abuseFilterAlert = [[AbuseFilterAlert alloc] initWithType:alertType]; + + [self.view addSubview:abuseFilterAlert]; + + NSDictionary *views = @{@"abuseFilterAlert": abuseFilterAlert}; + + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"H:|[abuseFilterAlert]|" + options: 0 + metrics: nil + views: views]]; + + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"V:|[abuseFilterAlert]|" + options: 0 + metrics: nil + views: views]]; +} + - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString: @"Preview_Captcha_Embed"]) { @@ -764,41 +783,6 @@ -(void)captchaTextFieldDidChange:(UITextField *)textField { [self highlightCaptchaSubmitButton:(textField.text.length == 0) ? NO : YES]; -} - -//TODO: this shouldn't be in the controller. Find it a nice home. --(NSString *)restyleAbuseFilterWarningHtml:(NSString *)warningHtml -{ - // Abuse filter warnings have html :( Re-style as best we can... - return [NSString stringWithFormat: - @"\ - <html>\ - <head>\ - <style>\ - *{\ - background-color:transparent!important;\ - border-color:transparent!important;\ - width:auto!important;\ - font:auto!important;\ - font-family:sans-serif!important;\ - font-size:14px!important;\ - color:rgb(85, 85, 85)!important;\ - line-height:22px!important;\ - text-align:left!important;\ - }\ - td[style]{background-color:transparent!important;border-style:none!important;}\ - IMG{zoom:0.5;margin:20px}\ - body{padding:21px!important;padding-top:16px!important;margin:0px!important;}\ - </style>\ - </head>\ - <body>\ - <div>\ - %@\ - </div>\ - </body>\ - </html>\ - ", - warningHtml]; } // BOOL userIsloggedIn = [SessionSingleton sharedInstance].keychainCredentials.userName ? YES : NO; diff --git a/wikipedia/en.lproj/Localizable.strings b/wikipedia/en.lproj/Localizable.strings index a58f959..92e3cab 100644 --- a/wikipedia/en.lproj/Localizable.strings +++ b/wikipedia/en.lproj/Localizable.strings @@ -180,3 +180,14 @@ "license-footer-name" = "CC BY-SA 3.0"; "table-of-contents-heading" = "Contents"; + +"abuse-filter-warning-heading" = "This looks like an unconstructive edit, are you sure you want to save it?"; +"abuse-filter-warning-subheading" = "Your edit may contain one or more of the following:"; +"abuse-filter-warning-caps" = "Typing in all caps"; +"abuse-filter-warning-blanking" = "Blanking articles or spamming"; +"abuse-filter-warning-irrelevant" = "Irrelevant external links and images"; +"abuse-filter-warning-repeat" = "Repeating characters"; + +"abuse-filter-disallow-heading" = "You cannot save this edit. Please go back and change it."; +"abuse-filter-disallow-unconstructive" = "An automated filter has identified this edit as potentially unconstructive and potential vandalism."; +"abuse-filter-disallow-notable" = "Wikipedia is an encyclopedia and only neutral, notable content belongs here."; diff --git a/wikipedia/qqq.lproj/Localizable.strings b/wikipedia/qqq.lproj/Localizable.strings index add9162..9b67e21 100644 --- a/wikipedia/qqq.lproj/Localizable.strings +++ b/wikipedia/qqq.lproj/Localizable.strings @@ -159,3 +159,12 @@ "main-menu-rate-app" = "Button text for showing the app in the app store so user can rate the app"; "main-menu-terms-of-use" = "Button text for showing site terms of use"; "main-menu-show-today" = "Button text for showing mobile version of main page"; +"abuse-filter-warning-heading" = "Header text for unconstructive edit warning"; +"abuse-filter-warning-subheading" = "Subheading text for potentially unconstructive edit warning"; +"abuse-filter-warning-caps" = "Label text for typing in all capitals"; +"abuse-filter-warning-blanking" = "Label text for blanking articles or spamming"; +"abuse-filter-warning-irrelevant" = "Label text for irrelevant external links and images"; +"abuse-filter-warning-repeat" = "Label text for repeating characters"; +"abuse-filter-disallow-heading" = "Header text for disallowed edit warning."; +"abuse-filter-disallow-unconstructive" = "Label text for unconstructive edit description"; +"abuse-filter-disallow-notable" = "Label text for notable content description"; -- To view, visit https://gerrit.wikimedia.org/r/148445 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I056ed6110745c0b95b3e12dcb1166f1ad170486c Gerrit-PatchSet: 2 Gerrit-Project: apps/ios/wikipedia Gerrit-Branch: master Gerrit-Owner: Mhurd <mh...@wikimedia.org> Gerrit-Reviewer: Brion VIBBER <br...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits