X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/53b27422d140022594fc241cca91c3183be57bca..48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff:/iOS/Pods/FolioReaderKit/Source/ScrollScrubber.swift?ds=inline diff --git a/iOS/Pods/FolioReaderKit/Source/ScrollScrubber.swift b/iOS/Pods/FolioReaderKit/Source/ScrollScrubber.swift new file mode 100644 index 0000000..7f73b42 --- /dev/null +++ b/iOS/Pods/FolioReaderKit/Source/ScrollScrubber.swift @@ -0,0 +1,263 @@ +// +// ScrollScrubber.swift +// FolioReaderKit +// +// Created by Heberti Almeida on 7/14/16. +// Copyright © 2016 FolioReader. All rights reserved. +// + +import UIKit + +func < (lhs: T?, rhs: T?) -> Bool { + switch (lhs, rhs) { + case let (l?, r?): + return l < r + case (nil, _?): + return true + default: + return false + } +} + +func > (lhs: T?, rhs: T?) -> Bool { + switch (lhs, rhs) { + case let (l?, r?): + return l > r + default: + return rhs < lhs + } +} + +enum ScrollType: Int { + case page + // `chapter` is only for the collection view if vertical with horizontal content is used + case chapter +} + +enum ScrollDirection: Int { + case none + case right + case left + case up + case down + + init() { + self = .none + } +} + +class ScrollScrubber: NSObject, UIScrollViewDelegate { + weak var delegate: FolioReaderCenter? + var showSpeed = 0.6 + var hideSpeed = 0.6 + var hideDelay = 1.0 + + var visible = false + var usingSlider = false + var slider: UISlider! + var hideTimer: Timer! + var scrollStart: CGFloat! + var scrollDelta: CGFloat! + var scrollDeltaTimer: Timer! + + fileprivate weak var readerContainer: FolioReaderContainer? + + fileprivate var readerConfig: FolioReaderConfig { + guard let readerContainer = readerContainer else { return FolioReaderConfig() } + return readerContainer.readerConfig + } + + fileprivate var folioReader: FolioReader { + guard let readerContainer = readerContainer else { return FolioReader() } + return readerContainer.folioReader + } + + var frame: CGRect { + didSet { + self.slider.frame = frame + } + } + + init(frame:CGRect, withReaderContainer readerContainer: FolioReaderContainer) { + self.frame = frame + self.readerContainer = readerContainer + + super.init() + + slider = UISlider() + slider.layer.anchorPoint = CGPoint(x: 0, y: 0) + slider.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2)) + slider.alpha = 0 + self.reloadColors() + + // less obtrusive knob and fixes jump: http://stackoverflow.com/a/22301039/484780 + let thumbImg = UIImage(readerImageNamed: "knob") + let thumbImgColor = thumbImg?.imageTintColor(readerConfig.tintColor)?.withRenderingMode(.alwaysOriginal) + slider.setThumbImage(thumbImgColor, for: UIControlState()) + slider.setThumbImage(thumbImgColor, for: .selected) + slider.setThumbImage(thumbImgColor, for: .highlighted) + + slider.addTarget(self, action: #selector(ScrollScrubber.sliderChange(_:)), for: .valueChanged) + slider.addTarget(self, action: #selector(ScrollScrubber.sliderTouchDown(_:)), for: .touchDown) + slider.addTarget(self, action: #selector(ScrollScrubber.sliderTouchUp(_:)), for: .touchUpInside) + slider.addTarget(self, action: #selector(ScrollScrubber.sliderTouchUp(_:)), for: .touchUpOutside) + } + + func reloadColors() { + slider.minimumTrackTintColor = readerConfig.tintColor + slider.maximumTrackTintColor = folioReader.isNight(readerConfig.nightModeSeparatorColor, readerConfig.menuSeparatorColor) + } + + // MARK: - slider events + + @objc func sliderTouchDown(_ slider:UISlider) { + usingSlider = true + show() + } + + @objc func sliderTouchUp(_ slider:UISlider) { + usingSlider = false + hideAfterDelay() + } + + @objc func sliderChange(_ slider:UISlider) { + let movePosition = (height() * CGFloat(slider.value)) + let offset = readerConfig.isDirection(CGPoint(x: 0, y: movePosition), CGPoint(x: movePosition, y: 0), CGPoint(x: 0, y: movePosition)) + scrollView()?.setContentOffset(offset, animated: false) + } + + // MARK: - show / hide + + func show() { + cancelHide() + + visible = true + + if slider.alpha <= 0 { + UIView.animate(withDuration: showSpeed, animations: { + + self.slider.alpha = 1 + + }, completion: { (Bool) -> Void in + self.hideAfterDelay() + }) + } else { + slider.alpha = 1 + if usingSlider == false { + hideAfterDelay() + } + } + } + + + @objc func hide() { + visible = false + resetScrollDelta() + UIView.animate(withDuration: hideSpeed, animations: { + self.slider.alpha = 0 + }) + } + + func hideAfterDelay() { + cancelHide() + hideTimer = Timer.scheduledTimer(timeInterval: hideDelay, target: self, selector: #selector(ScrollScrubber.hide), userInfo: nil, repeats: false) + } + + func cancelHide() { + + if hideTimer != nil { + hideTimer.invalidate() + hideTimer = nil + } + + if visible == false { + slider.layer.removeAllAnimations() + } + + visible = true + } + + func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { + + if scrollDeltaTimer != nil { + scrollDeltaTimer.invalidate() + scrollDeltaTimer = nil + } + + if scrollStart == nil { + scrollStart = scrollView.contentOffset.forDirection(withConfiguration: readerConfig) + } + } + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + guard (readerConfig.scrollDirection == .vertical || + readerConfig.scrollDirection == .defaultVertical || + readerConfig.scrollDirection == .horizontalWithVerticalContent) else { + return + } + + if visible && usingSlider == false { + setSliderVal() + } + + if (slider.alpha > 0) { + self.show() + } else if delegate?.currentPage != nil && scrollStart != nil { + scrollDelta = scrollView.contentOffset.forDirection(withConfiguration: readerConfig) - scrollStart + + guard let pageHeight = folioReader.readerCenter?.pageHeight, + (scrollDeltaTimer == nil && scrollDelta > (pageHeight * 0.2 ) || (scrollDelta * -1) > (pageHeight * 0.2)) else { + return + } + + self.show() + self.resetScrollDelta() + } + } + + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + resetScrollDelta() + } + + func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { + scrollDeltaTimer = Timer(timeInterval:0.5, target: self, selector: #selector(ScrollScrubber.resetScrollDelta), userInfo: nil, repeats: false) + RunLoop.current.add(scrollDeltaTimer, forMode: RunLoopMode.commonModes) + } + + @objc func resetScrollDelta() { + if scrollDeltaTimer != nil { + scrollDeltaTimer.invalidate() + scrollDeltaTimer = nil + } + + scrollStart = (scrollView()?.contentOffset.forDirection(withConfiguration: readerConfig) ?? 0) + scrollDelta = 0 + } + + func setSliderVal() { + slider.value = Float(scrollTop() / height()) + } + + // MARK: - utility methods + + fileprivate func scrollView() -> UIScrollView? { + return delegate?.currentPage?.webView?.scrollView + } + + fileprivate func height() -> CGFloat { + guard let currentPage = delegate?.currentPage, + let pageHeight = folioReader.readerCenter?.pageHeight, + let webView = currentPage.webView else { + return 0 + } + + return webView.scrollView.contentSize.height - pageHeight + 44 + } + + fileprivate func scrollTop() -> CGFloat { + guard let currentPage = delegate?.currentPage, let webView = currentPage.webView else { + return 0 + } + return webView.scrollView.contentOffset.forDirection(withConfiguration: readerConfig) + } +}