--- /dev/null
+//
+// BookDetailsViewController.swift
+// WolneLektury
+//
+// Created by Pawel Dabrowski on 19/06/2018.
+// Copyright © 2018 Fundacja Nowoczesna Polska. All rights reserved.
+//
+
+import UIKit
+import MZDownloadManager
+import FolioReaderKit
+import MatomoTracker
+
+class BookDetailsViewController: WLViewController {
+
+ var bookDetailsModel: BookDetailsModel?
+ private var bookSlug: String!
+ private var isFavourite = false
+ private var isBookPremium: Bool = false
+ @IBOutlet weak var headerView: UIView!
+ @IBOutlet weak var refreshButton: ActivityIndicatorButton!
+ @IBOutlet weak var backButton: UIButton!
+ @IBOutlet weak var tableView: UITableView!
+
+ @IBOutlet weak var favouriteButton: UIButton!
+ @IBOutlet weak var shareButton: UIButton!
+ @IBOutlet weak var buttonsContainer: UIView!
+ @IBOutlet weak var headerHeightConstraint: NSLayoutConstraint!
+ @IBOutlet weak var buttonsContainerWidthConstraint: NSLayoutConstraint!
+
+ @IBOutlet weak var becomeFriendView: UIView!
+ @IBOutlet weak var becomeFriendLabel: UILabel!
+ @IBOutlet weak var becomeFriendButton: UIButton!
+ @IBOutlet weak var becomeFriendStarImageView: UIImageView!
+ @IBOutlet weak var headerLabel: UILabel!
+
+ var topColor = UIColor(red:0.91, green:0.31, blue:0.20, alpha:1.00)
+ var headerProgress: CGFloat = 100
+
+ var cellsArray = [WLTableViewCell]()
+ var readCell: BookDetailsButtonTableViewCell?
+ var audiobookCell: BookDetailsButtonTableViewCell?
+ var readingState: ReadingStateModel.ReadingState = .unknown
+
+ @IBAction func refreshButtonAction(_ sender: Any) {
+ refreshData()
+ }
+
+ @IBAction func becomeFriendButtonAction(_ sender: Any) {
+ onBecomeFriendButtonTapped()
+ }
+
+ @IBAction func backButtonAction(_ sender: Any) {
+ navigationController?.popViewController(animated: true)
+ }
+
+ @IBAction func favouriteButtonAction(_ sender: Any) {
+ setFavourite(favourite: !isFavourite)
+ }
+
+ @IBAction func sharebuttonAction(_ sender: UIButton) {
+
+ if let url = bookDetailsModel?.url {
+ self.share(string: url, button: sender)
+ }
+ }
+
+ static func instance(bookSlug: String, isBookPremium: Bool = false) -> BookDetailsViewController{
+ let controller = BookDetailsViewController.instance()
+ controller.bookSlug = bookSlug
+ controller.isBookPremium = isBookPremium
+ return controller
+ }
+
+ var bigHeaderHeight: CGFloat = 200
+ var smallHeaderHeight: CGFloat = 200
+
+ open override var preferredStatusBarStyle : UIStatusBarStyle {
+ return .lightContent
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ headerLabel.text = ""
+ tableView.isHidden = true
+ buttonsContainer.isHidden = true
+ becomeFriendStarImageView.tintColor = UIColor.white
+ becomeFriendButton.layer.cornerRadius = 18
+ refreshButton.tintColor = UIColor.white
+
+ bigHeaderHeight = 190 + UIApplication.shared.statusBarFrame.size.height
+ smallHeaderHeight = 44 + UIApplication.shared.statusBarFrame.size.height
+ headerHeightConstraint.constant = bigHeaderHeight
+
+ headerView.backgroundColor = Constants.Colors.navbarBgColor()
+ tableView.rowHeight = UITableViewAutomaticDimension
+ tableView.estimatedRowHeight = 200
+ tableView.separatorStyle = .none
+ tableView.registerNib(name: "BookDetailsHeaderTableViewCell")
+ tableView.registerNib(name: "BookDetailsInfoTableViewCell")
+ refreshData()
+
+ if syncManager.isLoggedIn() == false{
+ favouriteButton.isHidden = true
+ buttonsContainerWidthConstraint.constant = 42
+ }
+
+ let tintColor = UIColor(red:0.91, green:0.31, blue:0.20, alpha:1.00)
+ favouriteButton.tintColor = tintColor
+ shareButton.tintColor = tintColor
+ favouriteButton.layer.cornerRadius = 21
+ shareButton.layer.cornerRadius = 21
+ let buttonBorderColor = UIColor(red:0.96, green:0.96, blue:0.96, alpha:1.00)
+ favouriteButton.layer.borderColor = buttonBorderColor.cgColor
+ shareButton.layer.borderColor = buttonBorderColor.cgColor
+ favouriteButton.layer.borderWidth = 1.0
+ shareButton.layer.borderWidth = 1.0
+
+ edgesForExtendedLayout = []
+ extendedLayoutIncludesOpaqueBars = false
+ if #available(iOS 11.0, *) {
+ tableView.contentInsetAdjustmentBehavior = .never
+ } else {
+ automaticallyAdjustsScrollViewInsets = false
+ }
+
+ if isBookPremium && DatabaseManager.shared.isUserPremium() == false {
+ becomeFriendView.isHidden = false
+ becomeFriendLabel.text = "become_friend_desc".localized
+ becomeFriendButton.text = "become_friend_button".localized.uppercased()
+ }
+ else {
+ becomeFriendView.isHidden = true
+ }
+
+ refreshIsFavourite()
+ refreshReadingState()
+ }
+
+ func createCells(bookDetails: BookDetailsModel) {
+ cellsArray = [WLTableViewCell]()
+ self.bookDetailsModel = bookDetails
+ let titleCell = BookDetailsHeaderTableViewCell.instance(height: bigHeaderHeight)
+ titleCell.setup(bookModel: bookDetails, topColor: topColor)
+ cellsArray.append(titleCell)
+ let infoCell = BookDetailsInfoTableViewCell.instance()
+ infoCell.setup(bookModel: bookDetails)
+ cellsArray.append(infoCell)
+ cellsArray.append(BookDetailsSeparatorTableViewCell.instance())
+
+ if bookDetails.fragmentHtml.count > 0{
+ let fragmentCell = BookDetailsFragmentTableViewCell.instance()
+ fragmentCell.setup(fragmentTitle: bookDetails.fragmentTitle, fragmentHtml: bookDetails.fragmentHtml)
+ cellsArray.append( fragmentCell)
+ cellsArray.append(BookDetailsSeparatorTableViewCell.instance())
+
+ }
+
+ if isBookPremium && DatabaseManager.shared.isUserPremium() == false{ // dont show buttons when user is not premium
+
+ }
+ else{
+
+ if bookDetails.epub.count > 0{
+ var buttonType = BookDetailsButtonType.download_ebook
+ switch DownloadManager.sharedInstance.checkEbookStatus(bookSlug: bookDetails.slug){
+ case .downloaded:
+ buttonType = .download_ebook_read
+ case .downloading:
+ DownloadManager.sharedInstance.delegate = self
+ buttonType = .download_ebook_loading
+ default:
+ break
+ }
+ readCell = BookDetailsButtonTableViewCell.instance(delegate: self, bookDetailsButtonType: buttonType, bookDetailsModel: bookDetails)
+ cellsArray.append(readCell!)
+ }
+
+ if bookDetails.getAudiobookFilesUrls().count > 0 {
+ var buttonType = BookDetailsButtonType.download_audiobook
+
+ switch DownloadManager.sharedInstance.checkAudiobookStatus(bookDetailsModel: bookDetails){
+ case .downloaded:
+ buttonType = .download_audiobook_listen
+ case .downloading:
+ DownloadManager.sharedInstance.delegate = self
+ buttonType = .download_audiobook_loading
+ default:
+ break
+ }
+ audiobookCell = BookDetailsButtonTableViewCell.instance(delegate: self, bookDetailsButtonType: buttonType, bookDetailsModel: bookDetails)
+ cellsArray.append(audiobookCell!)
+ }
+
+// cellsArray.append(BookDetailsButtonTableViewCell.instance(delegate: self, bookDetailsButtonType: .support_us, bookDetailsModel: bookDetails))
+ }
+ }
+
+ func bookDetailsDownloaded(bookDetails: BookDetailsModel){
+ self.bookDetailsModel = bookDetails
+ tableView.isHidden = false
+ buttonsContainer.isHidden = false
+ headerView.alpha = 0
+ topColor = self.bookDetailsModel!.bgColor
+ headerLabel.text = bookDetails.title
+ createCells(bookDetails: self.bookDetailsModel!)
+ tableView.reloadData()
+ }
+
+ func setFavourite(favourite: Bool){
+ isFavourite = favourite
+ refreshFavouriteButton()
+
+ syncManager.setFavouriteState(slug: bookSlug, favourite: favourite) {[weak self] (result) in
+
+ guard let strongSelf = self else{
+ return
+ }
+
+ strongSelf.refreshButton.setIndicatorButtonState(state: .hidden)
+ switch result {
+ case .success/*(let model)*/:
+ strongSelf.isFavourite = favourite
+ case .failure/*(let error)*/:
+
+ break
+ }
+ }
+ }
+
+ func refreshFavouriteButton(){
+ favouriteButton.setImage(isFavourite ? #imageLiteral(resourceName: "icon_heart-fill-big") : #imageLiteral(resourceName: "icon_heart-outline-big"), for: .normal)
+ }
+
+ func refreshIsFavourite(){
+ guard syncManager.isLoggedIn() else { return }
+
+ syncManager.getFavouriteState(slug: bookSlug) {[weak self] (result) in
+
+ guard let strongSelf = self else{
+ return
+ }
+
+ switch result {
+ case .success(let model):
+ strongSelf.isFavourite = (model as! LikeModel).likes
+ strongSelf.refreshFavouriteButton()
+ case .failure/*(let error)*/:
+ break
+ }
+ }
+
+ }
+
+ func refreshReadingState(){
+
+ guard syncManager.isLoggedIn() else {
+ readingState = .unknown
+ return
+ }
+
+ syncManager.getReadingState(slug: bookSlug, completionHandler: { [weak self] (result) in
+
+ guard let strongSelf = self else{
+ return
+ }
+
+ switch result {
+ case .success(let model):
+ strongSelf.readingState = (model as! ReadingStateModel).state
+ case .failure/*(let error)*/:
+ break
+ }
+ })
+ }
+
+
+ func refreshData(){
+ var storedBook = false
+ if let downloadedModel = DatabaseManager.shared.getBookFromDownloaded(bookSlug: bookSlug) {
+ storedBook = true
+ bookDetailsDownloaded(bookDetails: downloadedModel)
+ }
+
+ if storedBook == false {
+ refreshButton.setIndicatorButtonState(state: .loading)
+ }
+
+ syncManager.getBookDetails(bookSlug: bookSlug) {[weak self] (result) in
+
+ guard let strongSelf = self else{
+ return
+ }
+
+ strongSelf.refreshButton.setIndicatorButtonState(state: .hidden)
+ switch result {
+ case .success(let model):
+ if let model = model as? BookDetailsModel{
+ model.slug = strongSelf.bookSlug
+ if storedBook {
+ DatabaseManager.shared.addBookToDownloaded(bookDetailsModel: model)
+ }
+ strongSelf.bookDetailsDownloaded(bookDetails: model)
+ }
+
+ case .failure/*(let error)*/:
+ if storedBook == false {
+ strongSelf.refreshButton.setIndicatorButtonState(state: .button)
+ self?.view.makeToast("book_loading_error".localized, duration: 3.0, position: .bottom)
+ }
+ }
+ }
+ }
+
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ openedPlayer = false
+ navigationController?.setNavigationBarHidden(true, animated: true)
+ DownloadManager.sharedInstance.delegate = self
+ }
+
+ override func viewWillDisappear(_ animated: Bool) {
+ super.viewWillDisappear(animated)
+ if !openedPlayer {
+ navigationController?.setNavigationBarHidden(false, animated: true)
+ }
+ DownloadManager.sharedInstance.delegate = nil
+ }
+
+ func downloadEbook(){
+ guard let bookDetailsModel = bookDetailsModel, bookDetailsModel.epub.count > 0 else {return}
+
+ DatabaseManager.shared.addBookToDownloaded(bookDetailsModel: bookDetailsModel)
+ DownloadManager.sharedInstance.delegate = self
+ DownloadManager.sharedInstance.downloadEbook(bookDetailsModel: bookDetailsModel)
+ }
+
+ var openedPlayer = false
+ func downloadAudiobooks(){
+ guard let bookDetailsModel = bookDetailsModel, bookDetailsModel.getAudiobookFilesUrls().count > 0 else {return}
+
+ DatabaseManager.shared.addBookToDownloaded(bookDetailsModel: bookDetailsModel)
+
+ DownloadManager.sharedInstance.delegate = self
+ DownloadManager.sharedInstance.downloadAudiobooks(bookDetailsModel: bookDetailsModel)
+ }
+
+ func updateReadingStateIfNeeded(state: ReadingStateModel.ReadingState) {
+ if state == .reading && readingState != .not_started {
+ return
+ }
+
+ if state == .complete && readingState == .complete {
+ return
+ }
+
+ syncManager.setReadingState(slug: bookSlug, readingState: state, completionHandler: nil)
+ }
+
+ func openFolioReader() {
+ guard ebookExists(bookSlug: bookSlug) else {
+ return
+ }
+
+ updateReadingStateIfNeeded(state: .reading)
+
+ var array = parentNames()
+ array.append("Reader")
+ MatomoTracker.shared.track(view: array)
+
+ let config = WLReaderConfig()
+ let bookPath = FileType.ebook.pathForFileName(filename: bookSlug, bookSlug: bookSlug)
+ let bookDirectory = FileType.ebook.destinationPathWithSlug(bookSlug: bookSlug) + "unzipped/"
+
+ if !FileManager.default.fileExists(atPath: bookDirectory) {
+ try! FileManager.default.createDirectory(atPath: bookDirectory, withIntermediateDirectories: true, attributes: nil)
+ }
+
+ let folioReader = FolioReader()
+ folioReader.delegate = self
+
+ folioReader.presentReader(parentViewController: self.navigationController!, withEpubPath: bookPath, unzipPath: bookDirectory, andConfig: config, shouldRemoveEpub: false)
+ }
+
+ func openAudiobook(afterDownload: Bool) {
+ guard let bookDetailsModel = bookDetailsModel else { return }
+
+ updateReadingStateIfNeeded(state: .reading)
+
+ openedPlayer = true
+ navigationController?.pushViewController(PlayerViewController.instance(bookDetailsModel: bookDetailsModel), animated: true)
+ }
+
+ deinit {
+ }
+}
+
+extension BookDetailsViewController: UITableViewDataSource{
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return cellsArray.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ return cellsArray[indexPath.row]
+ }
+}
+
+extension BookDetailsViewController: UITableViewDelegate{
+ func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+ return cellsArray[indexPath.row].getHeight()
+ }
+
+ func scrollViewDidScroll(_ scrollView: UIScrollView) {
+ print(scrollView.contentOffset)
+
+ var progress: CGFloat = 100
+
+ var newValue = bigHeaderHeight - scrollView.contentOffset.y
+ if newValue < smallHeaderHeight{
+ newValue = smallHeaderHeight
+ progress = 0
+ }
+ else{
+ progress = (bigHeaderHeight - smallHeaderHeight - scrollView.contentOffset.y) / (bigHeaderHeight - smallHeaderHeight)
+ if progress > 100{
+ progress = 100
+ }
+ }
+
+ headerView.alpha = 1 - progress
+ buttonsContainer.alpha = progress
+ headerHeightConstraint.constant = newValue
+ headerProgress = progress
+ }
+
+ func showHeader(){
+ headerView.alpha = 1
+ buttonsContainer.alpha = 0
+ headerHeightConstraint.constant = smallHeaderHeight
+ headerProgress = 0
+ }
+}
+
+extension BookDetailsViewController: BookDetailsButtonTableViewCellDelegate{
+
+ func bookDetailsButtonTableViewCellButtonTapped(buttonType: BookDetailsButtonType){
+ switch buttonType {
+ case .download_ebook:
+ downloadEbook()
+ case .download_ebook_read:
+ openFolioReader()
+ case .download_audiobook:
+ downloadAudiobooks()
+ case .download_audiobook_listen:
+ openAudiobook(afterDownload: false)
+ default:
+ break
+ }
+ }
+
+ func bookDetailsButtonTableViewCellDeleteButtonTapped(buttonType: BookDetailsButtonType){
+ switch buttonType {
+ case .download_ebook_read, .download_ebook_loading:
+ DownloadManager.sharedInstance.deleteEbook(bookSlug: bookSlug)
+ readCell?.setup(bookDetailsButtonType: .download_ebook, progress: nil, bookDetailsModel: bookDetailsModel)
+ bookDetailsModel = (bookDetailsModel?.copy() as! BookDetailsModel)
+ let _ = DatabaseManager.shared.removeBookFromDownloaded(bookSlug: bookSlug)
+ case .download_audiobook_listen, .download_audiobook_loading:
+ if let bookDetails = PlayerController.shared.currentBookDetails, bookDetails.slug == bookSlug{
+ PlayerController.shared.stopAndClear()
+ }
+ DownloadManager.sharedInstance.clearDownloadingAudiobookFromQueue(bookSlug: bookSlug)
+ DownloadManager.sharedInstance.deleteAudiobook(bookSlug: bookSlug)
+ audiobookCell?.setup(bookDetailsButtonType: .download_audiobook, progress:nil, bookDetailsModel: bookDetailsModel)
+ bookDetailsModel = (bookDetailsModel?.copy() as! BookDetailsModel)
+ let _ = DatabaseManager.shared.removeBookFromDownloaded(bookSlug: bookSlug)
+ default:
+ break
+ }
+ }
+}
+
+extension BookDetailsViewController: DownloadManagerDelegate{
+
+ func downloadManagerDownloadProgressChanged(model: MZDownloadModel, allProgress: Float, bookSlug: String) {
+ guard let bookDetailsModel = bookDetailsModel, bookDetailsModel.slug == bookSlug else { return }
+
+ if model.isAudiobook() {
+ audiobookCell?.setup(bookDetailsButtonType: .download_audiobook_loading, progress: allProgress, bookDetailsModel: bookDetailsModel)
+ }
+ else if model.isEbook() {
+ readCell?.setup(bookDetailsButtonType: .download_ebook_loading, progress: model.progress, bookDetailsModel: bookDetailsModel)
+ }
+ }
+
+ func downloadManagerDownloadFinished(model: MZDownloadModel, bookSlug: String) {
+ guard let bookDetailsModel = bookDetailsModel, bookDetailsModel.slug == bookSlug else { return }
+
+ if model.isAudiobook() {
+
+ bookDetailsModel.setInitialAudiobookChaptersValuesIfNeeded()
+
+ audiobookCell?.setup(bookDetailsButtonType: .download_audiobook_listen, progress: nil, bookDetailsModel: bookDetailsModel)
+ openAudiobook(afterDownload: true)
+ }
+ else if model.isEbook() {
+ readCell?.setup(bookDetailsButtonType: .download_ebook_read, progress: nil, bookDetailsModel: bookDetailsModel)
+ openFolioReader()
+ }
+ }
+
+ func downloadManagerDownloadFailed(model: MZDownloadModel, bookSlug: String) {
+ guard let bookDetailsModel = bookDetailsModel, bookDetailsModel.slug == bookSlug else { return }
+
+ if model.isAudiobook() {
+ view.makeToast("audiobook_download_error".localized, duration: 3.0, position: .bottom)
+ audiobookCell?.setup(bookDetailsButtonType: .download_audiobook, progress: nil, bookDetailsModel: bookDetailsModel)
+ }
+ else if model.isEbook() {
+ view.makeToast("book_download_error".localized, duration: 3.0, position: .bottom)
+ readCell?.setup(bookDetailsButtonType: .download_ebook, progress: nil, bookDetailsModel: bookDetailsModel)
+ }
+ }
+}
+
+extension BookDetailsViewController: FolioReaderDelegate{
+ @objc func folioReaderDidClose(_ folioReader: FolioReader) {
+ guard let bookDetailsModel = bookDetailsModel, let progressValues = folioReader.getProgressValues(), progressValues.currentPage > 0, progressValues.currentPage <= progressValues.totalPages else { return }
+
+ DatabaseManager.shared.updateCurrentChapters(bookDetailsModel: bookDetailsModel, currentChapter: progressValues.currentPage, totalChapters: progressValues.totalPages, currentAudioChapter: nil, totalAudioChapters: nil)
+ readCell?.setup(bookDetailsButtonType: .download_ebook_read, progress: nil, bookDetailsModel: bookDetailsModel)
+
+ if progressValues.currentPage == progressValues.totalPages && readingState == ReadingStateModel.ReadingState.reading{
+ updateReadingStateIfNeeded(state: .complete)
+ }
+ }
+}