diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index c6586ca6d..8a3f85d48 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -158,12 +158,12 @@ isa = PBXNativeTarget; buildConfigurationList = 1A42C29B1C0E3883000F2137 /* Build configuration list for PBXNativeTarget "Example" */; buildPhases = ( - BFF78AC0EC7FAA2ADF7765C4 /* 📦 Check Pods Manifest.lock */, + BFF78AC0EC7FAA2ADF7765C4 /* [CP] Check Pods Manifest.lock */, 1A42C2851C0E3882000F2137 /* Sources */, 1A42C2861C0E3882000F2137 /* Frameworks */, 1A42C2871C0E3882000F2137 /* Resources */, - B6A166DC30D64CDC32736E22 /* 📦 Embed Pods Frameworks */, - 8F716768EB59E9B6D88C48D7 /* 📦 Copy Pods Resources */, + B6A166DC30D64CDC32736E22 /* [CP] Embed Pods Frameworks */, + 8F716768EB59E9B6D88C48D7 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -178,12 +178,12 @@ isa = PBXNativeTarget; buildConfigurationList = CA10C1381C572A4B0049165D /* Build configuration list for PBXNativeTarget "FolioReaderTests" */; buildPhases = ( - 1D8126CC73301F2413345444 /* 📦 Check Pods Manifest.lock */, + 1D8126CC73301F2413345444 /* [CP] Check Pods Manifest.lock */, CA10C12D1C572A4B0049165D /* Sources */, CA10C12E1C572A4B0049165D /* Frameworks */, CA10C12F1C572A4B0049165D /* Resources */, - C1392FF51E4FD15EBB5AA8DD /* 📦 Embed Pods Frameworks */, - 652A7706A17894A2B0BA1503 /* 📦 Copy Pods Resources */, + C1392FF51E4FD15EBB5AA8DD /* [CP] Embed Pods Frameworks */, + 652A7706A17894A2B0BA1503 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -263,14 +263,14 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1D8126CC73301F2413345444 /* 📦 Check Pods Manifest.lock */ = { + 1D8126CC73301F2413345444 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -278,14 +278,14 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - 652A7706A17894A2B0BA1503 /* 📦 Copy Pods Resources */ = { + 652A7706A17894A2B0BA1503 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -293,14 +293,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FolioReaderTests/Pods-FolioReaderTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 8F716768EB59E9B6D88C48D7 /* 📦 Copy Pods Resources */ = { + 8F716768EB59E9B6D88C48D7 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -308,14 +308,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example/Pods-Example-resources.sh\"\n"; showEnvVarsInLog = 0; }; - B6A166DC30D64CDC32736E22 /* 📦 Embed Pods Frameworks */ = { + B6A166DC30D64CDC32736E22 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Embed Pods Frameworks"; + name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -323,14 +323,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - BFF78AC0EC7FAA2ADF7765C4 /* 📦 Check Pods Manifest.lock */ = { + BFF78AC0EC7FAA2ADF7765C4 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -338,14 +338,14 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - C1392FF51E4FD15EBB5AA8DD /* 📦 Embed Pods Frameworks */ = { + C1392FF51E4FD15EBB5AA8DD /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Embed Pods Frameworks"; + name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Example/Example/ViewController.swift b/Example/Example/ViewController.swift index d61afeb52..babf98373 100755 --- a/Example/Example/ViewController.swift +++ b/Example/Example/ViewController.swift @@ -32,6 +32,7 @@ class ViewController: UIViewController { func openEpub(sampleNum:Int) { let config = FolioReaderConfig() config.shouldHideNavigationOnTap = sampleNum == 1 ? true : false + config.scrollDirection = sampleNum == 1 ? .horizontal : .vertical // See more at FolioReaderConfig.swift // config.enableTTS = false diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 5db85bc10..9dcfbf6c7 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -37,4 +37,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 7bafcb0eb37bf78bf161a6ebcb80be176777e3a8 -COCOAPODS: 1.0.0 +COCOAPODS: 1.0.1 diff --git a/Source/FolioReaderCenter.swift b/Source/FolioReaderCenter.swift index 27ef9ec6a..47be698fa 100755 --- a/Source/FolioReaderCenter.swift +++ b/Source/FolioReaderCenter.swift @@ -93,7 +93,8 @@ class ScrollScrubber: NSObject, UIScrollViewDelegate { } func sliderChange(slider:UISlider) { - let offset = CGPointMake(0, height()*CGFloat(slider.value)) + let offset = isVerticalDirection(CGPointMake(0, height()*CGFloat(slider.value)), + CGPointMake(height()*CGFloat(slider.value), 0)) scrollView().setContentOffset(offset, animated: false) } @@ -157,11 +158,12 @@ class ScrollScrubber: NSObject, UIScrollViewDelegate { } if scrollStart == nil { - scrollStart = scrollView.contentOffset.y + scrollStart = scrollView.contentOffset.forDirection() } } func scrollViewDidScroll(scrollView: UIScrollView) { + guard readerConfig.scrollDirection == .vertical else { return } if visible && usingSlider == false { setSliderVal() @@ -172,7 +174,7 @@ class ScrollScrubber: NSObject, UIScrollViewDelegate { show() } else if delegate.currentPage != nil && scrollStart != nil { - scrollDelta = scrollView.contentOffset.y - scrollStart + scrollDelta = scrollView.contentOffset.forDirection() - scrollStart if scrollDeltaTimer == nil && scrollDelta > (pageHeight * 0.2 ) || (scrollDelta * -1) > (pageHeight * 0.2) { show() @@ -197,7 +199,7 @@ class ScrollScrubber: NSObject, UIScrollViewDelegate { scrollDeltaTimer = nil } - scrollStart = scrollView().contentOffset.y + scrollStart = scrollView().contentOffset.forDirection() scrollDelta = 0 } @@ -217,7 +219,7 @@ class ScrollScrubber: NSObject, UIScrollViewDelegate { } private func scrollTop() -> CGFloat { - return delegate.currentPage.webView.scrollView.contentOffset.y + return delegate.currentPage.webView.scrollView.contentOffset.forDirection() } } @@ -241,7 +243,8 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio private var screenBounds: CGRect! private var pointNow = CGPointZero - private let pageIndicatorHeight = 20 as CGFloat + private let pageIndicatorHeight: CGFloat = 20 + private var pageOffsetRate: CGFloat = 0 // MARK: - View life cicle @@ -256,7 +259,7 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio layout.sectionInset = UIEdgeInsetsZero layout.minimumLineSpacing = 0 layout.minimumInteritemSpacing = 0 - layout.scrollDirection = UICollectionViewScrollDirection.Vertical + layout.scrollDirection = .direction() let background = isNight(readerConfig.nightModeBackground, UIColor.whiteColor()) view.backgroundColor = background @@ -268,6 +271,7 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio collectionView.dataSource = self collectionView.pagingEnabled = true collectionView.showsVerticalScrollIndicator = false + collectionView.showsHorizontalScrollIndicator = false collectionView.backgroundColor = background collectionView.decelerationRate = UIScrollViewDecelerationRateFast view.addSubview(collectionView) @@ -320,6 +324,12 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio let navText = isNight(UIColor.whiteColor(), UIColor.blackColor()) let font = UIFont(name: "Avenir-Light", size: 17)! setTranslucentNavigation(color: navBackground, tintColor: tintColor, titleColor: navText, andFont: font) + +// if FolioReader.sharedInstance.nightMode { +// UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true) +// } else { +// UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.Default, animated: true) +// } } func configureNavBarButtons() { @@ -540,13 +550,20 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio self.pageIndicatorView.frame = pageIndicatorFrame self.pageIndicatorView.reloadView(updateShadow: true) - // adjust scroll scrubber slider + // Adjust scroll scrubber slider self.scrollScrubber.slider.frame = scrollScrubberFrame // Adjust collectionView - self.collectionView.contentSize = CGSizeMake(pageWidth, pageHeight * CGFloat(self.totalPages)) + self.collectionView.contentSize = isVerticalDirection( + CGSize(width: pageWidth, height: pageHeight * CGFloat(self.totalPages)), + CGSize(width: pageWidth * CGFloat(self.totalPages), height: pageHeight) + ) self.collectionView.setContentOffset(self.frameForPage(currentPageNumber).origin, animated: false) self.collectionView.collectionViewLayout.invalidateLayout() + + // Adjust internal page offset + let pageScrollView = self.currentPage.webView.scrollView + self.pageOffsetRate = pageScrollView.contentOffset.forDirection() / pageScrollView.contentSize.forDirection() }) } @@ -557,6 +574,18 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio pagesForCurrentPage(currentPage) scrollScrubber.setSliderVal() + + // After rotation fix internal page offset + var pageOffset = self.currentPage.webView.scrollView.contentSize.forDirection() * pageOffsetRate + + // Fix the offset for paged scroll + if readerConfig.scrollDirection == .horizontal { + var page = round(pageOffset / pageWidth) + pageOffset = page * pageWidth + } + + let pageOffsetPoint = isVerticalDirection(CGPoint(x: 0, y: pageOffset), CGPoint(x: pageOffset, y: 0)) + self.currentPage.webView.scrollView.setContentOffset(pageOffsetPoint, animated: true) } override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { @@ -627,8 +656,11 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio if let readingTime = page.webView.js("getReadingTime()") { pageIndicatorView.totalMinutes = Int(readingTime)! - pagesForCurrentPage(page) + + } else { + pageIndicatorView.totalMinutes = 0 } + pagesForCurrentPage(page) } if (completion != nil) { completion!() } @@ -636,8 +668,9 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio func pagesForCurrentPage(page: FolioReaderPage?) { if let page = page { - pageIndicatorView.totalPages = Int(ceil(page.webView.scrollView.contentSize.height/pageHeight)) - let webViewPage = pageForOffset(currentPage.webView.scrollView.contentOffset.y, pageHeight: pageHeight) + let pageSize = isVerticalDirection(pageHeight, pageWidth) + pageIndicatorView.totalPages = Int(ceil(page.webView.scrollView.contentSize.forDirection()/pageSize)) + let webViewPage = pageForOffset(currentPage.webView.scrollView.contentOffset.x, pageHeight: pageSize) pageIndicatorView.currentPage = webViewPage } } @@ -677,7 +710,10 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio } func frameForPage(page: Int) -> CGRect { - return CGRectMake(0, pageHeight * CGFloat(page-1), pageWidth, pageHeight) + return isVerticalDirection( + CGRectMake(0, pageHeight * CGFloat(page-1), pageWidth, pageHeight), + CGRectMake(pageWidth * CGFloat(page-1), 0, pageWidth, pageHeight) + ) } func changePageWith(page page: Int, animated: Bool = false, completion: (() -> Void)? = nil) { @@ -746,7 +782,7 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio } UIView.animateWithDuration(animated ? 0.3 : 0, delay: 0, options: .CurveEaseInOut, animations: { () -> Void in - self.collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Top, animated: false) + self.collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .direction(), animated: false) }) { (finished: Bool) -> Void in if (completion != nil) { completion!() } } @@ -977,7 +1013,11 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio if let position = FolioReader.defaults.valueForKey(kBookId) as? NSDictionary { let pageNumber = position["pageNumber"]! as! Int - let pageOffset = position["pageOffset"]! as! CGFloat + var pageOffset: CGFloat = 0 + + if let offset = isVerticalDirection(position["pageOffsetY"], position["pageOffsetX"]) as? CGFloat { + pageOffset = offset + } if isFirstLoad { updateCurrentPage(page) @@ -1014,6 +1054,12 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio } scrollScrubber.scrollViewWillBeginDragging(scrollView) + +// let currentPageNum = Int(pointNow.x / scrollView.bounds.size.width) + 1 +// if currentPage.webView.pageCount - 1 == currentPageNum { +// currentPage.refreshPageMode() +// } + currentPage.refreshPageMode() } func scrollViewDidScroll(scrollView: UIScrollView) { @@ -1026,15 +1072,18 @@ class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectio // Update current reading page if scrollView is UICollectionView {} else { - if let page = currentPage where page.webView.scrollView.contentOffset.y+pageHeight <= page.webView.scrollView.contentSize.height { - let webViewPage = pageForOffset(page.webView.scrollView.contentOffset.y, pageHeight: pageHeight) + let pageSize = isVerticalDirection(pageHeight, pageWidth) + + if let page = currentPage + where page.webView.scrollView.contentOffset.forDirection()+pageSize <= page.webView.scrollView.contentSize.forDirection() { + let webViewPage = pageForOffset(page.webView.scrollView.contentOffset.forDirection(), pageHeight: pageSize) if pageIndicatorView.currentPage != webViewPage { pageIndicatorView.currentPage = webViewPage } } } - scrollDirection = scrollView.contentOffset.y < pointNow.y ? .Down : .Up + scrollDirection = scrollView.contentOffset.forDirection() < pointNow.forDirection() ? .negative() : .positive() } func scrollViewDidEndDecelerating(scrollView: UIScrollView) { diff --git a/Source/FolioReaderConfig.swift b/Source/FolioReaderConfig.swift index ba4880b96..06fa421b5 100755 --- a/Source/FolioReaderConfig.swift +++ b/Source/FolioReaderConfig.swift @@ -8,6 +8,26 @@ import UIKit +public enum FolioReaderScrollDirection: Int { + + // Using Swift 3.0 specification: lower camel-case on enum cases + + case vertical + case horizontal + + /** + Returns the `UICollectionViewFlowLayout` scroll direction. + */ + public func collectionViewScrollDirection() -> UICollectionViewScrollDirection { + switch self { + case vertical: + return .Vertical + case horizontal: + return .Horizontal + } + } +} + public class FolioReaderConfig: NSObject { // Reader Colors public var tintColor: UIColor! @@ -22,6 +42,7 @@ public class FolioReaderConfig: NSObject { public lazy var mediaOverlayColor: UIColor! = self.tintColor // Custom actions + public var scrollDirection: FolioReaderScrollDirection = .vertical public var shouldHideNavigationOnTap = true public var allowSharing = true public var enableTTS = true diff --git a/Source/FolioReaderContainer.swift b/Source/FolioReaderContainer.swift index 9ea4ff4bc..45261c5a4 100755 --- a/Source/FolioReaderContainer.swift +++ b/Source/FolioReaderContainer.swift @@ -99,8 +99,9 @@ class FolioReaderContainer: UIViewController, FolioReaderSidePanelDelegate { // Add gestures let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(FolioReaderContainer.handleTapGesture(_:))) tapGestureRecognizer.numberOfTapsRequired = 1 - let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(FolioReaderContainer.handlePanGesture(_:))) centerNavigationController.view.addGestureRecognizer(tapGestureRecognizer) + + let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(FolioReaderContainer.handlePanGesture(_:))) centerNavigationController.view.addGestureRecognizer(panGestureRecognizer) // Read async book @@ -255,6 +256,8 @@ class FolioReaderContainer: UIViewController, FolioReaderSidePanelDelegate { } func handlePanGesture(recognizer: UIPanGestureRecognizer) { + guard readerConfig.scrollDirection == .vertical else { return } + let gestureIsDraggingFromLeftToRight = (recognizer.velocityInView(view).x > 0) switch(recognizer.state) { diff --git a/Source/FolioReaderKit.swift b/Source/FolioReaderKit.swift index 792047053..d89323ece 100755 --- a/Source/FolioReaderKit.swift +++ b/Source/FolioReaderKit.swift @@ -70,14 +70,12 @@ public class FolioReader : NSObject { get { return FolioReader.defaults.boolForKey(kNightMode) } set (value) { FolioReader.defaults.setBool(value, forKey: kNightMode) - FolioReader.defaults.synchronize() } } var currentFontName: Int { get { return FolioReader.defaults.valueForKey(kCurrentFontFamily) as! Int } set (value) { FolioReader.defaults.setValue(value, forKey: kCurrentFontFamily) - FolioReader.defaults.synchronize() } } @@ -85,7 +83,6 @@ public class FolioReader : NSObject { get { return FolioReader.defaults.valueForKey(kCurrentFontSize) as! Int } set (value) { FolioReader.defaults.setValue(value, forKey: kCurrentFontSize) - FolioReader.defaults.synchronize() } } @@ -93,7 +90,6 @@ public class FolioReader : NSObject { get { return FolioReader.defaults.valueForKey(kCurrentAudioRate) as! Int } set (value) { FolioReader.defaults.setValue(value, forKey: kCurrentAudioRate) - FolioReader.defaults.synchronize() } } @@ -101,7 +97,6 @@ public class FolioReader : NSObject { get { return FolioReader.defaults.valueForKey(kCurrentHighlightStyle) as! Int } set (value) { FolioReader.defaults.setValue(value, forKey: kCurrentHighlightStyle) - FolioReader.defaults.synchronize() } } @@ -109,7 +104,6 @@ public class FolioReader : NSObject { get { return MediaOverlayStyle(rawValue: FolioReader.defaults.valueForKey(kCurrentMediaOverlayStyle) as! Int)! } set (value) { FolioReader.defaults.setValue(value.rawValue, forKey: kCurrentMediaOverlayStyle) - FolioReader.defaults.synchronize() } } @@ -158,11 +152,11 @@ public class FolioReader : NSObject { if let currentPage = FolioReader.sharedInstance.readerCenter.currentPage { let position = [ "pageNumber": currentPageNumber, - "pageOffset": currentPage.webView.scrollView.contentOffset.y + "pageOffsetX": currentPage.webView.scrollView.contentOffset.x, + "pageOffsetY": currentPage.webView.scrollView.contentOffset.y ] FolioReader.defaults.setObject(position, forKey: kBookId) - FolioReader.defaults.synchronize() } } } @@ -174,6 +168,47 @@ func isNight (f: T, _ l: T) -> T { return FolioReader.sharedInstance.nightMode ? f : l } +// MARK: - Scroll Direction Functions + +func isVerticalDirection (f: T, _ l: T) -> T { + return readerConfig.scrollDirection == .vertical ? f : l +} + +extension UICollectionViewScrollDirection { + static func direction() -> UICollectionViewScrollDirection { + return isVerticalDirection(.Vertical, .Horizontal) + } +} + +extension UICollectionViewScrollPosition { + static func direction() -> UICollectionViewScrollPosition { + return isVerticalDirection(.Top, .Left) + } +} + +extension CGPoint { + func forDirection() -> CGFloat { + return isVerticalDirection(self.y, self.x) + } +} + +extension CGSize { + func forDirection() -> CGFloat { + return isVerticalDirection(self.height, self.width) + } +} + +extension ScrollDirection { + static func negative() -> ScrollDirection { + return isVerticalDirection(.Down, .Right) + } + + static func positive() -> ScrollDirection { + return isVerticalDirection(.Up, .Left) + } +} + + // MARK: - Extensions internal extension NSBundle { diff --git a/Source/FolioReaderPage.swift b/Source/FolioReaderPage.swift index 36d06e2f6..574e4b3f2 100755 --- a/Source/FolioReaderPage.swift +++ b/Source/FolioReaderPage.swift @@ -19,6 +19,7 @@ class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRecogni var pageNumber: Int! var webView: UIWebView! + private var colorView: UIView! weak var delegate: FolioPageDelegate! private var shouldShowBar = true private var menuIsVisible = false @@ -29,26 +30,59 @@ class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRecogni super.init(frame: frame) self.backgroundColor = UIColor.whiteColor() + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.refreshPageMode), name: "needRefreshPageMode", object: nil) + if webView == nil { webView = UIWebView(frame: webViewFrame()) webView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] webView.dataDetectorTypes = [.None, .Link] webView.scrollView.showsVerticalScrollIndicator = false + webView.scrollView.showsHorizontalScrollIndicator = false webView.backgroundColor = UIColor.clearColor() + self.contentView.addSubview(webView) } webView.delegate = self + if readerConfig.scrollDirection == .horizontal { + webView.scrollView.pagingEnabled = true + webView.paginationMode = .LeftToRight + webView.paginationBreakingMode = .Page + webView.scrollView.bounces = false + } else { + webView.scrollView.bounces = true + } + + if colorView == nil { + colorView = UIView(); + colorView.backgroundColor = UIColor(rgba: "#131313") + webView.scrollView.addSubview(colorView); + } + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(FolioReaderPage.handleTapGesture(_:))) tapGestureRecognizer.numberOfTapsRequired = 1 tapGestureRecognizer.delegate = self webView.addGestureRecognizer(tapGestureRecognizer) + +// var swipeLeftGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(FolioReaderPage.handleSwipeGesture(_:))) +// swipeLeftGestureRecognizer.direction = .Left +// swipeLeftGestureRecognizer.delegate = self +// webView.addGestureRecognizer(swipeLeftGestureRecognizer) +// +// var swipeRightGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(FolioReaderPage.handleSwipeGesture(_:))) +// swipeRightGestureRecognizer.direction = .Right +// swipeRightGestureRecognizer.delegate = self +// webView.addGestureRecognizer(swipeRightGestureRecognizer) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } + deinit { + NSNotificationCenter.defaultCenter().removeObserver(self) + } + override func layoutSubviews() { super.layoutSubviews() @@ -56,15 +90,27 @@ class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRecogni } func webViewFrame() -> CGRect { - if readerConfig.shouldHideNavigationOnTap == false { + let paddingTop: CGFloat = 20 + let paddingBottom: CGFloat = 30 + + guard readerConfig.shouldHideNavigationOnTap else { let statusbarHeight = UIApplication.sharedApplication().statusBarFrame.size.height let navBarHeight = FolioReader.sharedInstance.readerCenter.navigationController?.navigationBar.frame.size.height let navTotal = statusbarHeight + navBarHeight! - let newFrame = CGRect(x: self.bounds.origin.x, y: self.bounds.origin.y+navTotal, width: self.bounds.width, height: self.bounds.height-navTotal) + let newFrame = CGRect( + x: bounds.origin.x, + y: isVerticalDirection(bounds.origin.y + navTotal, bounds.origin.y + navTotal + paddingTop), + width: bounds.width, + height: isVerticalDirection(bounds.height - navTotal, bounds.height - navTotal - paddingTop - paddingBottom)) return newFrame - } else { - return self.bounds } + + let newFrame = CGRect( + x: bounds.origin.x, + y: isVerticalDirection(bounds.origin.y, bounds.origin.y + paddingTop), + width: bounds.width, + height: isVerticalDirection(bounds.height, bounds.height - paddingTop - paddingBottom)) + return newFrame } func loadHTMLString(string: String!, baseURL: NSURL!) { @@ -103,6 +149,8 @@ class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRecogni // MARK: - UIWebView Delegate func webViewDidFinishLoad(webView: UIWebView) { + self.refreshPageMode() + if (!book.hasAudio()) { FolioReader.sharedInstance.readerAudioPlayer.delegate = self; self.webView.js("wrappingSentencesWithinPTags()"); @@ -111,11 +159,15 @@ class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRecogni } } - webView.scrollView.contentSize = CGSizeMake(pageWidth, webView.scrollView.contentSize.height) +// webView.scrollView.contentSize = CGSizeMake(pageWidth, webView.scrollView.contentSize.height) - if scrollDirection == .Down && isScrolling { - let bottomOffset = CGPointMake(0, webView.scrollView.contentSize.height - webView.scrollView.bounds.height) - if bottomOffset.y >= 0 { + if scrollDirection == .negative() && isScrolling { + let bottomOffset = isVerticalDirection( + CGPointMake(0, webView.scrollView.contentSize.height - webView.scrollView.bounds.height), + CGPointMake(webView.scrollView.contentSize.width - webView.scrollView.bounds.width, 0) + ) + + if bottomOffset.forDirection() >= 0 { dispatch_async(dispatch_get_main_queue(), { webView.scrollView.setContentOffset(bottomOffset, animated: false) }) @@ -261,10 +313,50 @@ class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRecogni menuIsVisible = false } + func handleSwipeGesture(recognizer: UISwipeGestureRecognizer) { + let width = self.webView.bounds.size.width + var currentPageNum: Int = Int(self.webView.scrollView.contentOffset.x / width) + var totalPageNum: Int = Int(self.webView.scrollView.contentSize.width / width) + if self.webView.scrollView.contentSize.width % width != 0 { + totalPageNum += 1 + } + + switch recognizer.direction { + case UISwipeGestureRecognizerDirection.Left: + if currentPageNum < totalPageNum - 1 { +// self.webView.scrollView.contentOffset = CGPointMake(CGFloat(currentPageNum + 1) * width, 0) +// self.transition("pageCurl", subtype: kCATransitionFromRight, view: self.webView) + } else { + FolioReader.sharedInstance.readerCenter.changePageToNext() + } + case UISwipeGestureRecognizerDirection.Right: + if currentPageNum > 0 { +// self.webView.scrollView.contentOffset = CGPointMake(CGFloat(currentPageNum - 1) * width, 0) +// self.transition("pageCurl", subtype: kCATransitionFromLeft, view: self.webView) + } else { + if self.webView.scrollView.contentOffset.x == 0 { + FolioReader.sharedInstance.readerCenter.changePageToPrevious() + } + } + default: + break + } + + } + + func transition(type: String, subtype: String, view: UIView) { + let animation = CATransition(); + animation.duration = 0.7 + animation.type = type + animation.subtype = subtype + animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) + view.layer.addAnimation(animation, forKey: "animation") + } + // MARK: - Scroll positioning func scrollPageToOffset(offset: String, animating: Bool) { - let jsCommand = "window.scrollTo(0,\(offset));" + let jsCommand = isVerticalDirection("window.scrollTo(0,\(offset));", "window.scrollTo(\(offset),0);") if animating { UIView.animateWithDuration(0.35, animations: { self.webView.js(jsCommand) @@ -348,6 +440,19 @@ class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRecogni func audioMarkID(ID: String){ self.webView.js("audioMarkID('\(book.playbackActiveClass())','\(ID)')"); } + + func refreshPageMode() { + if FolioReader.sharedInstance.nightMode { + // omit create webView and colorView + let script = "document.documentElement.offsetHeight" + let contentHeight = webView.stringByEvaluatingJavaScriptFromString(script) + let frameHeight = webView.frame.height + let lastPageHeight = frameHeight * CGFloat(webView.pageCount) - CGFloat(Double(contentHeight!)!) + colorView.frame = CGRectMake(webView.frame.width * CGFloat(webView.pageCount-1), webView.frame.height - lastPageHeight, webView.frame.width, lastPageHeight) + } else { + colorView.frame = CGRectZero + } + } } // MARK: - WebView Highlight and share implementation @@ -375,30 +480,30 @@ extension UIWebView { // menu on existing highlight if isShare { - if action == #selector(UIWebView.colors(_:)) || (action == #selector(UIWebView.share(_:)) && readerConfig?.allowSharing == true) || action == #selector(UIWebView.remove(_:)) { + if action == #selector(UIWebView.colors(_:)) || (action == #selector(UIWebView.share(_:)) && readerConfig.allowSharing) || action == #selector(UIWebView.remove(_:)) { return true } return false - // menu for selecting highlight color + // menu for selecting highlight color } else if isColors { if action == #selector(UIWebView.setYellow(_:)) || action == #selector(UIWebView.setGreen(_:)) || action == #selector(UIWebView.setBlue(_:)) || action == #selector(UIWebView.setPink(_:)) || action == #selector(UIWebView.setUnderline(_:)) { return true } return false - // default menu + // default menu } else { var isOneWord = false if let result = js("getSelectedText()") where result.componentsSeparatedByString(" ").count == 1 { isOneWord = true } - + if action == #selector(UIWebView.highlight(_:)) - || (action == #selector(UIWebView.define(_:)) && isOneWord) - || (action == #selector(UIWebView.play(_:)) && (book.hasAudio() || readerConfig?.enableTTS == true)) - || (action == #selector(UIWebView.share(_:)) && readerConfig?.allowSharing == true) - || (action == #selector(NSObject.copy(_:)) && readerConfig?.allowSharing == true) { + || (action == #selector(UIWebView.define(_:)) && isOneWord) + || (action == #selector(UIWebView.play(_:)) && (book.hasAudio() || readerConfig.enableTTS)) + || (action == #selector(UIWebView.share(_:)) && readerConfig.allowSharing == true) + || (action == #selector(NSObject.copy(_:)) && readerConfig.allowSharing == true) { return true } return false @@ -565,6 +670,7 @@ extension UIWebView { func js(script: String) -> String? { let callback = self.stringByEvaluatingJavaScriptFromString(script) + NSNotificationCenter.defaultCenter().postNotificationName("needRefreshPageMode", object: nil) if callback!.isEmpty { return nil } return callback } diff --git a/Source/FolioReaderSidePanel.swift b/Source/FolioReaderSidePanel.swift index 1a5fe4097..241851e07 100755 --- a/Source/FolioReaderSidePanel.swift +++ b/Source/FolioReaderSidePanel.swift @@ -191,6 +191,7 @@ class FolioReaderSidePanel: UIViewController, UITableViewDelegate, UITableViewDa func didSelectClose(sender: UIBarButtonItem) { self.dismissViewControllerAnimated(true, completion: { + FolioReader.saveReaderState() FolioReader.sharedInstance.isReaderOpen = false FolioReader.sharedInstance.isReaderReady = false FolioReader.sharedInstance.readerAudioPlayer.stop() diff --git a/Source/Resources/Bridge.js b/Source/Resources/Bridge.js index 363fa5908..7305882e0 100755 --- a/Source/Resources/Bridge.js +++ b/Source/Resources/Bridge.js @@ -235,6 +235,18 @@ function goToEl(el) { if(elBottom > bottom || elTop < top) { document.body.scrollTop = el.offsetTop - 20 } + + /* Set scroll left in case horz scroll is activated. + + The following works because el.offsetTop accounts for each page turned + as if the document was scrolling vertical. We then divide by the window + height to figure out what page the element should appear on and set scroll left + to scroll to that page. + */ + if( document.body.scrollTop == 0 ){ + var elLeft = document.body.clientWidth * Math.floor(el.offsetTop / window.innerHeight); + document.body.scrollLeft = elLeft; + } return el; }