Mhurd has uploaded a new change for review. https://gerrit.wikimedia.org/r/150964
Change subject: References panel now appears on bottom of screen. ...................................................................... References panel now appears on bottom of screen. Change-Id: Ie3ad35d6065c874eca0d7289cf190bc3e2bc8156 --- M Wikipedia.xcodeproj/project.pbxproj M wikipedia/Base.lproj/Main_iPhone.storyboard A wikipedia/View Controllers/References/ReferenceGradientView.h A wikipedia/View Controllers/References/ReferenceGradientView.m A wikipedia/View Controllers/References/ReferenceVC.h A wikipedia/View Controllers/References/ReferenceVC.m A wikipedia/View Controllers/References/ReferencesVC.h A wikipedia/View Controllers/References/ReferencesVC.m M wikipedia/View Controllers/TableOfContents/TOCViewController.m M wikipedia/View Controllers/WebView/WebViewController.h M wikipedia/View Controllers/WebView/WebViewController.m M wikipedia/assets/index.html M www/index.html 13 files changed, 1,034 insertions(+), 7 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/apps/ios/wikipedia refs/changes/64/150964/1 diff --git a/Wikipedia.xcodeproj/project.pbxproj b/Wikipedia.xcodeproj/project.pbxproj index 4a0c454..fed55a2 100644 --- a/Wikipedia.xcodeproj/project.pbxproj +++ b/Wikipedia.xcodeproj/project.pbxproj @@ -82,6 +82,7 @@ 047E74141860509000916964 /* SavedPagesResultPrototypeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 047E74131860509000916964 /* SavedPagesResultPrototypeView.xib */; }; 047ED63918C13E4900442BE3 /* PreviewWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 047ED63818C13E4900442BE3 /* PreviewWebView.m */; }; 047FF5471889078C009DB293 /* Image+Convenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 047FF5461889078C009DB293 /* Image+Convenience.m */; }; + 04821CD119895EDC007558F6 /* ReferenceGradientView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04821CD019895EDC007558F6 /* ReferenceGradientView.m */; }; 048A26771906268100395F53 /* PaddedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048A26761906268100395F53 /* PaddedLabel.m */; }; 0493C2CC1952373100EBB973 /* CoreDataHousekeeping.m in Sources */ = {isa = PBXBuildFile; fileRef = 0493C2CB1952373100EBB973 /* CoreDataHousekeeping.m */; }; 0493C2D419526A0100EBB973 /* WikiFont-Glyphs.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0493C2D319526A0100EBB973 /* WikiFont-Glyphs.ttf */; }; @@ -122,6 +123,8 @@ 04C91CEF195520990035ED1B /* logo-onboarding-subti...@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 04C91CED195520990035ED1B /* logo-onboarding-subti...@2x.png */; }; 04C91CF219554B310035ED1B /* logo-onboarding.png in Resources */ = {isa = PBXBuildFile; fileRef = 04C91CF019554B310035ED1B /* logo-onboarding.png */; }; 04C91CF319554B310035ED1B /* logo-onboard...@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 04C91CF119554B310035ED1B /* logo-onboard...@2x.png */; }; + 04CCA0C01983086D000E982A /* ReferencesVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04CCA0BF1983086D000E982A /* ReferencesVC.m */; }; + 04CCA0C319830A44000E982A /* ReferenceVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04CCA0C219830A44000E982A /* ReferenceVC.m */; }; 04CCCFEE1935093A00E3F60C /* SecondaryMenuRowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04CCCFEA1935093A00E3F60C /* SecondaryMenuRowView.m */; }; 04CCCFEF1935093A00E3F60C /* SecondaryMenuRowView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 04CCCFEB1935093A00E3F60C /* SecondaryMenuRowView.xib */; }; 04CCCFF01935093A00E3F60C /* SecondaryMenuViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04CCCFED1935093A00E3F60C /* SecondaryMenuViewController.m */; }; @@ -330,6 +333,8 @@ 047ED63818C13E4900442BE3 /* PreviewWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreviewWebView.m; sourceTree = "<group>"; }; 047FF5451889078C009DB293 /* Image+Convenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Image+Convenience.h"; sourceTree = "<group>"; }; 047FF5461889078C009DB293 /* Image+Convenience.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Image+Convenience.m"; sourceTree = "<group>"; }; + 04821CCF19895EDC007558F6 /* ReferenceGradientView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReferenceGradientView.h; sourceTree = "<group>"; }; + 04821CD019895EDC007558F6 /* ReferenceGradientView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReferenceGradientView.m; sourceTree = "<group>"; }; 048A26751906268100395F53 /* PaddedLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PaddedLabel.h; sourceTree = "<group>"; }; 048A26761906268100395F53 /* PaddedLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PaddedLabel.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 0493C2CA1952373100EBB973 /* CoreDataHousekeeping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoreDataHousekeeping.h; sourceTree = "<group>"; }; @@ -406,6 +411,10 @@ 04C91CED195520990035ED1B /* logo-onboarding-subti...@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-onboarding-subti...@2x.png"; sourceTree = "<group>"; }; 04C91CF019554B310035ED1B /* logo-onboarding.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-onboarding.png"; sourceTree = "<group>"; }; 04C91CF119554B310035ED1B /* logo-onboard...@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-onboard...@2x.png"; sourceTree = "<group>"; }; + 04CCA0BE1983086D000E982A /* ReferencesVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReferencesVC.h; sourceTree = "<group>"; }; + 04CCA0BF1983086D000E982A /* ReferencesVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReferencesVC.m; sourceTree = "<group>"; }; + 04CCA0C119830A44000E982A /* ReferenceVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReferenceVC.h; sourceTree = "<group>"; }; + 04CCA0C219830A44000E982A /* ReferenceVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReferenceVC.m; sourceTree = "<group>"; }; 04CCCFE91935093A00E3F60C /* SecondaryMenuRowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecondaryMenuRowView.h; sourceTree = "<group>"; }; 04CCCFEA1935093A00E3F60C /* SecondaryMenuRowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecondaryMenuRowView.m; sourceTree = "<group>"; }; 04CCCFEB1935093A00E3F60C /* SecondaryMenuRowView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SecondaryMenuRowView.xib; sourceTree = "<group>"; }; @@ -1134,6 +1143,7 @@ 04F27B6D18FE0F2E00EDD838 /* PageHistory */, 04DD89AE18BFE63A00DD5DAD /* Preview */, D49B2ECF196C684F002F035D /* PullToRefresh */, + 04CCA0BD19830837000E982A /* References */, 0412CC5F192536580010E616 /* Root */, 04293002186030B0002A13FC /* SavedPages */, 04292FEE185FBA70002A13FC /* SearchResults */, @@ -1246,6 +1256,19 @@ 04C91CEA195517250035ED1B /* OnboardingViewController.m */, ); path = Onboarding; + sourceTree = "<group>"; + }; + 04CCA0BD19830837000E982A /* References */ = { + isa = PBXGroup; + children = ( + 04CCA0BE1983086D000E982A /* ReferencesVC.h */, + 04CCA0BF1983086D000E982A /* ReferencesVC.m */, + 04CCA0C119830A44000E982A /* ReferenceVC.h */, + 04CCA0C219830A44000E982A /* ReferenceVC.m */, + 04821CCF19895EDC007558F6 /* ReferenceGradientView.h */, + 04821CD019895EDC007558F6 /* ReferenceGradientView.m */, + ); + path = References; sourceTree = "<group>"; }; 04CCCFE81935093A00E3F60C /* Secondary */ = { @@ -1897,6 +1920,7 @@ 0429300A18604898002A13FC /* SavedPagesResultCell.m in Sources */, 04D34DC11863F6B200610A87 /* History.m in Sources */, 04D34DAF1863D2D600610A87 /* XPathQuery.m in Sources */, + 04821CD119895EDC007558F6 /* ReferenceGradientView.m in Sources */, 0472BC18193AD88C00C40BDA /* Section+DisplayHtml.m in Sources */, 047ED63918C13E4900442BE3 /* PreviewWebView.m in Sources */, 04B6925018E77B2A00F88D8A /* UIWebView+HideScrollGradient.m in Sources */, @@ -1906,6 +1930,7 @@ D4B0AE0B19366A2C00F0AC90 /* ReadingActionFunnel.m in Sources */, 0452C810195D0F03007925A6 /* UIViewController+ModalPop.m in Sources */, 041C55D21950B27D006CE0EF /* EditSummaryViewController.m in Sources */, + 04CCA0C01983086D000E982A /* ReferencesVC.m in Sources */, 04C43ABE183442FC006C643B /* NSRunLoop+TimeOutAndFlag.m in Sources */, D4B0AE0E19366A5400F0AC90 /* LoginFunnel.m in Sources */, 043C668A18BE9A8E00580E9B /* PreviewWikiTextOp.m in Sources */, @@ -1919,6 +1944,7 @@ 0433542218A023FE009305F0 /* UIViewController+HideKeyboard.m in Sources */, C958EE3418CE73E600148D13 /* DownloadTitlesForRandomArticlesOp.m in Sources */, 0452C803195CB216007925A6 /* UIViewController+ModalsSearch.m in Sources */, + 04CCA0C319830A44000E982A /* ReferenceVC.m in Sources */, 04B91AB718E4D5B200FFAA1C /* TabularScrollView.m in Sources */, 04C695D218ED213000D9F2DA /* UIScrollView+NoHorizontalScrolling.m in Sources */, 04F0E2EE186FB2D100468738 /* TOCSectionCellView.m in Sources */, diff --git a/wikipedia/Base.lproj/Main_iPhone.storyboard b/wikipedia/Base.lproj/Main_iPhone.storyboard index c44bf88..f8853c8 100644 --- a/wikipedia/Base.lproj/Main_iPhone.storyboard +++ b/wikipedia/Base.lproj/Main_iPhone.storyboard @@ -134,7 +134,7 @@ </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="I47-Yh-yr4" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> - <point key="canvasLocation" x="-407" y="698"/> + <point key="canvasLocation" x="574" y="730"/> </scene> <!--Page History View Controller--> <scene sceneID="nqw-r1-g0T"> @@ -1198,6 +1198,17 @@ <constraint firstItem="SiM-aO-PlN" firstAttribute="top" secondItem="F4Q-Xc-ImV" secondAttribute="top" id="vWw-wM-gCP"/> </constraints> </view> + <containerView clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gB8-UC-wuQ" userLabel="References Container View"> + <rect key="frame" x="0.0" y="308" width="320" height="200"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> + <constraints> + <constraint firstAttribute="height" constant="200" id="Z6r-VJ-hik"/> + </constraints> + <connections> + <segue destination="1wG-t8-xjS" kind="embed" identifier="ReferencesVC_embed" id="fwM-jR-p9Z"/> + </connections> + </containerView> </subviews> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> <constraints> @@ -1205,9 +1216,12 @@ <constraint firstItem="WeL-Mj-Zsh" firstAttribute="leading" secondItem="kh9-bI-dsS" secondAttribute="leading" id="3Zs-jL-a48"/> <constraint firstItem="WeL-Mj-Zsh" firstAttribute="trailing" secondItem="F4Q-Xc-ImV" secondAttribute="trailing" id="J2p-jy-zrW"/> <constraint firstAttribute="trailing" secondItem="WeL-Mj-Zsh" secondAttribute="trailing" id="QSr-uN-iN4"/> + <constraint firstItem="WeL-Mj-Zsh" firstAttribute="leading" secondItem="gB8-UC-wuQ" secondAttribute="leading" id="TPG-uM-6qs"/> <constraint firstItem="WeL-Mj-Zsh" firstAttribute="leading" secondItem="F4Q-Xc-ImV" secondAttribute="leading" id="akc-jF-1Pw"/> <constraint firstAttribute="bottom" secondItem="F4Q-Xc-ImV" secondAttribute="bottom" placeholder="YES" id="bOy-uv-taw"/> <constraint firstAttribute="bottom" secondItem="WeL-Mj-Zsh" secondAttribute="bottom" id="myK-xK-1sX"/> + <constraint firstItem="gB8-UC-wuQ" firstAttribute="bottom" secondItem="kh9-bI-dsS" secondAttribute="bottom" id="nMr-wt-aMC"/> + <constraint firstItem="WeL-Mj-Zsh" firstAttribute="trailing" secondItem="gB8-UC-wuQ" secondAttribute="trailing" id="sLM-fO-nId"/> </constraints> </view> <extendedEdge key="edgesForExtendedLayout"/> @@ -1217,6 +1231,9 @@ </navigationItem> <connections> <outlet property="bottomBarView" destination="F4Q-Xc-ImV" id="U8K-lV-PiW"/> + <outlet property="referencesContainerView" destination="gB8-UC-wuQ" id="f7G-jI-SWO"/> + <outlet property="referencesContainerViewBottomConstraint" destination="nMr-wt-aMC" id="z1X-xR-f8n"/> + <outlet property="referencesContainerViewHeightConstraint" destination="Z6r-VJ-hik" id="vdX-Ye-y6G"/> <outlet property="webView" destination="WeL-Mj-Zsh" id="UAL-nl-cQD"/> <outlet property="webViewLeftConstraint" destination="3Zs-jL-a48" id="fnl-sG-tsS"/> <outlet property="webViewRightConstraint" destination="QSr-uN-iN4" id="EG4-9F-vyJ"/> @@ -1423,6 +1440,69 @@ </objects> <point key="canvasLocation" x="-1137" y="-210"/> </scene> + <!--ReferenceVC--> + <scene sceneID="oNi-7F-FeN"> + <objects> + <viewController restorationIdentifier="ReferenceVC" storyboardIdentifier="ReferenceVC" extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="Pxx-VU-xla" customClass="ReferenceVC" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="KFQ-nS-ONF"/> + <viewControllerLayoutGuide type="bottom" id="XwI-oB-1rV"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="rS5-jM-7C5"> + <rect key="frame" x="0.0" y="0.0" width="320" height="300"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <webView opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" allowsInlineMediaPlayback="NO" mediaPlaybackAllowsAirPlay="NO" translatesAutoresizingMaskIntoConstraints="NO" id="90R-X9-ZAd"> + <rect key="frame" x="0.0" y="0.0" width="320" height="300"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> + <dataDetectorType key="dataDetectorTypes"/> + </webView> + </subviews> + <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> + <constraints> + <constraint firstAttribute="trailing" secondItem="90R-X9-ZAd" secondAttribute="trailing" id="4QL-a7-pAf"/> + <constraint firstAttribute="bottom" secondItem="90R-X9-ZAd" secondAttribute="bottom" id="8uv-Uy-4Ox"/> + <constraint firstItem="90R-X9-ZAd" firstAttribute="leading" secondItem="rS5-jM-7C5" secondAttribute="leading" id="b3G-88-nvO"/> + <constraint firstItem="90R-X9-ZAd" firstAttribute="top" secondItem="rS5-jM-7C5" secondAttribute="top" id="jtu-qj-29x"/> + </constraints> + </view> + <nil key="simulatedStatusBarMetrics"/> + <nil key="simulatedTopBarMetrics"/> + <nil key="simulatedBottomBarMetrics"/> + <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> + <size key="freeformSize" width="320" height="300"/> + <connections> + <outlet property="referenceWebView" destination="90R-X9-ZAd" id="NWM-sh-DXF"/> + </connections> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="zcN-5N-Ydk" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="-478" y="955"/> + </scene> + <!--ReferencesVC--> + <scene sceneID="Qi9-my-V1s"> + <objects> + <viewController restorationIdentifier="ReferencesVC" storyboardIdentifier="ReferencesVC" extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="1wG-t8-xjS" customClass="ReferencesVC" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="IrU-sf-pxP"/> + <viewControllerLayoutGuide type="bottom" id="atY-QA-Qs8"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="357-00-U3r"> + <rect key="frame" x="0.0" y="0.0" width="320" height="300"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> + </view> + <nil key="simulatedStatusBarMetrics"/> + <nil key="simulatedTopBarMetrics"/> + <nil key="simulatedBottomBarMetrics"/> + <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> + <size key="freeformSize" width="320" height="300"/> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="Z8Q-li-V84" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="-478" y="559"/> + </scene> <!--Modal Menu And Content View Controller--> <scene sceneID="pAe-va-e4P"> <objects> @@ -1626,7 +1706,7 @@ </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="heC-Be-Fgw" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> - <point key="canvasLocation" x="89" y="434"/> + <point key="canvasLocation" x="478" y="501"/> </scene> <!--Center Nav Controller--> <scene sceneID="dor-Wk-JQd"> diff --git a/wikipedia/View Controllers/References/ReferenceGradientView.h b/wikipedia/View Controllers/References/ReferenceGradientView.h new file mode 100644 index 0000000..bfb2037 --- /dev/null +++ b/wikipedia/View Controllers/References/ReferenceGradientView.h @@ -0,0 +1,8 @@ +// Created by Monte Hurd on 7/30/14. +// Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; please copy and modify! + +#import <UIKit/UIKit.h> + +@interface ReferenceGradientView : UIView + +@end diff --git a/wikipedia/View Controllers/References/ReferenceGradientView.m b/wikipedia/View Controllers/References/ReferenceGradientView.m new file mode 100644 index 0000000..165a22a --- /dev/null +++ b/wikipedia/View Controllers/References/ReferenceGradientView.m @@ -0,0 +1,60 @@ +// Created by Monte Hurd on 7/30/14. +// Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; please copy and modify! + +#import "ReferenceGradientView.h" + +@implementation ReferenceGradientView + +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { + // Allow side-swipes to fall through to the references web view, but not + // if a sub view with userInteractionEnabled YES was tapped. + // See: http://stackoverflow.com/a/12355957 + for (UIView *view in self.subviews) { + if (view.userInteractionEnabled) { + if (CGRectContainsPoint(view.frame, point)) return YES; + } + } + return NO; +} + +- (void)drawRect:(CGRect)rect +{ + [super drawRect:rect]; + + CGContextRef ctx = UIGraphicsGetCurrentContext(); + + CGFloat topHalfAlpha = 0.88; + + // Make the gradient begin just below the vertical center. + CGFloat gradientTop = CGRectGetMidY(rect) + 10; + + // Draw opaque black in top half of rect. + CGRect topHalfRect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, gradientTop); + CGContextSetRGBFillColor(ctx, 0.0, 0.0, 0.0, topHalfAlpha); + CGContextSetRGBStrokeColor(ctx, 0.0, 0.0, 0.0, topHalfAlpha); + CGContextFillRect(ctx, topHalfRect); + + // Draw black to transparent gradient from middle to bottom of rect. + // Gradient drawing based on: http://stackoverflow.com/a/422208 + CGGradientRef gradient; + CGColorSpaceRef rgbSpace; + size_t locationCount = 2; + CGFloat locations[2] = { 0.0, 1.0 }; + CGFloat colorComponents[8] = { + 0.0, 0.0, 0.0, topHalfAlpha, // starting color + 0.0, 0.0, 0.0, 0.0 // ending color + }; + + rgbSpace = CGColorSpaceCreateDeviceRGB(); + gradient = CGGradientCreateWithColorComponents(rgbSpace, colorComponents, locations, locationCount); + + //CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f); + CGPoint midCenter = CGPointMake(CGRectGetMidX(rect), gradientTop); + CGPoint bottomCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); + CGContextDrawLinearGradient(ctx, gradient, midCenter, bottomCenter, 0); + + CGGradientRelease(gradient); + CGColorSpaceRelease(rgbSpace); +} + +@end diff --git a/wikipedia/View Controllers/References/ReferenceVC.h b/wikipedia/View Controllers/References/ReferenceVC.h new file mode 100644 index 0000000..8469104 --- /dev/null +++ b/wikipedia/View Controllers/References/ReferenceVC.h @@ -0,0 +1,18 @@ +// Created by Monte Hurd on 7/25/14. +// Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; please copy and modify! + +#import <UIKit/UIKit.h> + +@class WebViewController; +@interface ReferenceVC : UIViewController <UIWebViewDelegate> + +@property (assign, nonatomic) NSInteger index; + +@property (strong, nonatomic) NSString *html; + +@property (strong, nonatomic) NSString *linkId; +@property (strong, nonatomic) NSString *linkText; + +@property (weak, nonatomic) WebViewController *webVC; + +@end diff --git a/wikipedia/View Controllers/References/ReferenceVC.m b/wikipedia/View Controllers/References/ReferenceVC.m new file mode 100644 index 0000000..52c36ac --- /dev/null +++ b/wikipedia/View Controllers/References/ReferenceVC.m @@ -0,0 +1,171 @@ +// Created by Monte Hurd on 7/25/14. +// Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; please copy and modify! + +#import "ReferenceVC.h" +#import "WebViewController.h" +#import "SessionSingleton.h" +#import "MWLanguageInfo.h" +#import "WikipediaAppUtils.h" + +#define REFERENCE_LINK_COLOR @"#2b6fb2" + +@interface ReferenceVC () + +@property (strong, nonatomic) IBOutlet UIWebView *referenceWebView; + +@end + +@implementation ReferenceVC + +- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType +{ + //NSLog(@"request = %@ \ntype = %d", request, navigationType); + switch (navigationType) { + case UIWebViewNavigationTypeOther: + // YES allows the reference html to actually be loaded/displayed. + return YES; + break; + case UIWebViewNavigationTypeLinkClicked: { + NSURL *requestURL = [request URL]; + +// Test wiki link: +//requestURL = [NSURL URLWithString:@"/wiki/toast"]; + + NSString *scheme = [requestURL scheme]; + + // Open external link in Safari. + if ( + [scheme isEqualToString:@"http"] + || + [scheme isEqualToString:@"https"] + || + [scheme isEqualToString:@"mailto"] + ){ + [[UIApplication sharedApplication] openURL:requestURL]; + + // Or open wiki link in the WebViewController's web view. + }else if ([requestURL.path hasPrefix:@"/wiki/"]) { + + NSString *href = requestURL.path; + NSString *encodedTitle = [href substringWithRange:NSMakeRange(6, href.length - 6)]; + NSString *title = [encodedTitle stringByRemovingPercentEncoding]; + MWPageTitle *pageTitle = [MWPageTitle titleWithString:title]; + [self.webVC navigateToPage: pageTitle + domain: [SessionSingleton sharedInstance].currentArticleDomain + discoveryMethod: DISCOVERY_METHOD_LINK + invalidatingCache: NO]; + [self.webVC referencesHide]; + } + + return NO; + } + default: + return NO; + break; + } +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view. + + // Prevent this web view from blocking the article web view from scrolling to top + // when title bar tapped. (Only one scroll view can have scrollsToTop set to YES for + // the title bar tap to cause scroll-to-top.) + self.referenceWebView.scrollView.scrollsToTop = NO; + self.referenceWebView.delegate = self; + + NSString *domain = [SessionSingleton sharedInstance].currentArticleDomain; + MWLanguageInfo *languageInfo = [MWLanguageInfo languageInfoForCode:domain]; + NSString *baseUrl = [NSString stringWithFormat:@"https://%@.wikipedia.org/", languageInfo.code]; + + NSString *html = [NSString stringWithFormat:@"\ +<html>\ +<head>\ +<base href='%@' target='_self'>\ +<style>\ + *{\ + color:#999;\ + font-family:'Helvetica Neue';\ + font-size:14pt;\ + font-weight:normal;\ + line-height:148%%;\ + font-style:normal;\ + -webkit-text-size-adjust: none;\ + -webkit-hyphens: auto;\ + word-break: break-word;\ + }\ + BODY{\ + padding-left:10;\ + padding-right:10;\ + }\ + A, A *{\ + color:%@;\ + text-decoration:none;\ + }\ +</style>\ +</head>\ +<body style='background-color:black;' lang='%@' dir='%@'>\ +%@ %@\ +</body>\ +</html>\ +", baseUrl, REFERENCE_LINK_COLOR, languageInfo.code, languageInfo.dir, self.linkText, self.html]; + + [self.referenceWebView loadHTMLString:html baseURL:[NSURL URLWithString:@""]]; + + CGFloat topInset = 32; + + CGFloat bottomInset = (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) ? 0 : topInset; + + self.referenceWebView.scrollView.contentInset = UIEdgeInsetsMake(topInset, 0, bottomInset, 0); + + //self.webView.layer.borderColor = [UIColor whiteColor].CGColor; + //self.webView.layer.borderWidth = 25; + + //self.view.layer.borderColor = [UIColor whiteColor].CGColor; + //self.view.layer.borderWidth = 1; +} + +-(void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + + NSString *eval = [NSString stringWithFormat:@"\ + document.getElementById('%@').oldBackgroundColor = document.getElementById('%@').style.backgroundColor;\ + document.getElementById('%@').style.backgroundColor = '#999';\ + document.getElementById('%@').style.borderRadius = 2;\ + ", self.linkId, self.linkId, self.linkId, self.linkId]; + + [self.webVC.webView stringByEvaluatingJavaScriptFromString:eval]; +} + +-(void)viewWillDisappear:(BOOL)animated +{ + NSString *eval = [NSString stringWithFormat:@"\ + document.getElementById('%@').style.backgroundColor = document.getElementById('%@').oldBackgroundColor;\ + ", self.linkId, self.linkId]; + + [self.webVC.webView stringByEvaluatingJavaScriptFromString:eval]; + + [super viewWillDisappear:animated]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender +{ + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/wikipedia/View Controllers/References/ReferencesVC.h b/wikipedia/View Controllers/References/ReferencesVC.h new file mode 100644 index 0000000..b413baa --- /dev/null +++ b/wikipedia/View Controllers/References/ReferencesVC.h @@ -0,0 +1,17 @@ +// Created by Monte Hurd on 7/25/14. +// Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; please copy and modify! + +#import <UIKit/UIKit.h> + +@class WebViewController; +@interface ReferencesVC : UIViewController <UIPageViewControllerDataSource, UIPageViewControllerDelegate> + +@property (strong, nonatomic) UIPageViewController *pageController; + +@property (strong, nonatomic) NSDictionary *payload; + +@property (weak, nonatomic) WebViewController *webVC; + +-(void)reset; + +@end diff --git a/wikipedia/View Controllers/References/ReferencesVC.m b/wikipedia/View Controllers/References/ReferencesVC.m new file mode 100644 index 0000000..e8f251a --- /dev/null +++ b/wikipedia/View Controllers/References/ReferencesVC.m @@ -0,0 +1,521 @@ +// Created by Monte Hurd on 7/25/14. +// Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; please copy and modify! + +#import "ReferencesVC.h" +#import "ReferenceVC.h" +#import "WikiGlyphButton.h" +#import "WikiGlyphLabel.h" +#import "WikiGlyph_Chars.h" +#import "WikiGlyph_Chars_iOS.h" +#import "WebViewController.h" +#import "WikipediaAppUtils.h" +#import "UIView+Debugging.h" +#import "WMF_Colors.h" +#import "ReferenceGradientView.h" +#import "SessionSingleton.h" +#import "MWLanguageInfo.h" +#import "UIWebView+ElementLocation.h" + + + +// TODO: +// scroll up if link covered by refs panel +// ask brion where to put "a:hover {text-decoration: none;}" + + + + +// Show prev-next buttons instead of page dots if number of refs exceeds this number. +#define PAGE_CONTROL_MAX_REFS 10 +#define PAGE_CONTROL_DOT_COLOR 0x2b6fb2 + +@interface ReferencesVC () + +@property (strong, nonatomic) UIPageControl *topPageControl; +@property (strong, nonatomic) WikiGlyphButton *xButton; + +@property (strong, nonatomic) WikiGlyphButton *nextButton; +@property (strong, nonatomic) WikiGlyphButton *prevButton; + +@property (strong, nonatomic) ReferenceGradientView *topContainerView; + +@property (strong, nonatomic) NSArray *refs; +@property (nonatomic) NSUInteger refsIndex; +@property (strong, nonatomic) NSArray *linkIds; +@property (strong, nonatomic) NSArray *linkText; + +@end + +@implementation ReferencesVC + +-(void)reset +{ + // Load a fake blank set of data. + self.payload = @{ + @"linkId": @[@"fake_refs_id"], + @"linkText": @[@""], + @"refs": @[@""], + @"refsIndex": @(0) + }; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view. + + self.refs = @[@""]; + self.linkIds = @[]; + self.linkText = @[]; + self.refsIndex = 0; + + self.view.backgroundColor = [UIColor blackColor]; + + [self setupPageController]; + + [self setupTopContainer]; + + [self setupConstraints]; + + //self.view.layer.borderColor = [UIColor redColor].CGColor; + //self.view.layer.borderWidth = 10; + //[self.view randomlyColorSubviews]; +} + +- (void)setupPageController +{ + self.pageController = + [[UIPageViewController alloc] initWithTransitionStyle: UIPageViewControllerTransitionStyleScroll + navigationOrientation: UIPageViewControllerNavigationOrientationHorizontal + options: nil]; + + if(NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_6_1){ + // Needed for iOS 6. Otherwise a 20 pixel gap appears above. + self.pageController.wantsFullScreenLayout = YES; + } + + self.pageController.dataSource = self; + self.pageController.delegate = self; + + [self addChildViewController:self.pageController]; + [self.view addSubview:self.pageController.view]; + [self.pageController didMoveToParentViewController:self]; + + ReferenceVC *initialVC = [self viewControllerAtIndex:0]; + + if (initialVC){ + [self setViewControllers: @[initialVC] + direction: UIPageViewControllerNavigationDirectionForward + animated: NO + completion: nil]; + } +} + +- (void)setupTopContainer +{ + self.topContainerView = [[ReferenceGradientView alloc] init]; + + self.topContainerView.translatesAutoresizingMaskIntoConstraints = NO; + self.topContainerView.backgroundColor = [UIColor clearColor]; + [self.view addSubview:self.topContainerView]; + + self.xButton = [[WikiGlyphButton alloc] init]; + self.xButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.xButton.label setWikiText: WIKIGLYPH_X + color: [UIColor darkGrayColor] + size: 22 + baselineOffset: 0]; + self.xButton.label.textAlignment = NSTextAlignmentCenter; + self.xButton.userInteractionEnabled = YES; + [self.topContainerView addSubview:self.xButton]; + + BOOL isRTL = [WikipediaAppUtils isDeviceLanguageRTL]; + + self.nextButton = [[WikiGlyphButton alloc] init]; + self.nextButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.nextButton.label setWikiText: isRTL ? IOS_WIKIGLYPH_BACKWARD : IOS_WIKIGLYPH_FORWARD + color: [UIColor darkGrayColor] + size: 24 + baselineOffset: 2.0]; + self.nextButton.hidden = YES; + [self.topContainerView addSubview:self.nextButton]; + + self.prevButton = [[WikiGlyphButton alloc] init]; + self.prevButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.prevButton.label setWikiText: isRTL ? IOS_WIKIGLYPH_FORWARD : IOS_WIKIGLYPH_BACKWARD + color: [UIColor darkGrayColor] + size: 24 + baselineOffset: 2.0]; + self.prevButton.hidden = YES; + [self.topContainerView addSubview:self.prevButton]; + + UITapGestureRecognizer *prevTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(prevButtonTap)]; + [self.prevButton addGestureRecognizer:prevTap]; + + UITapGestureRecognizer *nextTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(nextButtonTap)]; + [self.nextButton addGestureRecognizer:nextTap]; + + UITapGestureRecognizer *xTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(xButtonTap)]; + [self.xButton addGestureRecognizer:xTap]; + + //self.nextButton.layer.borderWidth = 1; + //self.prevButton.layer.borderWidth = 1; + //self.nextButton.layer.borderColor = [UIColor whiteColor].CGColor; + //self.prevButton.layer.borderColor = [UIColor whiteColor].CGColor; + + //self.xButton.layer.borderWidth = 1; + //self.xButton.layer.borderColor = [UIColor whiteColor].CGColor; + + self.topPageControl = [[UIPageControl alloc] init]; + + //self.topPageControl.pageIndicatorTintColor = [UIColor redColor]; + self.topPageControl.currentPageIndicatorTintColor = UIColorFromRGBWithAlpha(PAGE_CONTROL_DOT_COLOR, 1.0); + + self.topPageControl.translatesAutoresizingMaskIntoConstraints = NO; + self.topPageControl.numberOfPages = 0; + self.topPageControl.currentPage = 0; + self.topPageControl.hidesForSinglePage = YES; + [self.topPageControl addTarget:self action:@selector(topPageControlTapped:) forControlEvents:UIControlEventValueChanged]; + [self.topContainerView addSubview:self.topPageControl]; + + // For now disable page control interactions. Taps are ok, but + // if you try to swipe the page control is doing something goofy + // with control events and swipes are sometimes falling through + // to the article web view, which causes the WebViewController + // to present the TOC. + self.topPageControl.userInteractionEnabled = NO; + + //self.topContainerView.layer.borderWidth = 1; + //self.topContainerView.layer.borderColor = [UIColor whiteColor].CGColor; +} + +-(void)xButtonTap +{ + [self.webVC referencesHide]; +} + +-(void)setupConstraints +{ + NSDictionary *views = @{ + @"xButton": self.xButton, + @"topPageControl": self.topPageControl, + @"topContainerView": self.topContainerView, + @"nextButton": self.nextButton, + @"prevButton": self.prevButton + }; + + NSDictionary *metrics = @{ + @"topItemsHeight": @50, + @"vPadding": @7, + @"hPadding": @14, + @"xWidth": @50 + }; + + [self.topContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"H:|[xButton(xWidth)]" + options: 0 + metrics: metrics + views: views]]; + + [self.topContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"H:[topPageControl]-(25)-|" + options: 0 + metrics: metrics + views: views]]; + + [self.topContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"V:|-(vPadding)-[xButton]-(vPadding)-|" + options: 0 + metrics: metrics + views: views]]; + + [self.topContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"V:|-(vPadding)-[nextButton]-(vPadding)-|" + options: 0 + metrics: metrics + views: views]]; + + [self.topContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"V:|-(vPadding)-[prevButton]-(vPadding)-|" + options: 0 + metrics: metrics + views: views]]; + + [self.topContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"H:[prevButton]-(20)-[nextButton]-(hPadding)-|" + options: 0 + metrics: metrics + views: views]]; + + [self.topContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"V:|-(vPadding)-[topPageControl]-(vPadding)-|" + options: 0 + metrics: metrics + views: views]]; + + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"V:|[topContainerView(topItemsHeight)]" + options: 0 + metrics: metrics + views: views]]; + + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"H:|[topContainerView]|" + options: 0 + metrics: metrics + views: views]]; +} + +-(NSArray *)refs +{ + if (!_refs || (_refs.count == 0)) return @[@""]; + return self.payload[@"refs"]; +} + +-(NSUInteger)refsIndex +{ + NSNumber *index = self.payload[@"refsIndex"]; + return index.integerValue; +} + +-(NSArray *)linkIds +{ + return self.payload[@"linkId"]; +} + +-(NSArray *)linkText +{ + return self.payload[@"linkText"]; +} + +-(NSDictionary *)reversePayloadArraysIfRTL:(NSDictionary *)payload +{ + //NSString *domain = [SessionSingleton sharedInstance].currentArticleDomain; + //MWLanguageInfo *languageInfo = [MWLanguageInfo languageInfoForCode:domain]; + BOOL isRTL = [WikipediaAppUtils isDeviceLanguageRTL]; + if (isRTL) { + //if ([languageInfo.dir isEqualToString:@"ltr"]) { + NSArray *a = payload[@"linkId"]; + if (a.count > 0) { + NSNumber *n = payload[@"refsIndex"]; + payload = @{ + @"linkId": [[payload[@"linkId"] reverseObjectEnumerator] allObjects], + @"linkText": [[payload[@"linkText"] reverseObjectEnumerator] allObjects], + @"refs": [[payload[@"refs"] reverseObjectEnumerator] allObjects], + @"refsIndex": @((a.count-1) - n.integerValue) + }; + } + } + return payload; +} + +-(void)scrollTappedReferenceUp +{ + NSNumber *n = self.payload[@"refsIndex"]; + if (!n) return; + NSArray *a = self.payload[@"linkId"]; + if (!a) return; + NSString *elementId = a[n.integerValue]; + if (!elementId) return; + CGRect r = [self.webVC.webView getScreenRectForHtmlElementWithId:elementId]; + if (!CGRectIsNull(r)) { + CGPoint p = CGPointMake( + self.webVC.webView.scrollView.contentOffset.x, + self.webVC.webView.scrollView.contentOffset.y + (r.origin.y - 70) + ); + [self.webVC.webView.scrollView setContentOffset:p animated:YES]; + }; +} + +-(void)setPayload:(NSDictionary *)payload +{ + payload = [self reversePayloadArraysIfRTL:payload]; + + _payload = payload; + + [self scrollTappedReferenceUp]; + + BOOL hidePageControl = (self.refs.count > PAGE_CONTROL_MAX_REFS); + self.prevButton.hidden = (!hidePageControl) || (self.refs.count < 2); + self.nextButton.hidden = (!hidePageControl) || (self.refs.count < 2); + // Use alpha - other changes to page control properties apparently cause it to be + // set to be not hidden. This way all that other code can remain as-is. + self.topPageControl.alpha = (hidePageControl ? 0.0 : 1.0); + + UIPageViewControllerNavigationDirection dir = (self.topPageControl.currentPage < self.refsIndex) + ? + UIPageViewControllerNavigationDirectionForward + : + UIPageViewControllerNavigationDirectionReverse; + + BOOL shouldAnimate = ((self.refs.count == 1) ? NO: YES); + + if (self.topPageControl.currentPage == self.refsIndex) shouldAnimate = NO; + + [self setViewControllers: @[[self viewControllerAtIndex:self.refsIndex]] + direction: dir + animated: shouldAnimate + completion: nil]; + + self.topPageControl.numberOfPages = self.refs.count; + self.topPageControl.currentPage = self.refsIndex; +} + +-(void)refViewDidAppear:(NSUInteger)index +{ + self.prevButton.enabled = (index <= 0) ? NO : YES; + self.nextButton.enabled = (index >= (self.refs.count - 1)) ? NO : YES; +} + +- (void)setViewControllers: (NSArray *)viewControllers + direction: (UIPageViewControllerNavigationDirection)direction + animated: (BOOL)animated + completion: (void (^)(BOOL finished))completion +{ + // UIPageViewController is ridiculous. Making it jump to a specific page is tricky - it + // will not then swipe back or forward correctly. This method fixes that. Use it rather + // than calling UIPageViewController's "setViewControllers" method directly. + // Based on: http://stackoverflow.com/a/18602186 + + __weak ReferencesVC *weakSelf = self; + [self.pageController setViewControllers: viewControllers + direction: direction + animated: animated + completion: ^(BOOL finished) { + if (!weakSelf.pageController) return; + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf.pageController setViewControllers: viewControllers + direction: direction + animated: NO + completion: ^(BOOL done){ + [weakSelf refViewDidAppear:weakSelf.topPageControl.currentPage]; + }]; + }); + }]; +} + +- (void)pageViewController: (UIPageViewController *)pageViewController + didFinishAnimating: (BOOL)finished + previousViewControllers: (NSArray *)previousViewControllers + transitionCompleted: (BOOL)completed +{ + // UIPageViewController was swiped. + // Update the UIPageControl dots to reflect the UIPageViewController selection. + ReferenceVC *currentView = [pageViewController.viewControllers objectAtIndex:0]; + self.topPageControl.currentPage = currentView.index; + + [self refViewDidAppear:self.topPageControl.currentPage]; +} + +- (ReferenceVC *)viewControllerAtIndex:(NSInteger)index +{ + if (index < 0) return nil; + if (index >= self.refs.count) return nil; + + ReferenceVC *refVC = [self.storyboard instantiateViewControllerWithIdentifier:@"ReferenceVC"]; + refVC.webVC = self.webVC; + refVC.index = index; + refVC.html = self.refs[index]; + refVC.linkId = self.linkIds[index]; + refVC.linkText = self.linkText[index]; + + return refVC; +} + +- (UIViewController *)pageViewController: (UIPageViewController *)pageViewController + viewControllerBeforeViewController: (UIViewController *)viewController +{ + return [self viewControllerAtIndex:(((ReferenceVC *)viewController).index - 1)]; +} + +- (UIViewController *)pageViewController: (UIPageViewController *)pageViewController + viewControllerAfterViewController: (UIViewController *)viewController +{ + return [self viewControllerAtIndex:(((ReferenceVC *)viewController).index + 1)]; +} + +-(void)topPageControlTapped:(id)sender +{ + // UIPageControl was tapped. + // Update the UIPageViewController to reflect the UIPageControl selection. + + ReferenceVC *currentView = [self.pageController.viewControllers objectAtIndex:0]; + BOOL isTopPageControlAhead = (self.topPageControl.currentPage > currentView.index); + + id nextVC = isTopPageControlAhead + ? + [self pageViewController:self.pageController viewControllerAfterViewController:currentView] + : + [self pageViewController:self.pageController viewControllerBeforeViewController:currentView]; + + UIPageViewControllerNavigationDirection dir = isTopPageControlAhead + ? + UIPageViewControllerNavigationDirectionForward + : + UIPageViewControllerNavigationDirectionReverse; + + if (nextVC) { + [self setViewControllers: @[nextVC] + direction: dir + animated: YES + completion: nil]; + } +} + +-(void)prevButtonTap +{ + if (!self.prevButton.enabled) return; + + BOOL isRTL = [WikipediaAppUtils isDeviceLanguageRTL]; + + UIPageViewControllerNavigationDirection dir = isRTL + ? + UIPageViewControllerNavigationDirectionForward + : + UIPageViewControllerNavigationDirectionReverse; + + [self setViewControllers: @[[self viewControllerAtIndex:(--self.topPageControl.currentPage)]] + direction: dir + animated: YES + completion: nil]; +} + +-(void)nextButtonTap +{ + if (!self.nextButton.enabled) return; + + BOOL isRTL = [WikipediaAppUtils isDeviceLanguageRTL]; + + UIPageViewControllerNavigationDirection dir = isRTL + ? + UIPageViewControllerNavigationDirectionReverse + : + UIPageViewControllerNavigationDirectionForward; + + [self setViewControllers: @[[self viewControllerAtIndex:(++self.topPageControl.currentPage)]] + direction: dir + animated: YES + completion: nil]; +} + +/* +// Commented out these two methods to hide the built-in UIPageControl. +// See: http://stackoverflow.com/a/20749979 +- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController { + return 5; +} + +- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController { + return 0; +} +*/ + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender +{ + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/wikipedia/View Controllers/TableOfContents/TOCViewController.m b/wikipedia/View Controllers/TableOfContents/TOCViewController.m index 805d9ad..8bcf97b 100644 --- a/wikipedia/View Controllers/TableOfContents/TOCViewController.m +++ b/wikipedia/View Controllers/TableOfContents/TOCViewController.m @@ -64,8 +64,6 @@ self.scrollContainer.translatesAutoresizingMaskIntoConstraints = NO; self.scrollContainer.backgroundColor = [UIColor clearColor]; - - self.scrollView.scrollsToTop = NO; // Adjust scrollview content inset when contentSize changes so bottom entry can be scrolled to top. [self.scrollView addObserver: self @@ -76,9 +74,17 @@ [self refreshForCurrentArticle]; } +- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView +{ + [self.webVC.webView.scrollView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; + return YES; +} + -(void)viewWillDisappear:(BOOL)animated { [self.funnel logClose]; + + self.webVC.webView.scrollView.scrollsToTop = YES; [super viewWillDisappear:animated]; } @@ -87,6 +93,9 @@ { [super viewDidAppear:animated]; + self.scrollView.scrollsToTop = YES; + self.webVC.webView.scrollView.scrollsToTop = NO; + [self.funnel logOpen]; } diff --git a/wikipedia/View Controllers/WebView/WebViewController.h b/wikipedia/View Controllers/WebView/WebViewController.h index b3a9d7a..68ca8d9 100644 --- a/wikipedia/View Controllers/WebView/WebViewController.h +++ b/wikipedia/View Controllers/WebView/WebViewController.h @@ -11,6 +11,10 @@ @property (weak, nonatomic) IBOutlet UIWebView *webView; @property (nonatomic) BOOL bottomMenuHidden; +@property (nonatomic) BOOL referencesHidden; + +-(void)referencesShow; +-(void)referencesHide; // Reloads the current article from the core data cache. // If "invalidateCache" is set to YES the article will be re-downloaded first. diff --git a/wikipedia/View Controllers/WebView/WebViewController.m b/wikipedia/View Controllers/WebView/WebViewController.m index 59bc476..0b02456 100644 --- a/wikipedia/View Controllers/WebView/WebViewController.m +++ b/wikipedia/View Controllers/WebView/WebViewController.m @@ -51,6 +51,7 @@ #import "TopMenuContainerView.h" #import "WikiGlyph_Chars.h" #import "UINavigationController+TopActionSheet.h" +#import "ReferencesVC.h" //#import "UIView+Debugging.h" @@ -92,8 +93,12 @@ @property (nonatomic) BOOL unsafeToToggleTOC; @property (weak, nonatomic) BottomMenuViewController *bottomMenuViewController; +@property (weak, nonatomic) ReferencesVC *referencesVC; +@property (weak, nonatomic) IBOutlet UIView *referencesContainerView; @property (strong, nonatomic) NSLayoutConstraint *bottomBarViewBottomConstraint; +@property (strong, nonatomic) IBOutlet NSLayoutConstraint *referencesContainerViewBottomConstraint; +@property (strong, nonatomic) IBOutlet NSLayoutConstraint *referencesContainerViewHeightConstraint; @property (copy) NSString *jumpToFragment; @@ -235,7 +240,8 @@ - +//self.referencesContainerView.layer.borderWidth = 10; +//self.referencesContainerView.layer.borderColor = [UIColor redColor].CGColor; } @@ -313,6 +319,7 @@ [super viewWillAppear:animated]; self.bottomMenuHidden = ROOT.topMenuHidden; + self.referencesHidden = YES; ROOT.topMenuViewController.navBarMode = NAVBAR_MODE_DEFAULT; [ROOT.topMenuViewController updateTOCButtonVisibility]; @@ -451,6 +458,9 @@ [self.view setNeedsUpdateConstraints]; self.webView.transform = CGAffineTransformIdentity; + + self.referencesContainerView.transform = CGAffineTransformIdentity; + self.bottomBarView.transform = CGAffineTransformIdentity; self.webViewRightConstraint.constant = 0; @@ -501,8 +511,10 @@ animations: ^{ self.bottomMenuHidden = YES; + self.referencesHidden = YES; [self.view setNeedsUpdateConstraints]; self.webView.transform = xf; + self.referencesContainerView.transform = xf; self.bottomBarView.transform = xf; self.webViewRightConstraint.constant = [self tocGetWidthForWebViewScale:webViewScale]; [self.view layoutIfNeeded]; @@ -608,7 +620,9 @@ if (!currentArticleTitle || (currentArticleTitle.length == 0)) return; if (recognizer.state == UIGestureRecognizerStateEnded){ - [self tocShow]; + if (self.referencesHidden) { + [self tocShow]; + } } } @@ -809,6 +823,8 @@ [weakSelf tocHide]; return; } + + if(!weakSelf.referencesHidden) [weakSelf referencesHide]; // @todo merge this link title extraction into MWSite if ([href hasPrefix:@"/wiki/"]) { @@ -896,10 +912,21 @@ // nonAnchorTouchEndedWithoutDragging is used so TOC may be hidden if user tapped, but did *not* drag. // Used because UIWebView is difficult to attach one-finger touch events to. [weakSelf tocHide]; + + [weakSelf referencesHide]; }]; [self.bridge addListener:@"referenceClicked" withBlock:^(NSString *messageType, NSDictionary *payload) { - NSLog(@"referenceClicked: %@", payload); + + if([weakSelf tocDrawerIsOpen]){ + [weakSelf tocHide]; + return; + } + + //NSLog(@"referenceClicked: %@", payload); + weakSelf.referencesVC.payload = payload; + [weakSelf referencesShow]; + }]; self.unsafeToScroll = NO; @@ -1089,6 +1116,8 @@ if (fabsf(distanceScrolled) < minPixelsScrolled) return; [ROOT animateTopAndBottomMenuHidden:((distanceScrolled > 0) ? NO : YES)]; + + [self referencesHide]; } } @@ -1106,6 +1135,8 @@ - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView { + [self referencesHide]; + // Called when the title bar is tapped. [self animateTopAndBottomMenuReveal]; return YES; @@ -1136,6 +1167,9 @@ //[[SessionSingleton sharedInstance].zeroConfigState toggleFakeZeroOn]; //[self toggleImageSheet]; + + //ReferencesVC *referencesVC = [self.navigationController.storyboard instantiateViewControllerWithIdentifier:@"ReferencesVC"]; + //[self presentViewController:referencesVC animated:YES completion:^{}]; } -(void)toggleImageSheet @@ -1927,6 +1961,11 @@ if ([segue.identifier isEqualToString: @"BottomMenuViewController_embed2"]) { self.bottomMenuViewController = (BottomMenuViewController *) [segue destinationViewController]; } + + if ([segue.identifier isEqualToString: @"ReferencesVC_embed"]) { + self.referencesVC = (ReferencesVC *) [segue destinationViewController]; + self.referencesVC.webVC = self; + } } -(void)setBottomMenuHidden:(BOOL)bottomMenuHidden @@ -2030,4 +2069,64 @@ [alert show]; } +#pragma mark Refs + +-(void)setReferencesHidden:(BOOL)referencesHidden +{ + if (self.referencesHidden == referencesHidden) return; + + _referencesHidden = referencesHidden; + + [self updateReferencesHeightAndBottomConstraints]; + + if (referencesHidden) { + // Cause the highlighted ref link in the webView to no longer be highlighted. + [self.referencesVC reset]; + } + + // Fade out refs when hidden. + CGFloat alpha = referencesHidden ? 0.0 : 1.0; + + self.referencesContainerView.alpha = alpha; +} + +-(void)updateReferencesHeightAndBottomConstraints +{ + CGFloat percentOfHeight = UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? 0.4 : 0.6; + if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) percentOfHeight *= 0.5; + NSNumber *refsHeight = @(self.view.frame.size.height * percentOfHeight); + CGFloat f = self.referencesHidden ? refsHeight.integerValue : 0; + self.referencesContainerViewBottomConstraint.constant = f; + self.referencesContainerViewHeightConstraint.constant = refsHeight.integerValue; +} + +-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration +{ + [self updateReferencesHeightAndBottomConstraints]; +} + +-(void)referencesShow +{ + if (!self.referencesHidden) return; + [UIView animateWithDuration: 0.16 + delay: 0.0f + options: UIViewAnimationOptionBeginFromCurrentState + animations: ^{ + self.referencesHidden = NO; + [self.view layoutIfNeeded]; + }completion:nil]; +} + +-(void)referencesHide +{ + if (self.referencesHidden) return; + [UIView animateWithDuration: 0.16 + delay: 0.0f + options: UIViewAnimationOptionBeginFromCurrentState + animations: ^{ + self.referencesHidden = YES; + [self.view layoutIfNeeded]; + }completion:nil]; +} + @end diff --git a/wikipedia/assets/index.html b/wikipedia/assets/index.html index a207b8b..4105d36 100644 --- a/wikipedia/assets/index.html +++ b/wikipedia/assets/index.html @@ -8,6 +8,13 @@ <base href="https://wikipedia.org"> + <style type="text/css"> + /* Note: this was added so ref link taps don't show underline. Move upstream later if possible. */ + + a:hover {text-decoration: none;} + + </style> + </head> <body> <div class="content" id="content"> diff --git a/www/index.html b/www/index.html index a207b8b..4105d36 100644 --- a/www/index.html +++ b/www/index.html @@ -8,6 +8,13 @@ <base href="https://wikipedia.org"> + <style type="text/css"> + /* Note: this was added so ref link taps don't show underline. Move upstream later if possible. */ + + a:hover {text-decoration: none;} + + </style> + </head> <body> <div class="content" id="content"> -- To view, visit https://gerrit.wikimedia.org/r/150964 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie3ad35d6065c874eca0d7289cf190bc3e2bc8156 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