Generic bookmarks

This commit is contained in:
Chris Li 2016-09-29 16:17:18 -04:00
parent 8ab153b0e8
commit 7d11c1499a
7 changed files with 29 additions and 417 deletions

View File

@ -14,6 +14,9 @@ import DZNEmptyDataSet
class BookmarkController: UITableViewController, NSFetchedResultsControllerDelegate, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate {
var book: Book?
var isTopViewController: Bool {
return self == navigationController?.viewControllers.first
}
// MARK: - Overrides
@ -26,16 +29,26 @@ class BookmarkController: UITableViewController, NSFetchedResultsControllerDeleg
tableView.allowsMultipleSelectionDuringEditing = true
tableView.emptyDataSetSource = self
tableView.emptyDataSetDelegate = self
if isTopViewController {
navigationItem.leftBarButtonItem = UIBarButtonItem(imageNamed: "Cross", target: self, action: #selector(BookmarkController.dismissSelf))
}
}
override func setEditing(editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
navigationItem.leftBarButtonItem = editing ? UIBarButtonItem(barButtonSystemItem: .Trash) : nil
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: editing ? .Done : .Edit)
navigationItem.leftBarButtonItem?.target = self
navigationItem.leftBarButtonItem?.action = #selector(BookmarkController.trashButtonTapped(_:))
navigationItem.rightBarButtonItem?.target = self
navigationItem.rightBarButtonItem?.action = #selector(BookmarkController.editButtonTapped(_:))
switch (editing, isTopViewController) {
case (true, true), (true, false):
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Trash, target: self, action: #selector(BookmarkController.trashButtonTapped(_:)))
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: #selector(BookmarkController.editButtonTapped(_:)))
case (false, true):
navigationItem.leftBarButtonItem = UIBarButtonItem(imageNamed: "Cross", target: self, action: #selector(BookmarkController.dismissSelf))
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Edit, target: self, action: #selector(BookmarkController.editButtonTapped(_:)))
case (false, false):
navigationItem.leftBarButtonItem = nil
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Edit, target: self, action: #selector(BookmarkController.editButtonTapped(_:)))
}
}
// MARK: - Action
@ -62,6 +75,10 @@ class BookmarkController: UITableViewController, NSFetchedResultsControllerDeleg
setEditing(!editing, animated: true)
}
func dismissSelf() {
dismissViewControllerAnimated(true, completion: nil)
}
// MARK: - Empty table datasource & delegate
func imageForEmptyDataSet(scrollView: UIScrollView!) -> UIImage! {
@ -141,7 +158,6 @@ class BookmarkController: UITableViewController, NSFetchedResultsControllerDeleg
defer {dismissViewControllerAnimated(true, completion: nil)}
guard let article = fetchedResultController.objectAtIndexPath(indexPath) as? Article,
let url = article.url else {return}
trash(articles: [article])
let operation = ArticleLoadOperation(url: url)
GlobalQueue.shared.add(load: operation)

View File

@ -1,228 +0,0 @@
//
// BookmarkTBVC.swift
// Kiwix
//
// Created by Chris on 1/10/16.
// Copyright © 2016 Chris. All rights reserved.
//
import UIKit
import CoreData
import DZNEmptyDataSet
class BookmarkTBVC: UITableViewController, NSFetchedResultsControllerDelegate, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate {
override func viewDidLoad() {
super.viewDidLoad()
clearsSelectionOnViewWillAppear = true
title = LocalizedStrings.bookmarks
tableView.estimatedRowHeight = 66.0
tableView.rowHeight = UITableViewAutomaticDimension
tableView.allowsMultipleSelectionDuringEditing = true
tableView.emptyDataSetSource = self
tableView.emptyDataSetDelegate = self
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
setEditing(false, animated: false)
navigationController?.setToolbarHidden(true, animated: true)
}
func updateWidgetData() {
let operation = UpdateWidgetDataSourceOperation()
GlobalQueue.shared.addOperation(operation)
}
// MARK: - Empty table datasource & delegate
func imageForEmptyDataSet(scrollView: UIScrollView!) -> UIImage! {
return UIImage(named: "BookmarkColor")
}
func titleForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! {
let text = NSLocalizedString("Bookmarks", comment: "Bookmarks view title")
let attributes = [NSFontAttributeName: UIFont.boldSystemFontOfSize(18.0),
NSForegroundColorAttributeName: UIColor.darkGrayColor()]
return NSAttributedString(string: text, attributes: attributes)
}
func descriptionForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! {
let text = NSLocalizedString("To add a bookmark, long press the star button when reading an article", comment: "Bookmarks view message")
let style = NSMutableParagraphStyle()
style.lineBreakMode = .ByWordWrapping
style.alignment = .Center
let attributes = [NSFontAttributeName: UIFont.boldSystemFontOfSize(14.0),
NSForegroundColorAttributeName: UIColor.lightGrayColor(),
NSParagraphStyleAttributeName: style]
return NSAttributedString(string: text, attributes: attributes)
}
func spaceHeightForEmptyDataSet(scrollView: UIScrollView!) -> CGFloat {
return 30.0
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultController.sections?.count ?? 0
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let sectionInfo = fetchedResultController.sections?[section] else {return 0}
return sectionInfo.numberOfObjects
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let article = fetchedResultController.objectAtIndexPath(indexPath) as? Article
if let _ = article?.snippet {
let cell = tableView.dequeueReusableCellWithIdentifier("BookmarkSnippetCell", forIndexPath: indexPath)
configureSnippetCell(cell, atIndexPath: indexPath)
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("BookmarkCell", forIndexPath: indexPath)
configureCell(cell, atIndexPath: indexPath)
return cell
}
}
func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
guard let cell = cell as? BookmarkCell else {return}
guard let article = fetchedResultController.objectAtIndexPath(indexPath) as? Article else {return}
cell.thumbImageView.image = {
guard let data = article.thumbImageData else {return nil}
return UIImage(data: data)
}()
cell.titleLabel.text = article.title
cell.subtitleLabel.text = article.book?.title
}
func configureSnippetCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
configureCell(cell, atIndexPath: indexPath)
guard let cell = cell as? BookmarkSnippetCell else {return}
guard let article = fetchedResultController.objectAtIndexPath(indexPath) as? Article else {return}
cell.snippetLabel.text = article.snippet
}
// MARK: - Table view delegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
guard !tableView.editing else {return}
defer {dismissViewControllerAnimated(true, completion: nil)}
guard let article = fetchedResultController.objectAtIndexPath(indexPath) as? Article,
let url = article.url else {return}
let operation = ArticleLoadOperation(url: url)
GlobalQueue.shared.add(load: operation)
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {}
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let remove = UITableViewRowAction(style: .Destructive, title: LocalizedStrings.remove) { (action, indexPath) -> Void in
guard let article = self.fetchedResultController.objectAtIndexPath(indexPath) as? Article else {return}
let context = NSManagedObjectContext.mainQueueContext
context.performBlockAndWait({ () -> Void in
article.isBookmarked = false
})
self.updateWidgetData()
}
return [remove]
}
// MARK: - Fetched Result Controller Delegate
let managedObjectContext = UIApplication.appDelegate.managedObjectContext
lazy var fetchedResultController: NSFetchedResultsController = {
let fetchRequest = NSFetchRequest(entityName: "Article")
let dateDescriptor = NSSortDescriptor(key: "bookmarkDate", ascending: false)
let titleDescriptor = NSSortDescriptor(key: "title", ascending: true)
fetchRequest.sortDescriptors = [dateDescriptor, titleDescriptor]
fetchRequest.predicate = NSPredicate(format: "isBookmarked == true")
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: nil, cacheName: "BookmarksFRC" + NSBundle.appShortVersion)
fetchedResultsController.delegate = self
fetchedResultsController.performFetch(deleteCache: false)
return fetchedResultsController
}()
// MARK: - Fetched Result Controller Delegate
func controllerWillChangeContent(controller: NSFetchedResultsController) {
tableView.beginUpdates()
}
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
switch type {
case .Insert:
tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
case .Delete:
tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
default:
return
}
}
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case .Insert:
guard let newIndexPath = newIndexPath else {return}
tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
case .Delete:
guard let indexPath = indexPath else {return}
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
case .Update:
guard let indexPath = indexPath, let cell = tableView.cellForRowAtIndexPath(indexPath) else {return}
configureCell(cell, atIndexPath: indexPath)
case .Move:
guard let indexPath = indexPath, let newIndexPath = newIndexPath else {return}
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
}
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
tableView.endUpdates()
}
// MARK: - Action
@IBAction func editingButtonTapped(sender: UIBarButtonItem) {
setEditing(!editing, animated: true)
navigationController?.setToolbarHidden(!editing, animated: true)
}
@IBAction func removeBookmarkButtonTapped(sender: UIBarButtonItem) {
guard editing else {return}
guard let selectedIndexPathes = tableView.indexPathsForSelectedRows else {return}
let artiicles = selectedIndexPathes.flatMap() {fetchedResultController.objectAtIndexPath($0) as? Article}
if artiicles.count > 0 {
updateWidgetData()
}
let context = NSManagedObjectContext.mainQueueContext
context.performBlock {
artiicles.forEach() {
$0.isBookmarked = false
$0.bookmarkDate = nil
}
}
}
@IBAction func dismissButtonTapped(sender: UIBarButtonItem) {
dismissViewControllerAnimated(true, completion: nil)
}
}
extension LocalizedStrings {
class var bookmarks: String {return NSLocalizedString("Bookmarks", comment: "")}
class var bookmarkAddGuide: String {return NSLocalizedString("To add a bookmark, long press the star button when reading an article", comment: "")}
}

View File

@ -49,7 +49,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.8.1454</string>
<string>1.8.1473</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="16A323" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="CQC-Yj-yBQ">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="16A323" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="epu-ol-vd5">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
@ -8,177 +8,6 @@
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--BookmarkTBVC-->
<scene sceneID="i8i-hs-b3w">
<objects>
<tableViewController storyboardIdentifier="BookmarkTBVC" id="EOO-t3-Qii" customClass="BookmarkTBVC" customModule="Kiwix" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="Cad-DV-oVY">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="sectionIndexBackgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="BookmarkCell" rowHeight="66" id="HDv-lO-b6r" customClass="BookmarkCell" customModule="Kiwix" customModuleProvider="target">
<rect key="frame" x="0.0" y="119.5" width="375" height="66"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="HDv-lO-b6r" id="OAl-D1-ec7">
<frame key="frameInset" width="375" height="65.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="U1x-fn-tr7">
<constraints>
<constraint firstAttribute="height" constant="22" id="EYh-7Y-oG7"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aAu-zR-Dyv">
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="NmU-4J-7nK">
<constraints>
<constraint firstAttribute="width" constant="50" id="CMB-0r-Nzi"/>
<constraint firstAttribute="height" constant="50" id="glp-JE-A6V"/>
</constraints>
</imageView>
</subviews>
<constraints>
<constraint firstItem="aAu-zR-Dyv" firstAttribute="trailing" secondItem="OAl-D1-ec7" secondAttribute="trailingMargin" id="ASW-qE-BKY"/>
<constraint firstItem="U1x-fn-tr7" firstAttribute="leading" secondItem="OAl-D1-ec7" secondAttribute="leadingMargin" constant="58" id="Q2t-Qj-2p6"/>
<constraint firstItem="U1x-fn-tr7" firstAttribute="leading" secondItem="NmU-4J-7nK" secondAttribute="trailing" constant="8" id="YPu-Lb-iqi"/>
<constraint firstAttribute="bottomMargin" secondItem="aAu-zR-Dyv" secondAttribute="bottom" constant="2" id="Z8A-en-1vc"/>
<constraint firstItem="NmU-4J-7nK" firstAttribute="centerY" secondItem="OAl-D1-ec7" secondAttribute="centerY" id="ZK3-DD-4zy"/>
<constraint firstItem="U1x-fn-tr7" firstAttribute="trailing" secondItem="OAl-D1-ec7" secondAttribute="trailingMargin" id="ezr-0B-NeS"/>
<constraint firstItem="U1x-fn-tr7" firstAttribute="top" secondItem="OAl-D1-ec7" secondAttribute="topMargin" constant="2" id="i42-zE-aO6"/>
<constraint firstItem="aAu-zR-Dyv" firstAttribute="leading" secondItem="OAl-D1-ec7" secondAttribute="leadingMargin" constant="58" id="lIM-RO-d3O"/>
<constraint firstItem="aAu-zR-Dyv" firstAttribute="top" secondItem="U1x-fn-tr7" secondAttribute="bottom" constant="4" id="n7b-tr-1HP"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="subtitleLabel" destination="aAu-zR-Dyv" id="mi9-sm-cvx"/>
<outlet property="thumbImageView" destination="NmU-4J-7nK" id="eAX-4T-LOl"/>
<outlet property="titleLabel" destination="U1x-fn-tr7" id="EfA-a3-qhv"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="BookmarkSnippetCell" rowHeight="149" id="o5A-Xv-pf5" customClass="BookmarkSnippetCell" customModule="Kiwix" customModuleProvider="target">
<rect key="frame" x="0.0" y="185.5" width="375" height="149"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="o5A-Xv-pf5" id="KOC-sh-r2Q">
<frame key="frameInset" width="375" height="148.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Iw0-U5-FqV">
<constraints>
<constraint firstAttribute="height" constant="22" id="KCw-oa-mJL"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="V1Z-5u-ZFY">
<constraints>
<constraint firstAttribute="height" constant="19.5" id="Afp-Lh-Fdw"/>
</constraints>
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="gpH-Ig-sQv">
<constraints>
<constraint firstAttribute="width" constant="50" id="gH6-fM-fDz"/>
<constraint firstAttribute="height" constant="50" id="kcR-a8-RAR"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="justified" lineBreakMode="tailTruncation" numberOfLines="4" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7Cx-8r-nyy">
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption2"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="Iw0-U5-FqV" firstAttribute="leading" secondItem="KOC-sh-r2Q" secondAttribute="leadingMargin" constant="58" id="39Y-P9-vWW"/>
<constraint firstItem="7Cx-8r-nyy" firstAttribute="bottom" secondItem="KOC-sh-r2Q" secondAttribute="bottomMargin" id="E4h-0E-C3u"/>
<constraint firstItem="Iw0-U5-FqV" firstAttribute="trailing" secondItem="KOC-sh-r2Q" secondAttribute="trailingMargin" id="GPf-QW-QaX"/>
<constraint firstItem="7Cx-8r-nyy" firstAttribute="trailing" secondItem="KOC-sh-r2Q" secondAttribute="trailingMargin" id="OOc-05-0bc"/>
<constraint firstItem="gpH-Ig-sQv" firstAttribute="centerY" secondItem="KOC-sh-r2Q" secondAttribute="centerY" id="QiT-l5-ZVT"/>
<constraint firstItem="V1Z-5u-ZFY" firstAttribute="leading" secondItem="KOC-sh-r2Q" secondAttribute="leadingMargin" constant="58" id="XeK-HP-8f6"/>
<constraint firstItem="V1Z-5u-ZFY" firstAttribute="trailing" secondItem="KOC-sh-r2Q" secondAttribute="trailingMargin" id="ZSg-mU-O22"/>
<constraint firstAttribute="leadingMargin" secondItem="7Cx-8r-nyy" secondAttribute="leading" id="bbW-Pj-58I"/>
<constraint firstAttribute="topMargin" secondItem="gpH-Ig-sQv" secondAttribute="top" id="haD-cC-DNC"/>
<constraint firstItem="7Cx-8r-nyy" firstAttribute="top" secondItem="V1Z-5u-ZFY" secondAttribute="bottom" constant="10.5" id="j7f-8q-Nbg"/>
<constraint firstItem="V1Z-5u-ZFY" firstAttribute="top" secondItem="Iw0-U5-FqV" secondAttribute="bottom" constant="4" id="jU9-hy-tXJ"/>
<constraint firstItem="Iw0-U5-FqV" firstAttribute="leading" secondItem="gpH-Ig-sQv" secondAttribute="trailing" constant="8" id="k3s-1a-rdN"/>
<constraint firstItem="Iw0-U5-FqV" firstAttribute="top" secondItem="KOC-sh-r2Q" secondAttribute="topMargin" constant="2" id="zXo-gw-Gf1"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="QiT-l5-ZVT"/>
</mask>
</variation>
</tableViewCellContentView>
<connections>
<outlet property="snippetLabel" destination="7Cx-8r-nyy" id="BqO-aq-yel"/>
<outlet property="subtitleLabel" destination="V1Z-5u-ZFY" id="qpd-mB-abg"/>
<outlet property="thumbImageView" destination="gpH-Ig-sQv" id="nDY-7e-2rA"/>
<outlet property="titleLabel" destination="Iw0-U5-FqV" id="AKn-XL-dHz"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="EOO-t3-Qii" id="Lzl-Ub-vud"/>
<outlet property="delegate" destination="EOO-t3-Qii" id="GE5-qw-MBw"/>
</connections>
</tableView>
<toolbarItems>
<barButtonItem style="plain" systemItem="flexibleSpace" id="tZP-Up-9rY"/>
<barButtonItem image="StarRemoved" id="Rkc-aK-Y9L">
<connections>
<action selector="removeBookmarkButtonTapped:" destination="EOO-t3-Qii" id="j1W-eN-qKg"/>
</connections>
</barButtonItem>
</toolbarItems>
<navigationItem key="navigationItem" id="a2U-AV-M0y">
<barButtonItem key="leftBarButtonItem" image="DownArrow" id="66s-uf-eDs">
<connections>
<action selector="dismissButtonTapped:" destination="EOO-t3-Qii" id="3YA-A5-eSo"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" systemItem="edit" id="tTL-c1-xab">
<connections>
<action selector="editingButtonTapped:" destination="EOO-t3-Qii" id="Ebm-dR-YbU"/>
</connections>
</barButtonItem>
</navigationItem>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="b4G-fm-Sda" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2791.1999999999998" y="1136.5817091454273"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="QEZ-t8-ULC">
<objects>
<navigationController storyboardIdentifier="BookmarkNav" automaticallyAdjustsScrollViewInsets="NO" toolbarHidden="NO" id="CQC-Yj-yBQ" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="CXJ-5N-R8L">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="Yeq-LG-i5F">
<rect key="frame" x="0.0" y="623" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</toolbar>
<connections>
<segue destination="EOO-t3-Qii" kind="relationship" relationship="rootViewController" id="Uo9-Ji-muW"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ls9-CP-THB" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1099" y="1137"/>
</scene>
<!--Bookmark Controller-->
<scene sceneID="SVz-ni-k6U">
<objects>
@ -315,7 +144,7 @@
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="kQh-IS-Ttn" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2676" y="1787"/>
<point key="canvasLocation" x="2402" y="1764"/>
</scene>
<!--BookmarkHUD-->
<scene sceneID="eMu-pk-jX5">
@ -425,7 +254,7 @@
</connections>
</tapGestureRecognizer>
</objects>
<point key="canvasLocation" x="3543.1999999999998" y="1136.5817091454273"/>
<point key="canvasLocation" x="3380" y="1764"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="pBB-bl-wh0">
@ -449,7 +278,5 @@
<resources>
<image name="BookmarkAdded" width="21" height="21"/>
<image name="BookmarkRemoved" width="21" height="21"/>
<image name="DownArrow" width="21" height="21"/>
<image name="StarRemoved" width="21" height="21"/>
</resources>
</document>

View File

@ -21,7 +21,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.8.1458</string>
<string>1.8.1477</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionMainStoryboard</key>

View File

@ -26,7 +26,6 @@
971A10301D022AD5007FC62C /* LTBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A10281D022AD5007FC62C /* LTBarButtonItem.swift */; };
971A10311D022AD5007FC62C /* RefreshHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A10291D022AD5007FC62C /* RefreshHUD.swift */; };
971A10321D022AD5007FC62C /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A102A1D022AD5007FC62C /* SearchBar.swift */; };
971A10341D022AEC007FC62C /* BookmarkTBVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A10331D022AEC007FC62C /* BookmarkTBVC.swift */; };
971A10381D022C15007FC62C /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A10371D022C15007FC62C /* WebViewController.swift */; };
971A103B1D022C2C007FC62C /* AdjustLayoutTBVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A10391D022C2C007FC62C /* AdjustLayoutTBVC.swift */; };
971A103C1D022C2C007FC62C /* FontSizeTBVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971A103A1D022C2C007FC62C /* FontSizeTBVC.swift */; };
@ -237,7 +236,6 @@
971A10281D022AD5007FC62C /* LTBarButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTBarButtonItem.swift; sourceTree = "<group>"; };
971A10291D022AD5007FC62C /* RefreshHUD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshHUD.swift; sourceTree = "<group>"; };
971A102A1D022AD5007FC62C /* SearchBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = "<group>"; };
971A10331D022AEC007FC62C /* BookmarkTBVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BookmarkTBVC.swift; path = "Kiwix-iOS/Controller/BookmarkTBVC.swift"; sourceTree = SOURCE_ROOT; };
971A10371D022C15007FC62C /* WebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebViewController.swift; path = "Kiwix-iOS/Controller/WebViewController.swift"; sourceTree = SOURCE_ROOT; };
971A10391D022C2C007FC62C /* AdjustLayoutTBVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AdjustLayoutTBVC.swift; path = "Kiwix-iOS/Controller/AdjustLayoutTBVC.swift"; sourceTree = SOURCE_ROOT; };
971A103A1D022C2C007FC62C /* FontSizeTBVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FontSizeTBVC.swift; path = "Kiwix-iOS/Controller/FontSizeTBVC.swift"; sourceTree = SOURCE_ROOT; };
@ -690,7 +688,6 @@
9749A1B21C430653000F2D1E /* Bookmark */ = {
isa = PBXGroup;
children = (
971A10331D022AEC007FC62C /* BookmarkTBVC.swift */,
97C5BD4A1D9AF4B5009692CF /* BookmarkController.swift */,
97219DBC1D383A00009FDFF1 /* BookmarkHUD.swift */,
);
@ -1570,7 +1567,6 @@
971A103B1D022C2C007FC62C /* AdjustLayoutTBVC.swift in Sources */,
97219DBD1D383A00009FDFF1 /* BookmarkHUD.swift in Sources */,
97D6812E1D6F70DE00E5FA99 /* Kiwix.xcdatamodeld in Sources */,
971A10341D022AEC007FC62C /* BookmarkTBVC.swift in Sources */,
97A1FD1D1D6F71D800A80EE2 /* URLResponseCache.swift in Sources */,
9764F5971D8339D500E0B1C4 /* JSInjection.swift in Sources */,
9787BC211D9318300030D311 /* WelcomeController.swift in Sources */,

View File

@ -51,6 +51,7 @@ extension String {
class LocalizedStrings {
static let download = NSLocalizedString("Download", comment: "Common")
static let bookmarks = NSLocalizedString("Bookmarks", comment: "Common")
class Library {
static let spaceNotEnough = NSLocalizedString("Space Not Enough", comment: "Library")