diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj
index 076595264..f393605c0 100644
--- a/Example/Example.xcodeproj/project.pbxproj
+++ b/Example/Example.xcodeproj/project.pbxproj
@@ -376,7 +376,7 @@
TargetAttributes = {
1A42C2881C0E3882000F2137 = {
CreatedOnToolsVersion = 7.1.1;
- DevelopmentTeam = 32F2T8EJ6G;
+ DevelopmentTeam = C3VKVFB3SA;
LastSwiftMigration = 0800;
ProvisioningStyle = Automatic;
SystemCapabilities = {
@@ -944,7 +944,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- DEVELOPMENT_TEAM = 32F2T8EJ6G;
+ DEVELOPMENT_TEAM = C3VKVFB3SA;
INFOPLIST_FILE = Example/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.folioreader.Example;
@@ -961,7 +961,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- DEVELOPMENT_TEAM = 32F2T8EJ6G;
+ DEVELOPMENT_TEAM = C3VKVFB3SA;
INFOPLIST_FILE = Example/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.folioreader.Example;
diff --git a/Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 000000000..18d981003
--- /dev/null
+++ b/Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/Source/FolioReaderBookmarkList.swift b/Source/FolioReaderBookmarkList.swift
new file mode 100644
index 000000000..fff4da3bf
--- /dev/null
+++ b/Source/FolioReaderBookmarkList.swift
@@ -0,0 +1,92 @@
+//
+// FolioReaderBookmarkList.swift
+// FolioReaderKit
+//
+// Created by Omar Albeik on 26.03.2018.
+// Copyright (c) 2015 Folio Reader. All rights reserved.
+//
+
+import UIKit
+
+class FolioReaderBookmarkList: UITableViewController {
+
+ fileprivate var bookmarks = [Bookmark]()
+ fileprivate var readerConfig: FolioReaderConfig
+ fileprivate var folioReader: FolioReader
+
+ init(folioReader: FolioReader, readerConfig: FolioReaderConfig) {
+ self.readerConfig = readerConfig
+ self.folioReader = folioReader
+
+ super.init(style: UITableViewStyle.plain)
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init with coder not supported")
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ tableView.register(UITableViewCell.self, forCellReuseIdentifier: kReuseCellIdentifier)
+ tableView.separatorInset = UIEdgeInsets.zero
+ tableView.backgroundColor = folioReader.isNight(readerConfig.nightModeMenuBackground, readerConfig.menuBackgroundColor)
+ tableView.separatorColor = folioReader.isNight(readerConfig.nightModeSeparatorColor, readerConfig.menuSeparatorColor)
+
+ guard let bookId = (folioReader.readerContainer?.book.name as NSString?)?.deletingPathExtension else {
+ bookmarks = []
+ return
+ }
+
+ bookmarks = Bookmark.allByBookId(withConfiguration: readerConfig, bookId: bookId)
+ }
+
+ // MARK: - Table view data source
+
+ override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return bookmarks.count
+ }
+
+ override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: kReuseCellIdentifier, for: indexPath)
+ cell.backgroundColor = .clear
+
+ let bookmark = bookmarks[indexPath.row]
+
+ // Format date
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateFormat = readerConfig.localizedHighlightsDateFormat
+ let dateString = dateFormatter.string(from: bookmark.date)
+
+ cell.textLabel?.text = "Page \(bookmark.page)"
+ cell.detailTextLabel?.text = dateString
+
+ return cell
+ }
+
+ // MARK: - Table view delegate
+
+ override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ guard let bookmark = bookmarks[safe: indexPath.row] else {
+ return
+ }
+
+ folioReader.readerCenter?.changePageWith(page: bookmark.page, andFragment: bookmark.bookmarkId)
+ dismiss()
+ }
+
+ override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
+ if editingStyle == .delete {
+ let bookmark = bookmarks[indexPath.row]
+ bookmark.remove(withConfiguration: readerConfig) // Remove from Database
+ bookmarks.remove(at: indexPath.row)
+ tableView.deleteRows(at: [indexPath], with: .fade)
+ }
+ }
+
+ // MARK: - Handle rotation transition
+
+ override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
+ tableView.reloadData()
+ }
+}
diff --git a/Source/FolioReaderCenter.swift b/Source/FolioReaderCenter.swift
index be862143a..fa8670e84 100755
--- a/Source/FolioReaderCenter.swift
+++ b/Source/FolioReaderCenter.swift
@@ -11,12 +11,12 @@ import ZFDragableModalTransition
/// Protocol which is used from `FolioReaderCenter`s.
@objc public protocol FolioReaderCenterDelegate: class {
-
+
/// Notifies that a page appeared. This is triggered when a page is chosen and displayed.
///
/// - Parameter page: The appeared page
@objc optional func pageDidAppear(_ page: FolioReaderPage)
-
+
/// Passes and returns the HTML content as `String`. Implement this method if you want to modify the HTML content of a `FolioReaderPage`.
///
/// - Parameters:
@@ -29,24 +29,24 @@ import ZFDragableModalTransition
///
/// - Parameter pageNumber: The appeared page item
@objc optional func pageItemChanged(_ pageNumber: Int)
-
+
}
/// The base reader class
open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
-
+
/// This delegate receives the events from the current `FolioReaderPage`s delegate.
open weak var delegate: FolioReaderCenterDelegate?
-
+
/// This delegate receives the events from current page
open weak var pageDelegate: FolioReaderPageDelegate?
-
+
/// The base reader container
open weak var readerContainer: FolioReaderContainer?
-
+
/// The current visible page on reader
open fileprivate(set) var currentPage: FolioReaderPage?
-
+
/// The collection view with pages
open var collectionView: UICollectionView!
@@ -70,7 +70,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
var currentPageNumber: Int = 0
var pageWidth: CGFloat = 0.0
var pageHeight: CGFloat = 0.0
-
+
fileprivate var screenBounds: CGRect!
fileprivate var pointNow = CGPoint.zero
fileprivate var pageOffsetRate: CGFloat = 0
@@ -78,46 +78,46 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
fileprivate var isFirstLoad = true
fileprivate var currentWebViewScrollPositions = [Int: CGPoint]()
fileprivate var currentOrientation: UIInterfaceOrientation?
-
+
fileprivate var readerConfig: FolioReaderConfig {
guard let readerContainer = readerContainer else { return FolioReaderConfig() }
return readerContainer.readerConfig
}
-
+
fileprivate var book: FRBook {
guard let readerContainer = readerContainer else { return FRBook() }
return readerContainer.book
}
-
+
fileprivate var folioReader: FolioReader {
guard let readerContainer = readerContainer else { return FolioReader() }
return readerContainer.folioReader
}
-
+
// MARK: - Init
-
+
init(withContainer readerContainer: FolioReaderContainer) {
self.readerContainer = readerContainer
super.init(nibName: nil, bundle: Bundle.frameworkBundle())
-
+
self.initialization()
}
-
+
required public init?(coder aDecoder: NSCoder) {
fatalError("This class doesn't support NSCoding.")
}
-
+
/**
Common Initialization
*/
fileprivate func initialization() {
-
+
if (self.readerConfig.hideBars == true) {
self.pageIndicatorHeight = 0
}
self.totalPages = book.spine.spineReferences.count
-
+
// Loading indicator
let style: UIActivityIndicatorViewStyle = folioReader.isNight(.white, .gray)
loadingView = UIActivityIndicatorView(activityIndicatorStyle: style)
@@ -125,16 +125,16 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
loadingView.startAnimating()
self.view.addSubview(loadingView)
}
-
+
// MARK: - View life cicle
-
+
override open func viewDidLoad() {
super.viewDidLoad()
-
+
screenBounds = self.getScreenBounds()
setPageSize(UIApplication.shared.statusBarOrientation)
-
+
// Layout
collectionViewLayout.sectionInset = UIEdgeInsets.zero
collectionViewLayout.minimumLineSpacing = 0
@@ -143,7 +143,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
let background = folioReader.isNight(self.readerConfig.nightModeBackground, UIColor.white)
view.backgroundColor = background
-
+
// CollectionView
collectionView = UICollectionView(frame: screenBounds, collectionViewLayout: collectionViewLayout)
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
@@ -157,10 +157,6 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
enableScrollBetweenChapters(scrollEnabled: true)
view.addSubview(collectionView)
- if #available(iOS 11.0, *) {
- collectionView.contentInsetAdjustmentBehavior = .never
- }
-
// Activity Indicator
self.activityIndicator.activityIndicatorViewStyle = .gray
self.activityIndicator.hidesWhenStopped = true
@@ -168,19 +164,23 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
self.activityIndicator.backgroundColor = UIColor.gray
self.view.addSubview(self.activityIndicator)
self.view.bringSubview(toFront: self.activityIndicator)
-
+
+ if #available(iOS 11.0, *) {
+ collectionView.contentInsetAdjustmentBehavior = .never
+ }
+
if #available(iOS 10.0, *) {
collectionView.isPrefetchingEnabled = false
}
-
+
// Register cell classes
collectionView?.register(FolioReaderPage.self, forCellWithReuseIdentifier: kReuseCellIdentifier)
-
+
// Configure navigation bar and layout
automaticallyAdjustsScrollViewInsets = false
extendedLayoutIncludesOpaqueBars = true
configureNavBar()
-
+
// Page indicator view
if (self.readerConfig.hidePageIndicator == false) {
let frame = self.frameForPageIndicatorView()
@@ -189,7 +189,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
view.addSubview(pageIndicatorView)
}
}
-
+
guard let readerContainer = readerContainer else { return }
self.scrollScrubber = ScrollScrubber(frame: frameForScrollScrubber(), withReaderContainer: readerContainer)
self.scrollScrubber?.delegate = self
@@ -197,43 +197,43 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
view.addSubview(scrollScrubber.slider)
}
}
-
+
override open func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
-
+
configureNavBar()
-
+
// Update pages
pagesForCurrentPage(currentPage)
pageIndicatorView?.reloadView(updateShadow: true)
}
-
+
override open func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
-
+
screenBounds = self.getScreenBounds()
loadingView.center = view.center
-
+
setPageSize(UIApplication.shared.statusBarOrientation)
updateSubviewFrames()
}
-
+
// MARK: Layout
-
+
/**
Enable or disable the scrolling between chapters (`FolioReaderPage`s). If this is enabled it's only possible to read the current chapter. If another chapter should be displayed is has to be triggered programmatically with `changePageWith`.
-
+
- parameter scrollEnabled: `Bool` which enables or disables the scrolling between `FolioReaderPage`s.
*/
open func enableScrollBetweenChapters(scrollEnabled: Bool) {
self.collectionView.isScrollEnabled = scrollEnabled
}
-
+
fileprivate func updateSubviewFrames() {
self.pageIndicatorView?.frame = self.frameForPageIndicatorView()
self.scrollScrubber?.frame = self.frameForScrollScrubber()
}
-
+
fileprivate func frameForPageIndicatorView() -> CGRect {
var bounds = CGRect(x: 0, y: screenBounds.size.height-pageIndicatorHeight, width: screenBounds.size.width, height: pageIndicatorHeight)
@@ -243,12 +243,12 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
return bounds
}
-
+
fileprivate func frameForScrollScrubber() -> CGRect {
let scrubberY: CGFloat = ((self.readerConfig.shouldHideNavigationOnTap == true || self.readerConfig.hideBars == true) ? 50 : 74)
return CGRect(x: self.pageWidth + 10, y: scrubberY, width: 40, height: (self.pageHeight - 100))
}
-
+
func configureNavBar() {
let navBackground = folioReader.isNight(self.readerConfig.nightModeMenuBackground, UIColor.white)
let tintColor = readerConfig.tintColor
@@ -256,35 +256,41 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
let font = UIFont(name: "Avenir-Light", size: 17)!
setTranslucentNavigation(color: navBackground, tintColor: tintColor, titleColor: navText, andFont: font)
}
-
+
func configureNavBarButtons() {
-
+
// Navbar buttons
let shareIcon = UIImage(readerImageNamed: "icon-navbar-share")?.ignoreSystemTint(withConfiguration: self.readerConfig)
let audioIcon = UIImage(readerImageNamed: "icon-navbar-tts")?.ignoreSystemTint(withConfiguration: self.readerConfig) //man-speech-icon
let closeIcon = UIImage(readerImageNamed: "icon-navbar-close")?.ignoreSystemTint(withConfiguration: self.readerConfig)
let tocIcon = UIImage(readerImageNamed: "icon-navbar-toc")?.ignoreSystemTint(withConfiguration: self.readerConfig)
let fontIcon = UIImage(readerImageNamed: "icon-navbar-font")?.ignoreSystemTint(withConfiguration: self.readerConfig)
+
let space = 70 as CGFloat
-
+
let menu = UIBarButtonItem(image: closeIcon, style: .plain, target: self, action:#selector(closeReader(_:)))
let toc = UIBarButtonItem(image: tocIcon, style: .plain, target: self, action:#selector(presentChapterList(_:)))
-
+
navigationItem.leftBarButtonItems = [menu, toc]
-
+
var rightBarIcons = [UIBarButtonItem]()
-
+
if (self.readerConfig.allowSharing == true) {
rightBarIcons.append(UIBarButtonItem(image: shareIcon, style: .plain, target: self, action:#selector(shareChapter(_:))))
}
-
+
+ if readerConfig.allowBookmarking {
+ let bookmarkButton = UIBookmarkBarButtonItem(target: self, action: #selector(didTapBookmarkIcon(_:)), readerConfig: readerConfig)
+ rightBarIcons.append(bookmarkButton)
+ }
+
if self.book.hasAudio || self.readerConfig.enableTTS {
rightBarIcons.append(UIBarButtonItem(image: audioIcon, style: .plain, target: self, action:#selector(presentPlayerMenu(_:))))
}
-
+
let font = UIBarButtonItem(image: fontIcon, style: .plain, target: self, action: #selector(presentFontsMenu))
font.width = space
-
+
rightBarIcons.append(contentsOf: [font])
navigationItem.rightBarButtonItems = rightBarIcons
@@ -292,28 +298,28 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
navigationItem.title = book.title
}
}
-
+
func reloadData() {
self.loadingView.stopAnimating()
self.totalPages = book.spine.spineReferences.count
-
+
self.collectionView.reloadData()
self.configureNavBarButtons()
self.setCollectionViewProgressiveDirection()
-
+
if self.readerConfig.loadSavedPositionForCurrentBook {
guard let position = folioReader.savedPositionForCurrentBook, let pageNumber = position["pageNumber"] as? Int, pageNumber > 0 else {
self.currentPageNumber = 1
return
}
-
+
self.changePageWith(page: pageNumber)
self.currentPageNumber = pageNumber
}
}
-
+
// MARK: Change page progressive direction
-
+
private func transformViewForRTL(_ view: UIView?) {
if folioReader.needsRTLChange {
view?.transform = CGAffineTransform(scaleX: -1, y: 1)
@@ -321,36 +327,36 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
view?.transform = CGAffineTransform.identity
}
}
-
+
func setCollectionViewProgressiveDirection() {
self.transformViewForRTL(self.collectionView)
}
-
+
func setPageProgressiveDirection(_ page: FolioReaderPage) {
self.transformViewForRTL(page)
}
-
+
// MARK: Change layout orientation
-
+
/// Get internal page offset before layout change
private func updatePageOffsetRate() {
guard let currentPage = self.currentPage, let webView = currentPage.webView else {
return
}
-
+
let pageScrollView = webView.scrollView
let contentSize = pageScrollView.contentSize.forDirection(withConfiguration: self.readerConfig)
let contentOffset = pageScrollView.contentOffset.forDirection(withConfiguration: self.readerConfig)
self.pageOffsetRate = (contentSize != 0 ? (contentOffset / contentSize) : 0)
}
-
+
func setScrollDirection(_ direction: FolioReaderScrollDirection) {
guard let currentPage = self.currentPage, let webView = currentPage.webView else {
return
}
-
+
let pageScrollView = webView.scrollView
-
+
// Get internal page offset before layout change
self.updatePageOffsetRate()
// Change layout
@@ -359,65 +365,65 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
self.currentPage?.setNeedsLayout()
self.collectionView.collectionViewLayout.invalidateLayout()
self.collectionView.setContentOffset(frameForPage(self.currentPageNumber).origin, animated: false)
-
+
// Page progressive direction
self.setCollectionViewProgressiveDirection()
delay(0.2) { self.setPageProgressiveDirection(currentPage) }
-
-
+
+
/**
* This delay is needed because the page will not be ready yet
* so the delay wait until layout finished the changes.
*/
delay(0.1) {
var pageOffset = (pageScrollView.contentSize.forDirection(withConfiguration: self.readerConfig) * self.pageOffsetRate)
-
+
// Fix the offset for paged scroll
if (self.readerConfig.scrollDirection == .horizontal && self.pageWidth != 0) {
let page = round(pageOffset / self.pageWidth)
pageOffset = (page * self.pageWidth)
}
-
+
let pageOffsetPoint = self.readerConfig.isDirection(CGPoint(x: 0, y: pageOffset), CGPoint(x: pageOffset, y: 0), CGPoint(x: 0, y: pageOffset))
pageScrollView.setContentOffset(pageOffsetPoint, animated: true)
}
}
-
+
// MARK: Status bar and Navigation bar
-
+
func hideBars() {
guard self.readerConfig.shouldHideNavigationOnTap == true else {
return
}
-
+
self.updateBarsStatus(true)
}
-
+
func showBars() {
self.configureNavBar()
self.updateBarsStatus(false)
}
-
+
func toggleBars() {
guard self.readerConfig.shouldHideNavigationOnTap == true else {
return
}
-
+
let shouldHide = !self.navigationController!.isNavigationBarHidden
if shouldHide == false {
self.configureNavBar()
}
-
+
self.updateBarsStatus(shouldHide)
}
-
+
private func updateBarsStatus(_ shouldHide: Bool, shouldShowIndicator: Bool = false) {
guard let readerContainer = readerContainer else { return }
readerContainer.shouldHideStatusBar = shouldHide
-
+
UIView.animate(withDuration: 0.25, animations: {
readerContainer.setNeedsStatusBarAppearanceUpdate()
-
+
// Show minutes indicator
if (shouldShowIndicator == true) {
self.pageIndicatorView?.minutesLabel.alpha = shouldHide ? 0 : 1
@@ -425,27 +431,27 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
})
self.navigationController?.setNavigationBarHidden(shouldHide, animated: true)
}
-
+
// MARK: UICollectionViewDataSource
-
+
open func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
-
+
open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return totalPages
}
-
+
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let reuseableCell = collectionView.dequeueReusableCell(withReuseIdentifier: kReuseCellIdentifier, for: indexPath) as? FolioReaderPage
return self.configure(readerPageCell: reuseableCell, atIndexPath: indexPath)
}
-
+
private func configure(readerPageCell cell: FolioReaderPage?, atIndexPath indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = cell, let readerContainer = readerContainer else {
return UICollectionViewCell()
}
-
+
cell.setup(withReaderContainer: readerContainer)
cell.pageNumber = indexPath.row+1
cell.webView?.scrollView.delegate = self
@@ -456,50 +462,50 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
cell.webView?.frame = cell.webViewFrame()
cell.delegate = self
cell.backgroundColor = .clear
-
+
setPageProgressiveDirection(cell)
-
+
// Configure the cell
let resource = self.book.spine.spineReferences[indexPath.row].resource
guard var html = try? String(contentsOfFile: resource.fullHref, encoding: String.Encoding.utf8) else {
return cell
}
-
+
let mediaOverlayStyleColors = "\"\(self.readerConfig.mediaOverlayColor.hexString(false))\", \"\(self.readerConfig.mediaOverlayColor.highlightColor().hexString(false))\""
-
+
// Inject CSS
let jsFilePath = Bundle.frameworkBundle().path(forResource: "Bridge", ofType: "js")
let cssFilePath = Bundle.frameworkBundle().path(forResource: "Style", ofType: "css")
let cssTag = ""
let jsTag = "" +
""
-
+
let toInject = "\n\(cssTag)\n\(jsTag)\n"
html = html.replacingOccurrences(of: "", with: toInject)
-
+
// Font class name
var classes = folioReader.currentFont.cssIdentifier
classes += " " + folioReader.currentMediaOverlayStyle.className()
-
+
// Night mode
if folioReader.nightMode {
classes += " nightMode"
}
-
+
// Font Size
classes += " \(folioReader.currentFontSize.cssIdentifier)"
-
+
html = html.replacingOccurrences(of: " CGSize {
var size = CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
@@ -517,38 +523,38 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
// MARK: - Device rotation
-
+
override open func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
guard folioReader.isReaderReady else { return }
-
+
setPageSize(toInterfaceOrientation)
updateCurrentPage()
-
+
if self.currentOrientation == nil || (self.currentOrientation?.isPortrait != toInterfaceOrientation.isPortrait) {
var pageIndicatorFrame = pageIndicatorView?.frame
pageIndicatorFrame?.origin.y = ((screenBounds.size.height < screenBounds.size.width) ? (self.collectionView.frame.height - pageIndicatorHeight) : (self.collectionView.frame.width - pageIndicatorHeight))
pageIndicatorFrame?.origin.x = 0
pageIndicatorFrame?.size.width = ((screenBounds.size.height < screenBounds.size.width) ? (self.collectionView.frame.width) : (self.collectionView.frame.height))
pageIndicatorFrame?.size.height = pageIndicatorHeight
-
+
var scrollScrubberFrame = scrollScrubber?.slider.frame;
scrollScrubberFrame?.origin.x = ((screenBounds.size.height < screenBounds.size.width) ? (screenBounds.size.width - 100) : (screenBounds.size.height + 10))
scrollScrubberFrame?.size.height = ((screenBounds.size.height < screenBounds.size.width) ? (self.collectionView.frame.height - 100) : (self.collectionView.frame.width - 100))
-
+
self.collectionView.collectionViewLayout.invalidateLayout()
-
+
UIView.animate(withDuration: duration, animations: {
// Adjust page indicator view
if let pageIndicatorFrame = pageIndicatorFrame {
self.pageIndicatorView?.frame = pageIndicatorFrame
self.pageIndicatorView?.reloadView(updateShadow: true)
}
-
+
// Adjust scroll scrubber slider
if let scrollScrubberFrame = scrollScrubberFrame {
self.scrollScrubber?.slider.frame = scrollScrubberFrame
}
-
+
// Adjust collectionView
self.collectionView.contentSize = self.readerConfig.isDirection(
CGSize(width: self.pageWidth, height: self.pageHeight * CGFloat(self.totalPages)),
@@ -557,44 +563,44 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
)
self.collectionView.setContentOffset(self.frameForPage(self.currentPageNumber).origin, animated: false)
self.collectionView.collectionViewLayout.invalidateLayout()
-
+
// Adjust internal page offset
self.updatePageOffsetRate()
})
}
-
+
self.currentOrientation = toInterfaceOrientation
}
-
+
override open func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
guard folioReader.isReaderReady == true, let currentPage = currentPage else {
return
}
-
+
// Update pages
pagesForCurrentPage(currentPage)
currentPage.refreshPageMode()
-
+
scrollScrubber?.setSliderVal()
-
+
// After rotation fix internal page offset
var pageOffset = (currentPage.webView?.scrollView.contentSize.forDirection(withConfiguration: self.readerConfig) ?? 0) * pageOffsetRate
-
+
// Fix the offset for paged scroll
if (self.readerConfig.scrollDirection == .horizontal && self.pageWidth != 0) {
let page = round(pageOffset / self.pageWidth)
pageOffset = page * self.pageWidth
}
-
+
let pageOffsetPoint = self.readerConfig.isDirection(CGPoint(x: 0, y: pageOffset), CGPoint(x: pageOffset, y: 0), CGPoint(x: 0, y: pageOffset))
currentPage.webView?.scrollView.setContentOffset(pageOffsetPoint, animated: true)
}
-
+
override open func willAnimateRotation(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
guard folioReader.isReaderReady else {
return
}
-
+
self.collectionView.scrollToItem(at: IndexPath(row: self.currentPageNumber - 1, section: 0), at: UICollectionViewScrollPosition(), animated: false)
if (self.currentPageNumber + 1) >= totalPages {
UIView.animate(withDuration: duration, animations: {
@@ -602,9 +608,9 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
})
}
}
-
+
// MARK: - Page
-
+
func setPageSize(_ orientation: UIInterfaceOrientation) {
guard orientation.isPortrait else {
if screenBounds.size.width > screenBounds.size.height {
@@ -616,7 +622,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
return
}
-
+
if screenBounds.size.width < screenBounds.size.height {
self.pageWidth = screenBounds.size.width
self.pageHeight = screenBounds.size.height
@@ -625,7 +631,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
self.pageHeight = screenBounds.size.width
}
}
-
+
func updateCurrentPage(_ page: FolioReaderPage? = nil, completion: (() -> Void)? = nil) {
if let page = page {
currentPage = page
@@ -634,64 +640,64 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
} else {
let currentIndexPath = getCurrentIndexPath()
currentPage = collectionView.cellForItem(at: currentIndexPath) as? FolioReaderPage
-
+
self.previousPageNumber = currentIndexPath.row
self.currentPageNumber = currentIndexPath.row+1
}
-
+
self.nextPageNumber = (((self.currentPageNumber + 1) <= totalPages) ? (self.currentPageNumber + 1) : self.currentPageNumber)
-
+
// Set pages
guard let currentPage = currentPage else {
completion?()
return
}
-
+
scrollScrubber?.setSliderVal()
-
+
if let readingTime = currentPage.webView?.js("getReadingTime()") {
pageIndicatorView?.totalMinutes = Int(readingTime)!
} else {
pageIndicatorView?.totalMinutes = 0
}
pagesForCurrentPage(currentPage)
-
+
delegate?.pageDidAppear?(currentPage)
delegate?.pageItemChanged?(self.getCurrentPageItemNumber())
-
+
completion?()
}
-
+
func pagesForCurrentPage(_ page: FolioReaderPage?) {
guard let page = page, let webView = page.webView else { return }
-
+
let pageSize = self.readerConfig.isDirection(pageHeight, self.pageWidth, pageHeight)
let contentSize = page.webView?.scrollView.contentSize.forDirection(withConfiguration: self.readerConfig) ?? 0
self.pageIndicatorView?.totalPages = ((pageSize != 0) ? Int(ceil(contentSize / pageSize)) : 0)
-
+
let pageOffSet = self.readerConfig.isDirection(webView.scrollView.contentOffset.x, webView.scrollView.contentOffset.x, webView.scrollView.contentOffset.y)
let webViewPage = pageForOffset(pageOffSet, pageHeight: pageSize)
-
+
self.pageIndicatorView?.currentPage = webViewPage
}
-
+
func pageForOffset(_ offset: CGFloat, pageHeight height: CGFloat) -> Int {
guard (height != 0) else {
return 0
}
-
+
let page = Int(ceil(offset / height))+1
return page
}
-
+
func getCurrentIndexPath() -> IndexPath {
let indexPaths = collectionView.indexPathsForVisibleItems
var indexPath = IndexPath()
-
+
if indexPaths.count > 1 {
let first = indexPaths.first!
let last = indexPaths.last!
-
+
switch self.pageScrollDirection {
case .up, .left:
if first.compare(last) == .orderedAscending {
@@ -709,10 +715,10 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
} else {
indexPath = indexPaths.first ?? IndexPath(row: 0, section: 0)
}
-
+
return indexPath
}
-
+
func frameForPage(_ page: Int) -> CGRect {
return self.readerConfig.isDirection(
CGRect(x: 0, y: self.pageHeight * CGFloat(page-1), width: self.pageWidth, height: self.pageHeight),
@@ -720,7 +726,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
CGRect(x: 0, y: self.pageHeight * CGFloat(page-1), width: self.pageWidth, height: self.pageHeight)
)
}
-
+
open func changePageWith(page: Int, andFragment fragment: String, animated: Bool = false, completion: (() -> Void)? = nil) {
if (self.currentPageNumber == page) {
if let currentPage = currentPage , fragment != "" {
@@ -736,7 +742,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
})
}
}
-
+
open func changePageWith(href: String, animated: Bool = false, completion: (() -> Void)? = nil) {
let item = findPageByHref(href)
let indexPath = IndexPath(row: item, section: 0)
@@ -746,11 +752,11 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
})
}
-
+
open func changePageWith(href: String, andAudioMarkID markID: String) {
if recentlyScrolled { return } // if user recently scrolled, do not change pages or scroll the webview
guard let currentPage = currentPage else { return }
-
+
let item = findPageByHref(href)
let pageUpdateNeeded = item+1 != currentPage.pageNumber
let indexPath = IndexPath(row: item, section: 0)
@@ -764,14 +770,14 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
}
}
-
+
open func changePageWith(indexPath: IndexPath, animated: Bool = false, completion: (() -> Void)? = nil) {
guard indexPathIsValid(indexPath) else {
print("ERROR: Attempt to scroll to invalid index path")
completion?()
return
}
-
+
UIView.animate(withDuration: animated ? 0.3 : 0, delay: 0, options: UIViewAnimationOptions(), animations: { () -> Void in
self.collectionView.scrollToItem(at: indexPath, at: .direction(withConfiguration: self.readerConfig), animated: false)
}) { (finished: Bool) -> Void in
@@ -784,31 +790,31 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
self.changePageItem(to: pageItem)
}
}
-
+
func indexPathIsValid(_ indexPath: IndexPath) -> Bool {
let section = indexPath.section
let row = indexPath.row
let lastSectionIndex = numberOfSections(in: collectionView) - 1
-
+
//Make sure the specified section exists
if section > lastSectionIndex {
return false
}
-
+
let rowCount = self.collectionView(collectionView, numberOfItemsInSection: indexPath.section) - 1
return row <= rowCount
}
-
+
open func isLastPage() -> Bool{
return (currentPageNumber == self.nextPageNumber)
}
-
+
public func changePageToNext(_ completion: (() -> Void)? = nil) {
changePageWith(page: self.nextPageNumber, animated: true) { () -> Void in
completion?()
}
}
-
+
public func changePageToPrevious(_ completion: (() -> Void)? = nil) {
changePageWith(page: self.previousPageNumber, animated: true) { () -> Void in
completion?()
@@ -837,7 +843,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
completion?()
}
-
+
public func getCurrentPageItemNumber() -> Int {
guard let page = currentPage, let webView = page.webView else { return 0 }
@@ -847,7 +853,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
return webViewPage
}
-
+
public func changePageItemToPrevious(_ completion: (() -> Void)? = nil) {
// TODO: It was implemented for horizontal orientation.
// Need check page orientation (v/h) and make correct calc for vertical
@@ -869,7 +875,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
completion?()
}
-
+
public func changePageItemToLast(animated: Bool = true, _ completion: (() -> Void)? = nil) {
// TODO: It was implemented for horizontal orientation.
// Need check page orientation (v/h) and make correct calc for vertical
@@ -895,7 +901,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
completion?()
}
-
+
public func changePageItem(to: Int, animated: Bool = true, completion: (() -> Void)? = nil) {
// TODO: It was implemented for horizontal orientation.
// Need check page orientation (v/h) and make correct calc for vertical
@@ -930,7 +936,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
}
}
-
+
/**
Find a page by FRTocReference.
*/
@@ -944,7 +950,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
return count
}
-
+
/**
Find a page by href.
*/
@@ -958,17 +964,17 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
return count
}
-
+
/**
Find and return the current chapter resource.
*/
public func getCurrentChapter() -> FRResource? {
var foundResource: FRResource?
-
+
func search(_ items: [FRTocReference]) {
for item in items {
guard foundResource == nil else { break }
-
+
if let reference = book.spine.spineReferences[safe: (currentPageNumber - 1)], let resource = item.resource, resource == reference.resource {
foundResource = resource
break
@@ -978,10 +984,10 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
}
search(book.flatTableOfContents)
-
+
return foundResource
}
-
+
/**
Return the current chapter progress based on current chapter and total of chapters.
*/
@@ -995,7 +1001,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
return CGFloat((100 * current) / total)
}
-
+
/**
Find and return the current chapter name.
*/
@@ -1008,18 +1014,18 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
let title = item.title else {
continue
}
-
+
return title
}
-
+
return nil
}
-
+
// MARK: Public page methods
-
+
/**
Changes the current page of the reader.
-
+
- parameter page: The target page index. Note: The page index starts at 1 (and not 0).
- parameter animated: En-/Disables the animation of the page change.
- parameter completion: A Closure which is called if the page change is completed.
@@ -1034,21 +1040,21 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
})
}
}
-
+
// MARK: - Audio Playing
-
+
func audioMark(href: String, fragmentID: String) {
changePageWith(href: href, andAudioMarkID: fragmentID)
}
-
+
// MARK: - Sharing
-
+
/**
Sharing chapter method.
*/
@objc func shareChapter(_ sender: UIBarButtonItem) {
guard let currentPage = currentPage else { return }
-
+
if let chapterText = currentPage.webView?.js("getBodyText()") {
let htmlText = chapterText.replacingOccurrences(of: "[\\n\\r]+", with: " ", options: .regularExpression)
var subject = readerConfig.localizedShareChapterSubject
@@ -1058,53 +1064,68 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
var chapterName = ""
var authorName = ""
var shareItems = [AnyObject]()
-
+
// Get book title
if let title = self.book.title {
bookTitle = title
subject += " “\(title)”"
}
-
+
// Get chapter name
if let chapter = getCurrentChapterName() {
chapterName = chapter
}
-
+
// Get author name
if let author = self.book.metadata.creators.first {
authorName = author.name
}
-
+
// Sharing html and text
html = "
"
html += "
\(htmlText)
"
html += "
"+readerConfig.localizedShareAllExcerptsFrom+"
"
html += "\(bookTitle) "
html += readerConfig.localizedShareBy+" \(authorName) "
-
+
if let bookShareLink = readerConfig.localizedShareWebLink {
html += "\(bookShareLink.absoluteString)"
shareItems.append(bookShareLink as AnyObject)
}
-
+
html += "
"
text = "\(chapterName)\n\n“\(chapterText)” \n\n\(bookTitle) \n\(readerConfig.localizedShareBy) \(authorName)"
-
+
let act = FolioReaderSharingProvider(subject: subject, text: text, html: html)
shareItems.insert(contentsOf: [act, "" as AnyObject], at: 0)
-
+
let activityViewController = UIActivityViewController(activityItems: shareItems, applicationActivities: nil)
activityViewController.excludedActivityTypes = [UIActivityType.print, UIActivityType.postToVimeo]
-
+
// Pop style on iPad
if let actv = activityViewController.popoverPresentationController {
actv.barButtonItem = sender
}
-
+
present(activityViewController, animated: true, completion: nil)
}
}
+
+ @objc func didTapBookmarkIcon(_ sender: UIBookmarkBarButtonItem) {
+// guard let bookId = (self.book.name as NSString?)?.deletingPathExtension else { return }
+// let pageNumber = folioReader.readerCenter?.currentPageNumber ?? 0
+//
+// let match = Bookmark.MatchingBookmark(id: "", bookId: bookId, currentPage: pageNumber)
+// let bookmark = Bookmark.matchBookmark(match, withConfiguration: readerConfig)
+ if sender.isHighlighed {
+ sender.isHighlighed = false
+
+ } else {
+ sender.isHighlighed = true
+ }
+ }
+
/**
Sharing highlight method.
*/
@@ -1116,23 +1137,23 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
var chapterName = ""
var authorName = ""
var shareItems = [AnyObject]()
-
+
// Get book title
if let title = self.book.title {
bookTitle = title
subject += " “\(title)”"
}
-
+
// Get chapter name
if let chapter = getCurrentChapterName() {
chapterName = chapter
}
-
+
// Get author name
if let author = self.book.metadata.creators.first {
authorName = author.name
}
-
+
// Sharing html and text
html = ""
html += "
\(chapterName)
"
@@ -1140,70 +1161,70 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
html += "
"+readerConfig.localizedShareAllExcerptsFrom+"
"
html += "\(bookTitle) "
html += readerConfig.localizedShareBy+" \(authorName) "
-
+
if let bookShareLink = readerConfig.localizedShareWebLink {
html += "\(bookShareLink.absoluteString)"
shareItems.append(bookShareLink as AnyObject)
}
-
+
html += "
"
text = "\(chapterName)\n\n“\(string)” \n\n\(bookTitle) \n\(readerConfig.localizedShareBy) \(authorName)"
-
+
let act = FolioReaderSharingProvider(subject: subject, text: text, html: html)
shareItems.insert(contentsOf: [act, "" as AnyObject], at: 0)
-
+
let activityViewController = UIActivityViewController(activityItems: shareItems, applicationActivities: nil)
activityViewController.excludedActivityTypes = [UIActivityType.print, UIActivityType.postToVimeo]
-
+
// Pop style on iPad
if let actv = activityViewController.popoverPresentationController {
actv.sourceView = currentPage
actv.sourceRect = rect
}
-
+
present(activityViewController, animated: true, completion: nil)
}
-
+
// MARK: - ScrollView Delegate
-
+
open func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.isScrolling = true
clearRecentlyScrolled()
recentlyScrolled = true
pointNow = scrollView.contentOffset
-
+
if let currentPage = currentPage {
currentPage.webView?.createMenu(options: true)
currentPage.webView?.setMenuVisible(false)
}
-
+
scrollScrubber?.scrollViewWillBeginDragging(scrollView)
}
-
+
open func scrollViewDidScroll(_ scrollView: UIScrollView) {
-
+
if (navigationController?.isNavigationBarHidden == false) {
self.toggleBars()
}
-
+
scrollScrubber?.scrollViewDidScroll(scrollView)
-
+
let isCollectionScrollView = (scrollView is UICollectionView)
let scrollType: ScrollType = ((isCollectionScrollView == true) ? .chapter : .page)
-
+
// Update current reading page
if (isCollectionScrollView == false), let page = currentPage, let webView = page.webView {
-
+
let pageSize = self.readerConfig.isDirection(self.pageHeight, self.pageWidth, self.pageHeight)
let contentOffset = webView.scrollView.contentOffset.forDirection(withConfiguration: self.readerConfig)
let contentSize = webView.scrollView.contentSize.forDirection(withConfiguration: self.readerConfig)
if (contentOffset + pageSize <= contentSize) {
-
+
let webViewPage = pageForOffset(contentOffset, pageHeight: pageSize)
-
+
if (readerConfig.scrollDirection == .horizontalWithVerticalContent) {
let currentIndexPathRow = (page.pageNumber - 1)
-
+
// if the cell reload doesn't save the top position offset
if let oldOffSet = self.currentWebViewScrollPositions[currentIndexPathRow], (abs(oldOffSet.y - scrollView.contentOffset.y) > 100) {
// Do nothing
@@ -1211,7 +1232,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
self.currentWebViewScrollPositions[currentIndexPathRow] = scrollView.contentOffset
}
}
-
+
if (pageIndicatorView?.currentPage != webViewPage) {
pageIndicatorView?.currentPage = webViewPage
}
@@ -1219,17 +1240,17 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
self.delegate?.pageItemChanged?(webViewPage)
}
}
-
+
self.updatePageScrollDirection(inScrollView: scrollView, forScrollType: scrollType)
}
-
+
private func updatePageScrollDirection(inScrollView scrollView: UIScrollView, forScrollType scrollType: ScrollType) {
-
+
let scrollViewContentOffsetForDirection = scrollView.contentOffset.forDirection(withConfiguration: self.readerConfig, scrollType: scrollType)
let pointNowForDirection = pointNow.forDirection(withConfiguration: self.readerConfig, scrollType: scrollType)
// The movement is either positive or negative. This happens if the page change isn't completed. Toggle to the other scroll direction then.
let isCurrentlyPositive = (self.pageScrollDirection == .left || self.pageScrollDirection == .up)
-
+
if (scrollViewContentOffsetForDirection < pointNowForDirection) {
self.pageScrollDirection = .negative(withConfiguration: self.readerConfig, scrollType: scrollType)
} else if (scrollViewContentOffsetForDirection > pointNowForDirection) {
@@ -1240,10 +1261,10 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
self.pageScrollDirection = .positive(withConfiguration: self.readerConfig, scrollType: scrollType)
}
}
-
+
open func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.isScrolling = false
-
+
// Perform the page after a short delay as the collection view hasn't completed it's transition if this method is called (the index paths aren't right during fast scrolls).
delay(0.2, closure: { [weak self] in
if (self?.readerConfig.scrollDirection == .horizontalWithVerticalContent),
@@ -1251,7 +1272,7 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
let currentIndexPathRow = cell.pageNumber - 1
self?.currentWebViewScrollPositions[currentIndexPathRow] = scrollView.contentOffset
}
-
+
if (scrollView is UICollectionView) {
guard let instance = self else {
return
@@ -1266,12 +1287,12 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
})
}
-
+
open func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
recentlyScrolledTimer = Timer(timeInterval:recentlyScrolledDelay, target: self, selector: #selector(FolioReaderCenter.clearRecentlyScrolled), userInfo: nil, repeats: false)
RunLoop.current.add(recentlyScrolledTimer, forMode: RunLoopMode.commonModes)
}
-
+
@objc func clearRecentlyScrolled() {
if(recentlyScrolledTimer != nil) {
recentlyScrolledTimer.invalidate()
@@ -1279,46 +1300,52 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
recentlyScrolled = false
}
-
+
open func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
scrollScrubber?.scrollViewDidEndScrollingAnimation(scrollView)
}
-
+
// MARK: NavigationBar Actions
-
+
@objc func closeReader(_ sender: UIBarButtonItem) {
dismiss()
folioReader.close()
}
-
+
/**
Present chapter list
*/
@objc func presentChapterList(_ sender: UIBarButtonItem) {
folioReader.saveReaderState()
-
+
let chapter = FolioReaderChapterList(folioReader: folioReader, readerConfig: readerConfig, book: book, delegate: self)
let highlight = FolioReaderHighlightList(folioReader: folioReader, readerConfig: readerConfig)
+ let bookmark = FolioReaderBookmarkList(folioReader: folioReader, readerConfig: readerConfig)
let pageController = PageViewController(folioReader: folioReader, readerConfig: readerConfig)
-
+
pageController.viewControllerOne = chapter
pageController.viewControllerTwo = highlight
+ pageController.viewControllerThree = bookmark
pageController.segmentedControlItems = [readerConfig.localizedContentsTitle, readerConfig.localizedHighlightsTitle]
-
+
+ if readerConfig.allowBookmarking {
+ pageController.segmentedControlItems.append(readerConfig.localizedBookmarksTitle)
+ }
+
let nav = UINavigationController(rootViewController: pageController)
present(nav, animated: true, completion: nil)
}
-
+
/**
Present fonts and settings menu
*/
@objc func presentFontsMenu() {
folioReader.saveReaderState()
hideBars()
-
+
let menu = FolioReaderFontsMenu(folioReader: folioReader, readerConfig: readerConfig)
menu.modalPresentationStyle = .custom
-
+
animator = ZFModalTransitionAnimator(modalViewController: menu)
animator.isDragable = false
animator.bounces = false
@@ -1326,21 +1353,21 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
animator.behindViewScale = 1
animator.transitionDuration = 0.6
animator.direction = ZFModalTransitonDirection.bottom
-
+
menu.transitioningDelegate = animator
self.present(menu, animated: true, completion: nil)
}
-
+
/**
Present audio player menu
*/
@objc func presentPlayerMenu(_ sender: UIBarButtonItem) {
folioReader.saveReaderState()
hideBars()
-
+
let menu = FolioReaderPlayerMenu(folioReader: folioReader, readerConfig: readerConfig)
menu.modalPresentationStyle = .custom
-
+
animator = ZFModalTransitionAnimator(modalViewController: menu)
animator.isDragable = true
animator.bounces = false
@@ -1348,18 +1375,18 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
animator.behindViewScale = 1
animator.transitionDuration = 0.6
animator.direction = ZFModalTransitonDirection.bottom
-
+
menu.transitioningDelegate = animator
present(menu, animated: true, completion: nil)
}
-
+
/**
Present Quote Share
*/
func presentQuoteShare(_ string: String) {
let quoteShare = FolioReaderQuoteShare(initWithText: string, readerConfig: readerConfig, folioReader: folioReader, book: book)
let nav = UINavigationController(rootViewController: quoteShare)
-
+
if UIDevice.current.userInterfaceIdiom == .pad {
nav.modalPresentationStyle = .formSheet
}
@@ -1382,17 +1409,17 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
// MARK: FolioPageDelegate
extension FolioReaderCenter: FolioReaderPageDelegate {
-
+
public func pageDidLoad(_ page: FolioReaderPage) {
if self.readerConfig.loadSavedPositionForCurrentBook, let position = folioReader.savedPositionForCurrentBook {
let pageNumber = position["pageNumber"] as? Int
let offset = self.readerConfig.isDirection(position["pageOffsetY"], position["pageOffsetX"], position["pageOffsetY"]) as? CGFloat
let pageOffset = offset
-
+
if isFirstLoad {
updateCurrentPage(page)
isFirstLoad = false
-
+
if (self.currentPageNumber == pageNumber && pageOffset > 0) {
page.scrollPageToOffset(pageOffset!, animated: false)
}
@@ -1403,7 +1430,7 @@ extension FolioReaderCenter: FolioReaderPageDelegate {
updateCurrentPage(page)
isFirstLoad = false
}
-
+
// Go to fragment if needed
if let fragmentID = tempFragment, let currentPage = currentPage , fragmentID != "" {
currentPage.handleAnchor(fragmentID, avoidBeginningAnchors: true, animated: true)
diff --git a/Source/FolioReaderConfig.swift b/Source/FolioReaderConfig.swift
index 033772f3e..6552a0331 100755
--- a/Source/FolioReaderConfig.swift
+++ b/Source/FolioReaderConfig.swift
@@ -138,6 +138,9 @@ open class FolioReaderConfig: NSObject {
/// Allow sharing option, if `false` will hide all sharing icons and options
open var allowSharing = true
+ /// Allow bookmarking option, if `false` will hide all bookmarking icons and options
+ open var allowBookmarking = true
+
/// Enable TTS (Text To Speech)
open var enableTTS = true
@@ -168,6 +171,9 @@ open class FolioReaderConfig: NSObject {
// MARK: Localized strings
+ /// Localizes Bookmarks title
+ open var localizedBookmarksTitle = NSLocalizedString("Bookmarks", comment: "")
+
/// Localizes Highlight title
open var localizedHighlightsTitle = NSLocalizedString("Highlights", comment: "")
diff --git a/Source/Models/Bookmark+Helper.swift b/Source/Models/Bookmark+Helper.swift
new file mode 100644
index 000000000..935936735
--- /dev/null
+++ b/Source/Models/Bookmark+Helper.swift
@@ -0,0 +1,131 @@
+//
+// Bookmark+Helper.swift
+// FolioReaderKit
+//
+// Created by Omar Albeik on 26.03.2018.
+// Copyright (c) 2015 Folio Reader. All rights reserved.
+//
+
+import Foundation
+import RealmSwift
+
+extension Bookmark {
+
+ public struct MatchingBookmark {
+ var id: String
+ var bookId: String
+ var currentPage: Int
+ }
+
+ /**
+ Match a bookmark on string.
+ */
+ public static func matchBookmark(_ matchingBookmark: MatchingBookmark, withConfiguration readerConfig: FolioReaderConfig) -> Bookmark? {
+
+ guard let bookmark = Bookmark.allByBookId(withConfiguration: readerConfig, bookId: matchingBookmark.bookId, andPage: matchingBookmark.currentPage as NSNumber).filter({ $0.bookmarkId == matchingBookmark.id }).first else {
+
+ let bookmark = Bookmark()
+ bookmark.bookmarkId = matchingBookmark.id
+ bookmark.page = matchingBookmark.currentPage
+ bookmark.bookId = matchingBookmark.bookId
+ bookmark.date = Date()
+
+ return bookmark
+ }
+
+ return bookmark
+ }
+
+ /// Save a Bookmark with completion block
+ ///
+ /// - Parameters:
+ /// - readerConfig: Current folio reader configuration.
+ /// - completion: Completion block.
+ public func persist(withConfiguration readerConfig: FolioReaderConfig, completion: Completion? = nil) {
+ do {
+ let realm = try Realm(configuration: readerConfig.realmConfiguration)
+ realm.beginWrite()
+ realm.add(self, update: true)
+ try realm.commitWrite()
+ completion?(nil)
+ } catch let error as NSError {
+ print("Error on persist bookmark: \(error)")
+ completion?(error)
+ }
+ }
+
+ /// Remove a Bookmark
+ ///
+ /// - Parameter readerConfig: Current folio reader configuration.
+ public func remove(withConfiguration readerConfig: FolioReaderConfig) {
+ do {
+ guard let realm = try? Realm(configuration: readerConfig.realmConfiguration) else {
+ return
+ }
+ try realm.write {
+ realm.delete(self)
+ try realm.commitWrite()
+ }
+ } catch let error as NSError {
+ print("Error on remove bookmark: \(error)")
+ }
+ }
+
+ /// Remove a Bookmark by ID
+ ///
+ /// - Parameters:
+ /// - readerConfig: Current folio reader configuration.
+ /// - bookmarkId: The ID to be removed
+ public static func removeById(withConfiguration readerConfig: FolioReaderConfig, bookmarkId: String) {
+ var bookmark: Bookmark?
+ let predicate = NSPredicate(format:"bookmarkId = %@", bookmarkId)
+
+ do {
+ let realm = try Realm(configuration: readerConfig.realmConfiguration)
+ bookmark = realm.objects(Bookmark.self).filter(predicate).toArray(Bookmark.self).first
+ bookmark?.remove(withConfiguration: readerConfig)
+ } catch let error as NSError {
+ print("Error on remove bookmark by id: \(error)")
+ }
+ }
+
+ /// Return a list of Bookmarks with a given ID
+ ///
+ /// - Parameters:
+ /// - readerConfig: Current folio reader configuration.
+ /// - bookId: Book ID
+ /// - page: Page number
+ /// - Returns: Return a list of Bookmarks
+ public static func allByBookId(withConfiguration readerConfig: FolioReaderConfig, bookId: String, andPage page: NSNumber? = nil) -> [Bookmark] {
+ var bookmarks: [Bookmark]?
+ var predicate = NSPredicate(format: "bookId = %@", bookId)
+ if let page = page {
+ predicate = NSPredicate(format: "bookId = %@ && page = %@", bookId, page)
+ }
+
+ do {
+ let realm = try Realm(configuration: readerConfig.realmConfiguration)
+ bookmarks = realm.objects(Bookmark.self).filter(predicate).toArray(Bookmark.self)
+ return (bookmarks ?? [])
+ } catch let error as NSError {
+ print("Error on fetch all by book Id: \(error)")
+ return []
+ }
+ }
+
+ /// Return all Bookmarks
+ ///
+ /// - Parameter readerConfig: - readerConfig: Current folio reader configuration.
+ /// - Returns: Return all Bookmarks
+ public static func all(withConfiguration readerConfig: FolioReaderConfig) -> [Bookmark] {
+ var bookmarks: [Bookmark]?
+ do {
+ let realm = try Realm(configuration: readerConfig.realmConfiguration)
+ bookmarks = realm.objects(Bookmark.self).toArray(Bookmark.self)
+ return bookmarks ?? []
+ } catch let error {
+ print("Error on fetch all: \(error)")
+ return []
+ }
+ }
+}
diff --git a/Source/Models/Bookmark.swift b/Source/Models/Bookmark.swift
new file mode 100644
index 000000000..55e00cc7d
--- /dev/null
+++ b/Source/Models/Bookmark.swift
@@ -0,0 +1,22 @@
+//
+// Bookmark.swift
+// FolioReaderKit
+//
+// Created by Omar Albeik on 26.03.2018.
+// Copyright (c) 2015 Folio Reader. All rights reserved.
+//
+
+import Foundation
+import RealmSwift
+
+/// A Bookmark object
+open class Bookmark: Object {
+ @objc open dynamic var bookId: String!
+ @objc open dynamic var date: Date!
+ @objc open dynamic var bookmarkId: String!
+ @objc open dynamic var page: Int = 0
+
+ override open class func primaryKey()-> String {
+ return "bookmarkId"
+ }
+}
diff --git a/Source/PageViewController.swift b/Source/PageViewController.swift
index fcfaf6383..46fa5f29f 100644
--- a/Source/PageViewController.swift
+++ b/Source/PageViewController.swift
@@ -15,6 +15,7 @@ class PageViewController: UIPageViewController {
var segmentedControlItems = [String]()
var viewControllerOne: UIViewController!
var viewControllerTwo: UIViewController!
+ var viewControllerThree: UIViewController!
var index: Int
fileprivate var readerConfig: FolioReaderConfig
fileprivate var folioReader: FolioReader
@@ -43,13 +44,22 @@ class PageViewController: UIPageViewController {
segmentedControl.selectedSegmentIndex = index
segmentedControl.setWidth(100, forSegmentAt: 0)
segmentedControl.setWidth(100, forSegmentAt: 1)
+ segmentedControl.setWidth(100, forSegmentAt: 2)
self.navigationItem.titleView = segmentedControl
viewList = [viewControllerOne, viewControllerTwo]
+ if readerConfig.allowBookmarking {
+ viewList.append(viewControllerThree)
+ }
+
viewControllerOne.didMove(toParentViewController: self)
viewControllerTwo.didMove(toParentViewController: self)
+ if readerConfig.allowBookmarking {
+ viewControllerThree.didMove(toParentViewController: self)
+ }
+
self.delegate = self
self.dataSource = self
diff --git a/Source/Resources/Images.xcassets/icon-navbar-bookmark-selected.imageset/Contents.json b/Source/Resources/Images.xcassets/icon-navbar-bookmark-selected.imageset/Contents.json
new file mode 100644
index 000000000..54824e564
--- /dev/null
+++ b/Source/Resources/Images.xcassets/icon-navbar-bookmark-selected.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "icon-navbar-bookmark-selected.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Source/Resources/Images.xcassets/icon-navbar-bookmark-selected.imageset/icon-navbar-bookmark-selected.pdf b/Source/Resources/Images.xcassets/icon-navbar-bookmark-selected.imageset/icon-navbar-bookmark-selected.pdf
new file mode 100644
index 000000000..c6a1faec9
Binary files /dev/null and b/Source/Resources/Images.xcassets/icon-navbar-bookmark-selected.imageset/icon-navbar-bookmark-selected.pdf differ
diff --git a/Source/Resources/Images.xcassets/icon-navbar-bookmark.imageset/Contents.json b/Source/Resources/Images.xcassets/icon-navbar-bookmark.imageset/Contents.json
new file mode 100644
index 000000000..62366f8cf
--- /dev/null
+++ b/Source/Resources/Images.xcassets/icon-navbar-bookmark.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "icon-navbar-bookmark.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Source/Resources/Images.xcassets/icon-navbar-bookmark.imageset/icon-navbar-bookmark.pdf b/Source/Resources/Images.xcassets/icon-navbar-bookmark.imageset/icon-navbar-bookmark.pdf
new file mode 100644
index 000000000..503de88af
Binary files /dev/null and b/Source/Resources/Images.xcassets/icon-navbar-bookmark.imageset/icon-navbar-bookmark.pdf differ
diff --git a/Source/UIBookmarkBarButtonItem.swift b/Source/UIBookmarkBarButtonItem.swift
new file mode 100644
index 000000000..6fa8acb42
--- /dev/null
+++ b/Source/UIBookmarkBarButtonItem.swift
@@ -0,0 +1,34 @@
+//
+// UIBookmarkBarButtonItem.swift
+// AEXML
+//
+// Created by Omar Albeik on 26.03.2018.
+//
+
+import UIKit
+
+class UIBookmarkBarButtonItem: UIBarButtonItem {
+
+ var isHighlighed = false {
+ didSet {
+ image = UIImage(readerImageNamed: isHighlighed ? "icon-navbar-bookmark-selected" : "icon-navbar-bookmark")
+ }
+ }
+
+ var readerConfig: FolioReaderConfig? {
+ didSet {
+ print("readerConfig")
+ guard let config = readerConfig else { return }
+ image = image?.ignoreSystemTint(withConfiguration: config)
+ }
+ }
+
+ convenience init(target: Any?, action: Selector?, isHighlighed: Bool = false, readerConfig: FolioReaderConfig) {
+
+ self.init(image: UIImage(readerImageNamed: "icon-navbar-bookmark"), style: .plain, target: target, action: action)
+
+ self.isHighlighed = isHighlighed
+ self.readerConfig = readerConfig
+ }
+
+}