diff --git a/Kiwix-iOS/Assets.xcassets/Bookmarks/Dots.imageset/more-2.png b/Kiwix-iOS/Assets.xcassets/Bookmarks/Dots.imageset/more-2.png deleted file mode 100644 index 106baee9..00000000 Binary files a/Kiwix-iOS/Assets.xcassets/Bookmarks/Dots.imageset/more-2.png and /dev/null differ diff --git a/Kiwix-iOS/Assets.xcassets/Bookmarks/Dots.imageset/Contents.json b/Kiwix-iOS/Assets.xcassets/Dots.imageset/Contents.json similarity index 87% rename from Kiwix-iOS/Assets.xcassets/Bookmarks/Dots.imageset/Contents.json rename to Kiwix-iOS/Assets.xcassets/Dots.imageset/Contents.json index 1dd8ef56..6c053b83 100644 --- a/Kiwix-iOS/Assets.xcassets/Bookmarks/Dots.imageset/Contents.json +++ b/Kiwix-iOS/Assets.xcassets/Dots.imageset/Contents.json @@ -10,7 +10,7 @@ }, { "idiom" : "universal", - "filename" : "more-2.png", + "filename" : "rsz_1more-2.png", "scale" : "3x" } ], diff --git a/Kiwix-iOS/Assets.xcassets/Dots.imageset/rsz_1more-2.png b/Kiwix-iOS/Assets.xcassets/Dots.imageset/rsz_1more-2.png new file mode 100644 index 00000000..1962d59a Binary files /dev/null and b/Kiwix-iOS/Assets.xcassets/Dots.imageset/rsz_1more-2.png differ diff --git a/Kiwix-iOS/Controller/Bookmark/BookmarkCollectionController.swift b/Kiwix-iOS/Controller/Bookmark/BookmarkCollectionController.swift index 732c231e..ef875da5 100644 --- a/Kiwix-iOS/Controller/Bookmark/BookmarkCollectionController.swift +++ b/Kiwix-iOS/Controller/Bookmark/BookmarkCollectionController.swift @@ -39,7 +39,7 @@ class BookmarkCollectionController: CoreDataCollectionBaseController, UICollecti func configureItemWidth(collectionViewWidth: CGFloat) { let itemsPerRow = ((collectionViewWidth - 10) / 320).rounded() - self.itemWidth = floor((collectionViewWidth - (itemsPerRow + 1) * 10) / itemsPerRow) + itemWidth = floor((collectionViewWidth - (itemsPerRow + 1) * 10) / itemsPerRow) } // MARK: - UI Control diff --git a/Kiwix-iOS/Controller/Library/LibraryBooksController.swift b/Kiwix-iOS/Controller/Library/LibraryBooksController.swift index e75bf612..c7fff831 100644 --- a/Kiwix-iOS/Controller/Library/LibraryBooksController.swift +++ b/Kiwix-iOS/Controller/Library/LibraryBooksController.swift @@ -8,14 +8,159 @@ import UIKit import CoreData +import ProcedureKit +import DZNEmptyDataSet -class LibraryBooksController: UIViewController { - - @IBOutlet weak var collectionView: UICollectionView! +class LibraryBooksController: CoreDataCollectionBaseController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, LibraryCollectionCellDelegate { + private(set) var itemWidth: CGFloat = 0.0 @IBAction func dismissButtonTapped(_ sender: UIBarButtonItem) { dismiss(animated: true, completion: nil) } + func configureItemWidth(collectionViewWidth: CGFloat) { + let itemsPerRow = (collectionViewWidth / 320).rounded() + itemWidth = (collectionViewWidth - 1 * (itemsPerRow - 1)) / itemsPerRow + } + override func viewDidLoad() { + super.viewDidLoad() + configureRefreshControl() + + if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout { + layout.minimumInteritemSpacing = 1 + layout.minimumLineSpacing = 1 + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + refreshAutomatically() + collectionView.collectionViewLayout.invalidateLayout() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + configureItemWidth(collectionViewWidth: collectionView.frame.width) + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + configureItemWidth(collectionViewWidth: collectionView.frame.width) + collectionView.collectionViewLayout.invalidateLayout() + } + + // MARK: - Refresh + + private(set) var isRefreshing = false // used to control text on empty table view + + private func configureRefreshControl() { + collectionView.refreshControl = RefreshLibControl() + collectionView.refreshControl?.addTarget(self, action: #selector(refresh), for: .valueChanged) + } + + func refreshAutomatically() { + guard let date = Preference.libraryLastRefreshTime else { refresh(); return } + guard date.timeIntervalSinceNow < -86400 else {return} + refresh() + } + + func refresh() { + let operation = RefreshLibraryOperation() + operation.add(observer: WillExecuteObserver { (operation) in + OperationQueue.main.addOperation({ + // Configure empty table data set, so it shows "Refreshing..." + self.isRefreshing = true + self.collectionView.reloadEmptyDataSet() + }) + }) + operation.add(observer: DidFinishObserver { (operation, errors) in + guard let operation = operation as? RefreshLibraryOperation else {return} + OperationQueue.main.addOperation({ + defer { + self.collectionView.refreshControl?.endRefreshing() + self.isRefreshing = false + self.collectionView.reloadEmptyDataSet() + } + + if let _ = errors.first { + // handle error [network, xmlparse] + } else { + if operation.firstTime { + //self.showLanguageFilterAlert() + //self.configureNavBarButtons() + } else { +// self.showRefreshSuccessMessage() + } + } + }) + }) + GlobalQueue.shared.add(operation: operation) + } + + // MARK: - UICollectionView Data Source + + func numberOfSections(in collectionView: UICollectionView) -> Int { + return fetchedResultController.sections?.count ?? 0 + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return fetchedResultController.sections?[section].numberOfObjects ?? 0 + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! LibraryCollectionCell + + let book = fetchedResultController.object(at: indexPath) + cell.delegate = self + cell.imageView.image = UIImage(data: book.favIcon ?? Data()) + cell.titleLabel.text = book.title + cell.subtitleLabel.text = [ + book.dateDescription, + book.fileSizeDescription, + book.articleCountDescription + ].flatMap({$0}).joined(separator: " ") + cell.descriptionLabel.text = book.desc + cell.hasPicLabel.isHidden = book.hasPic + + return cell + } + + func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { + let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Header", for: indexPath) as! LibraryCollectionHeader + header.textLabel.text = fetchedResultController.sections?[indexPath.section].name + return header + } + + // MARK: - UICollectionViewDelegateFlowLayout + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: itemWidth, height: 66) + } + + // MARK: - LibraryCollectionCellDelegate + + func didTapMoreButton(cell: LibraryCollectionCell) { + guard let indexPath = collectionView.indexPath(for: cell) else {return} + print("\(indexPath) tapped") + + } + + // MARK: - NSFetchedResultsController + + let managedObjectContext = AppDelegate.persistentContainer.viewContext + lazy var fetchedResultController: NSFetchedResultsController = { + let fetchRequest = Book.fetchRequest() + let langDescriptor = NSSortDescriptor(key: "language.name", ascending: true) + let titleDescriptor = NSSortDescriptor(key: "title", ascending: true) + fetchRequest.sortDescriptors = [langDescriptor, titleDescriptor] + fetchRequest.predicate = NSPredicate(format: "language.name != nil") +//// fetchRequest.predicate = self.onlineCompoundPredicate + + let controller = NSFetchedResultsController(fetchRequest: fetchRequest, + managedObjectContext: self.managedObjectContext, + sectionNameKeyPath: "language.name", cacheName: nil) + controller.delegate = self + try? controller.performFetch() + return controller as! NSFetchedResultsController + }() } diff --git a/Kiwix-iOS/Storyboard/Library.storyboard b/Kiwix-iOS/Storyboard/Library.storyboard index 047a87cf..e442bc72 100644 --- a/Kiwix-iOS/Storyboard/Library.storyboard +++ b/Kiwix-iOS/Storyboard/Library.storyboard @@ -6,6 +6,7 @@ + @@ -44,22 +45,118 @@ - + - + - - + + - + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -144,5 +241,6 @@ + diff --git a/Kiwix-iOS/View/Cells.swift b/Kiwix-iOS/View/Cells.swift index 3e003733..4ecbcf13 100644 --- a/Kiwix-iOS/View/Cells.swift +++ b/Kiwix-iOS/View/Cells.swift @@ -101,8 +101,6 @@ class ArticleSnippetCell: ArticleCell { @IBOutlet weak var snippetLabel: UILabel! } -// MARK: - Bookmark Cell - class BookmarkCollectionCell: UICollectionViewCell { override func awakeFromNib() { clipsToBounds = false @@ -144,6 +142,35 @@ class BookmarkCollectionCell: UICollectionViewCell { } } +class LibraryCollectionCell: UICollectionViewCell { + override func awakeFromNib() { + imageView.clipsToBounds = true + imageView.layer.cornerRadius = 2.0 + hasPicLabel.layer.borderWidth = 1.5 + hasPicLabel.layer.borderColor = UIColor.orange.cgColor + hasPicLabel.layer.cornerRadius = 8.0 + } + + @IBAction func moreButtonTapped(_ sender: UIButton) { + delegate?.didTapMoreButton(cell: self) + } + + weak var delegate: LibraryCollectionCellDelegate? + @IBOutlet weak var imageView: UIImageView! + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var subtitleLabel: UILabel! + @IBOutlet weak var descriptionLabel: UILabel! + @IBOutlet weak var hasPicLabel: UILabel! +} + +protocol LibraryCollectionCellDelegate: class { + func didTapMoreButton(cell: LibraryCollectionCell) +} + +class LibraryCollectionHeader: UICollectionReusableView { + @IBOutlet weak var textLabel: UILabel! +} +