mirror of
https://github.com/kiwix/kiwix-apple.git
synced 2025-09-24 04:03:03 -04:00
A working today widget prototype
This commit is contained in:
parent
88639f7c28
commit
dbf9f5dc42
10
Articles.entitlements
Normal file
10
Articles.entitlements
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.kiwix</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
@ -35,6 +35,11 @@ class BookmarkTBVC: UITableViewController, NSFetchedResultsControllerDelegate, D
|
||||
navigationController?.setToolbarHidden(!editing, animated: animated)
|
||||
}
|
||||
|
||||
func updateWidgetData() {
|
||||
let operation = UpdateWidgetDataSourceOperation()
|
||||
GlobalOperationQueue.sharedInstance.addOperation(operation)
|
||||
}
|
||||
|
||||
// MARK: - Empty table datasource & delegate
|
||||
|
||||
func imageForEmptyDataSet(scrollView: UIScrollView!) -> UIImage! {
|
||||
@ -92,16 +97,8 @@ class BookmarkTBVC: UITableViewController, NSFetchedResultsControllerDelegate, D
|
||||
guard let article = fetchedResultController.objectAtIndexPath(indexPath) as? Article else {return}
|
||||
|
||||
cell.thumbImageView.image = {
|
||||
if let urlString = article.thumbImageURL,
|
||||
let url = NSURL(string: urlString),
|
||||
let data = NSData(contentsOfURL: url),
|
||||
let image = UIImage(data: data) {
|
||||
return image
|
||||
} else if let bookFavIconImageData = article.book?.favIcon {
|
||||
return UIImage(data: bookFavIconImageData)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
guard let data = article.thumbImageData else {return nil}
|
||||
return UIImage(data: data)
|
||||
}()
|
||||
cell.titleLabel.text = article.title
|
||||
cell.subtitleLabel.text = article.book?.title
|
||||
@ -135,6 +132,7 @@ class BookmarkTBVC: UITableViewController, NSFetchedResultsControllerDelegate, D
|
||||
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}
|
||||
self.updateWidgetData()
|
||||
let context = NSManagedObjectContext.mainQueueContext
|
||||
context.performBlockAndWait({ () -> Void in
|
||||
context.deleteObject(article)
|
||||
@ -208,6 +206,11 @@ class BookmarkTBVC: UITableViewController, NSFetchedResultsControllerDelegate, D
|
||||
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() {
|
||||
|
@ -29,6 +29,9 @@ extension MainController: LPTBarButtonItemDelegate, TableOfContentsDelegate, Zim
|
||||
if article.isBookmarked {article.bookmarkDate = NSDate()}
|
||||
if article.snippet == nil {article.snippet = getSnippet(webView)}
|
||||
|
||||
let operation = UpdateWidgetDataSourceOperation()
|
||||
GlobalOperationQueue.sharedInstance.addOperation(operation)
|
||||
|
||||
guard let controller = bookmarkController ?? UIStoryboard.main.initViewController("BookmarkController", type: BookmarkController.self) else {return}
|
||||
bookmarkController = controller
|
||||
controller.bookmarkAdded = article.isBookmarked
|
||||
|
@ -36,7 +36,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.7.352</string>
|
||||
<string>1.7.448</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
10
Kiwix-iOS/Kiwix.entitlements
Normal file
10
Kiwix-iOS/Kiwix.entitlements
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.kiwix</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
@ -3,6 +3,7 @@
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Today View Controller-->
|
||||
@ -14,15 +15,85 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="FKl-LY-JtV"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" simulatedAppContext="notificationCenter" id="S3S-Oj-5AN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="37"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="rGU-qY-GzL">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="100"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="elH-Eg-whL">
|
||||
<size key="itemSize" width="64" height="92"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
</collectionViewFlowLayout>
|
||||
<cells>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="BookmarkWidgetCell" id="shV-TG-J6y" customClass="BookmarkWidgetCell" customModule="Articles" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="64" height="92"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="64" height="92"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oCt-Oa-l7V">
|
||||
<rect key="frame" x="0.0" y="0.0" width="64" height="64"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="oCt-Oa-l7V" secondAttribute="height" multiplier="1:1" id="mTX-gY-AnP"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="5ff-qy-Hgj">
|
||||
<rect key="frame" x="2" y="2" width="60" height="60"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="5ff-qy-Hgj" secondAttribute="height" multiplier="1:1" id="xey-BP-NuA"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cpM-fR-Nl4">
|
||||
<rect key="frame" x="0.0" y="66" width="64" height="12"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="10"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="lightTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstItem="oCt-Oa-l7V" firstAttribute="leading" secondItem="shV-TG-J6y" secondAttribute="leading" id="3Iz-Ch-1ub"/>
|
||||
<constraint firstAttribute="trailing" secondItem="oCt-Oa-l7V" secondAttribute="trailing" id="4th-dr-nsA"/>
|
||||
<constraint firstItem="cpM-fR-Nl4" firstAttribute="leading" secondItem="shV-TG-J6y" secondAttribute="leading" id="R3a-Ik-dTO"/>
|
||||
<constraint firstItem="oCt-Oa-l7V" firstAttribute="top" secondItem="shV-TG-J6y" secondAttribute="top" id="fJC-Sd-n9A"/>
|
||||
<constraint firstItem="5ff-qy-Hgj" firstAttribute="top" secondItem="shV-TG-J6y" secondAttribute="top" constant="2" id="gyY-t5-3oU"/>
|
||||
<constraint firstAttribute="trailing" secondItem="5ff-qy-Hgj" secondAttribute="trailing" constant="2" id="n7k-4X-SYx"/>
|
||||
<constraint firstItem="cpM-fR-Nl4" firstAttribute="top" secondItem="oCt-Oa-l7V" secondAttribute="bottom" constant="2" id="pYC-H9-NbT"/>
|
||||
<constraint firstAttribute="trailing" secondItem="cpM-fR-Nl4" secondAttribute="trailing" id="rRQ-AL-9dU"/>
|
||||
<constraint firstItem="5ff-qy-Hgj" firstAttribute="leading" secondItem="shV-TG-J6y" secondAttribute="leading" constant="2" id="spE-wK-Obf"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="64" height="92"/>
|
||||
<connections>
|
||||
<outlet property="imageBackgroundView" destination="oCt-Oa-l7V" id="0EK-gh-2yQ"/>
|
||||
<outlet property="imageView" destination="5ff-qy-Hgj" id="P92-ze-loY"/>
|
||||
<outlet property="label" destination="cpM-fR-Nl4" id="jQp-Vs-HaK"/>
|
||||
</connections>
|
||||
</collectionViewCell>
|
||||
</cells>
|
||||
</collectionView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="FKl-LY-JtV" firstAttribute="top" secondItem="rGU-qY-GzL" secondAttribute="bottom" id="0DU-Xd-zt9"/>
|
||||
<constraint firstItem="rGU-qY-GzL" firstAttribute="leading" secondItem="S3S-Oj-5AN" secondAttribute="leading" id="76F-49-Fzg"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rGU-qY-GzL" secondAttribute="trailing" id="CEt-21-7VZ"/>
|
||||
<constraint firstItem="rGU-qY-GzL" firstAttribute="top" secondItem="Ft6-oW-KC0" secondAttribute="bottom" id="TFg-Zd-dq7"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<extendedEdge key="edgesForExtendedLayout"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<size key="freeformSize" width="320" height="37"/>
|
||||
<size key="freeformSize" width="320" height="100"/>
|
||||
<connections>
|
||||
<outlet property="collectionView" destination="rGU-qY-GzL" id="lfU-S6-XrK"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="vXp-U4-Rya" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
|
22
Kiwix-iOSWidgets/Articles/BookmarkWidgetCell.swift
Normal file
22
Kiwix-iOSWidgets/Articles/BookmarkWidgetCell.swift
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// BookmarkWidgetCell.swift
|
||||
// Kiwix
|
||||
//
|
||||
// Created by Chris Li on 7/20/16.
|
||||
// Copyright © 2016 Chris. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class BookmarkWidgetCell: UICollectionViewCell {
|
||||
override func awakeFromNib() {
|
||||
imageView.layer.masksToBounds = true
|
||||
imageView.layer.cornerRadius = 4.0
|
||||
imageBackgroundView.layer.masksToBounds = true
|
||||
imageBackgroundView.layer.cornerRadius = 6.0
|
||||
}
|
||||
|
||||
@IBOutlet weak var imageView: UIImageView!
|
||||
@IBOutlet weak var imageBackgroundView: UIView!
|
||||
@IBOutlet weak var label: UILabel!
|
||||
}
|
@ -9,17 +9,39 @@
|
||||
import UIKit
|
||||
import NotificationCenter
|
||||
|
||||
class TodayViewController: UIViewController, NCWidgetProviding {
|
||||
class TodayViewController: UIViewController, NCWidgetProviding, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
|
||||
|
||||
@IBOutlet weak var collectionView: UICollectionView!
|
||||
|
||||
private var rowHeight: CGFloat = 110.0
|
||||
private let hSpacing: CGFloat = 15.0
|
||||
private var titles = [String]()
|
||||
private var thumbDatas = [NSData]()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view from its nib.
|
||||
collectionView.dataSource = self
|
||||
collectionView.delegate = self
|
||||
preferredContentSize = CGSizeMake(0, rowHeight)
|
||||
updateData()
|
||||
}
|
||||
|
||||
override func viewWillAppear(animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
updateData()
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
super.didReceiveMemoryWarning()
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NCWidgetProviding
|
||||
|
||||
func widgetMarginInsetsForProposedMarginInsets(defaultMarginInsets: UIEdgeInsets) -> UIEdgeInsets {
|
||||
return UIEdgeInsetsZero
|
||||
}
|
||||
|
||||
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) {
|
||||
// Perform any setup necessary in order to update the view.
|
||||
@ -28,7 +50,56 @@ class TodayViewController: UIViewController, NCWidgetProviding {
|
||||
// If there's no update required, use NCUpdateResult.NoData
|
||||
// If there's an update, use NCUpdateResult.NewData
|
||||
|
||||
updateData()
|
||||
|
||||
completionHandler(NCUpdateResult.NewData)
|
||||
}
|
||||
|
||||
func updateData() {
|
||||
let defaults = NSUserDefaults(suiteName: "group.kiwix")
|
||||
guard let bookmarks = defaults?.objectForKey("bookmarks") as? [String: NSArray],
|
||||
let titles = bookmarks["titles"] as? [String],
|
||||
let thumbDatas = bookmarks["thumbDatas"] as? [NSData] else {return}
|
||||
self.titles = titles
|
||||
self.thumbDatas = thumbDatas
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
||||
// MARK: - UICollectionView
|
||||
|
||||
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return titles.count
|
||||
}
|
||||
|
||||
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("BookmarkWidgetCell", forIndexPath: indexPath)
|
||||
configureCell(cell, atIndexPath: indexPath)
|
||||
return cell
|
||||
}
|
||||
|
||||
func configureCell(cell: UICollectionViewCell, atIndexPath indexPath: NSIndexPath) {
|
||||
guard let cell = cell as? BookmarkWidgetCell else {return}
|
||||
cell.label.text = titles[indexPath.item]
|
||||
cell.imageView.image = UIImage(data: thumbDatas[indexPath.item])
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDelegateFlowLayout
|
||||
|
||||
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
|
||||
let sectionInset = self.collectionView(collectionView, layout: collectionViewLayout, insetForSectionAtIndex: indexPath.section)
|
||||
let itemWidth = (collectionView.frame.width - 6 * hSpacing) / 5.0
|
||||
return CGSizeMake(itemWidth, rowHeight - sectionInset.top - sectionInset.bottom)
|
||||
}
|
||||
|
||||
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
|
||||
return UIEdgeInsetsMake(10, hSpacing, 10, hSpacing)
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,10 @@
|
||||
971A107F1D022F74007FC62C /* ImportBookLearnMore.html in Resources */ = {isa = PBXBuildFile; fileRef = 971A107B1D022F74007FC62C /* ImportBookLearnMore.html */; };
|
||||
971A10801D022F74007FC62C /* Pic_I.png in Resources */ = {isa = PBXBuildFile; fileRef = 971A107C1D022F74007FC62C /* Pic_I.png */; };
|
||||
971A10811D022F74007FC62C /* Pic_P.png in Resources */ = {isa = PBXBuildFile; fileRef = 971A107D1D022F74007FC62C /* Pic_P.png */; };
|
||||
971C4F0E1D400F010027B7D2 /* UpdateWidgetDataSourceOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971C4F0D1D400F010027B7D2 /* UpdateWidgetDataSourceOperation.swift */; };
|
||||
971C4F121D4020E90027B7D2 /* BookmarkWidgetCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971C4F111D4020E90027B7D2 /* BookmarkWidgetCell.swift */; };
|
||||
971C4F141D411DC00027B7D2 /* ArticleDataContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971C4F131D411DC00027B7D2 /* ArticleDataContainer.swift */; };
|
||||
971C4F151D411DC00027B7D2 /* ArticleDataContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971C4F131D411DC00027B7D2 /* ArticleDataContainer.swift */; };
|
||||
97219DBD1D383A00009FDFF1 /* BookmarkController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97219DBC1D383A00009FDFF1 /* BookmarkController.swift */; };
|
||||
9722121C1D3ECCFE00C0DCF2 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E609F01D103DED00EBCB9D /* NotificationCenter.framework */; };
|
||||
9722121F1D3ECCFE00C0DCF2 /* TodayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9722121E1D3ECCFE00C0DCF2 /* TodayViewController.swift */; };
|
||||
@ -335,6 +339,11 @@
|
||||
971A107B1D022F74007FC62C /* ImportBookLearnMore.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = ImportBookLearnMore.html; path = Kiwix/HelpDocuments/ImportBookLearnMore.html; sourceTree = SOURCE_ROOT; };
|
||||
971A107C1D022F74007FC62C /* Pic_I.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Pic_I.png; path = Kiwix/HelpDocuments/Pic_I.png; sourceTree = SOURCE_ROOT; };
|
||||
971A107D1D022F74007FC62C /* Pic_P.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Pic_P.png; path = Kiwix/HelpDocuments/Pic_P.png; sourceTree = SOURCE_ROOT; };
|
||||
971C4F0B1D3FFFA60027B7D2 /* Kiwix.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = Kiwix.entitlements; path = "Kiwix-iOS/Kiwix.entitlements"; sourceTree = SOURCE_ROOT; };
|
||||
971C4F0C1D3FFFFF0027B7D2 /* Articles.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = Articles.entitlements; path = ../../Articles.entitlements; sourceTree = "<group>"; };
|
||||
971C4F0D1D400F010027B7D2 /* UpdateWidgetDataSourceOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UpdateWidgetDataSourceOperation.swift; path = Operations/UpdateWidgetDataSourceOperation.swift; sourceTree = "<group>"; };
|
||||
971C4F111D4020E90027B7D2 /* BookmarkWidgetCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkWidgetCell.swift; sourceTree = "<group>"; };
|
||||
971C4F131D411DC00027B7D2 /* ArticleDataContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ArticleDataContainer.swift; path = Kiwix/Tools/ArticleDataContainer.swift; sourceTree = "<group>"; };
|
||||
97219DBC1D383A00009FDFF1 /* BookmarkController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BookmarkController.swift; path = "Kiwix-iOS/Controller/Bookmark/BookmarkController.swift"; sourceTree = SOURCE_ROOT; };
|
||||
9722121B1D3ECCFE00C0DCF2 /* Articles.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Articles.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9722121E1D3ECCFE00C0DCF2 /* TodayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayViewController.swift; sourceTree = "<group>"; };
|
||||
@ -718,8 +727,10 @@
|
||||
9722121D1D3ECCFE00C0DCF2 /* Articles */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9722121E1D3ECCFE00C0DCF2 /* TodayViewController.swift */,
|
||||
971C4F0C1D3FFFFF0027B7D2 /* Articles.entitlements */,
|
||||
972212201D3ECCFE00C0DCF2 /* MainInterface.storyboard */,
|
||||
9722121E1D3ECCFE00C0DCF2 /* TodayViewController.swift */,
|
||||
971C4F111D4020E90027B7D2 /* BookmarkWidgetCell.swift */,
|
||||
972212231D3ECCFE00C0DCF2 /* Info.plist */,
|
||||
);
|
||||
path = Articles;
|
||||
@ -813,6 +824,7 @@
|
||||
97E891681CA976E90001CA32 /* FileManager.swift */,
|
||||
973C8D5B1C25F945007272F9 /* Preference.swift */,
|
||||
979C51511CECA9AF001707F2 /* StringTools.swift */,
|
||||
971C4F131D411DC00027B7D2 /* ArticleDataContainer.swift */,
|
||||
);
|
||||
name = Tools;
|
||||
sourceTree = "<group>";
|
||||
@ -912,6 +924,7 @@
|
||||
978C58791C1CCC920077AE47 /* Supporting */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
971C4F0B1D3FFFA60027B7D2 /* Kiwix.entitlements */,
|
||||
971A10791D022F05007FC62C /* Localizable.stringsdict */,
|
||||
971A10191D0228E8007FC62C /* JavaScripts */,
|
||||
975227CF1D022814001D1DDE /* LaunchScreen.storyboard */,
|
||||
@ -1093,6 +1106,7 @@
|
||||
9779A1C51D34225E0071EFAB /* RefreshLibraryOperation.swift */,
|
||||
973DD4241D344558009D45DB /* ScanLocalBookOperation.swift */,
|
||||
9779A1C61D34225E0071EFAB /* SearchOperation.swift */,
|
||||
971C4F0D1D400F010027B7D2 /* UpdateWidgetDataSourceOperation.swift */,
|
||||
970C61961D34243600087758 /* URLSessionDownloadTaskOperation.swift */,
|
||||
);
|
||||
name = Operation;
|
||||
@ -1279,6 +1293,11 @@
|
||||
9722121A1D3ECCFE00C0DCF2 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
DevelopmentTeam = L7HWM3SP3L;
|
||||
SystemCapabilities = {
|
||||
com.apple.ApplicationGroups.iOS = {
|
||||
enabled = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
973BCCE81CEB3FA400F10B44 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
@ -1295,6 +1314,9 @@
|
||||
CreatedOnToolsVersion = 7.2;
|
||||
DevelopmentTeam = L7HWM3SP3L;
|
||||
SystemCapabilities = {
|
||||
com.apple.ApplicationGroups.iOS = {
|
||||
enabled = 1;
|
||||
};
|
||||
com.apple.BackgroundModes = {
|
||||
enabled = 0;
|
||||
};
|
||||
@ -1535,7 +1557,9 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
971C4F121D4020E90027B7D2 /* BookmarkWidgetCell.swift in Sources */,
|
||||
9722121F1D3ECCFE00C0DCF2 /* TodayViewController.swift in Sources */,
|
||||
971C4F151D411DC00027B7D2 /* ArticleDataContainer.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1626,6 +1650,7 @@
|
||||
9779A1CC1D34225E0071EFAB /* SearchOperation.swift in Sources */,
|
||||
97BAA8EC1D3D2D7B0038F57F /* PacketAnalyzer.swift in Sources */,
|
||||
970E68BA1D3809A3001E8514 /* MainController.swift in Sources */,
|
||||
971C4F141D411DC00027B7D2 /* ArticleDataContainer.swift in Sources */,
|
||||
970C65501D398D5A007032F8 /* BookmarkControllerAnimator.swift in Sources */,
|
||||
978C58981C1CD86E0077AE47 /* Book.swift in Sources */,
|
||||
978C58961C1CD86E0077AE47 /* Language.swift in Sources */,
|
||||
@ -1662,6 +1687,7 @@
|
||||
9779A1C81D34225E0071EFAB /* AlertOperation.swift in Sources */,
|
||||
971A104B1D022CBE007FC62C /* SearchBooksVC.swift in Sources */,
|
||||
977998771C1E0B7900B1DD5E /* Article+CoreDataProperties.swift in Sources */,
|
||||
971C4F0E1D400F010027B7D2 /* UpdateWidgetDataSourceOperation.swift in Sources */,
|
||||
971187301CEB50FC00B9909D /* ZimReader.mm in Sources */,
|
||||
971A103C1D022C2C007FC62C /* FontSizeTBVC.swift in Sources */,
|
||||
971A103B1D022C2C007FC62C /* AdjustLayoutTBVC.swift in Sources */,
|
||||
@ -1757,6 +1783,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Articles.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
INFOPLIST_FILE = "Kiwix-iOSWidgets/Articles/Info.plist";
|
||||
@ -1772,6 +1799,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Articles.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
INFOPLIST_FILE = "Kiwix-iOSWidgets/Articles/Info.plist";
|
||||
@ -2002,6 +2030,7 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "Kiwix-iOS/Kiwix.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
@ -2036,6 +2065,7 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "Kiwix-iOS/Kiwix.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
|
@ -65,7 +65,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "1"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
|
@ -1,108 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
wasCreatedForAppExtension = "YES"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97E609EE1D103DED00EBCB9D"
|
||||
BuildableName = "Kiwix-iOSWidget.appex"
|
||||
BlueprintName = "Kiwix-iOSWidget"
|
||||
ReferencedContainer = "container:Kiwix.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97A2AB871C1B80FF00052E74"
|
||||
BuildableName = "Kiwix.app"
|
||||
BlueprintName = "Kiwix-iOS"
|
||||
ReferencedContainer = "container:Kiwix.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97E609EE1D103DED00EBCB9D"
|
||||
BuildableName = "Kiwix-iOSWidget.appex"
|
||||
BlueprintName = "Kiwix-iOSWidget"
|
||||
ReferencedContainer = "container:Kiwix.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = ""
|
||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97A2AB871C1B80FF00052E74"
|
||||
BuildableName = "Kiwix.app"
|
||||
BlueprintName = "Kiwix-iOS"
|
||||
ReferencedContainer = "container:Kiwix.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97A2AB871C1B80FF00052E74"
|
||||
BuildableName = "Kiwix.app"
|
||||
BlueprintName = "Kiwix-iOS"
|
||||
ReferencedContainer = "container:Kiwix.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
@ -19,11 +19,6 @@
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>Kiwix-iOSWidget.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>8</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
|
@ -24,9 +24,31 @@ class Article: NSManagedObject {
|
||||
return article
|
||||
}
|
||||
|
||||
class func fetchRecentFiveBookmarks(context: NSManagedObjectContext) -> [Article] {
|
||||
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")
|
||||
fetchRequest.fetchLimit = 5
|
||||
return fetch(fetchRequest, type: Article.self, context: context) ?? [Article]()
|
||||
}
|
||||
|
||||
// MARK: - Helper
|
||||
|
||||
var url: NSURL? {
|
||||
guard let urlString = urlString else {return nil}
|
||||
return NSURL(string: urlString)
|
||||
}
|
||||
|
||||
var thumbImageData: NSData? {
|
||||
if let urlString = thumbImageURL,
|
||||
let url = NSURL(string: urlString),
|
||||
let data = NSData(contentsOfURL: url) {
|
||||
return data
|
||||
} else {
|
||||
return book?.favIcon
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
44
Kiwix/Operations/UpdateWidgetDataSourceOperation.swift
Normal file
44
Kiwix/Operations/UpdateWidgetDataSourceOperation.swift
Normal file
@ -0,0 +1,44 @@
|
||||
//
|
||||
// UpdateWidgetDataSourceOperation.swift
|
||||
// Kiwix
|
||||
//
|
||||
// Created by Chris Li on 7/20/16.
|
||||
// Copyright © 2016 Chris. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
import PSOperations
|
||||
|
||||
class UpdateWidgetDataSourceOperation: Operation {
|
||||
let context: NSManagedObjectContext
|
||||
|
||||
override init() {
|
||||
self.context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
|
||||
context.parentContext = NSManagedObjectContext.mainQueueContext
|
||||
context.mergePolicy = NSOverwriteMergePolicy
|
||||
super.init()
|
||||
name = String(self)
|
||||
}
|
||||
|
||||
override func execute() {
|
||||
let defaults = NSUserDefaults(suiteName: "group.kiwix")
|
||||
|
||||
var articles = [Article]()
|
||||
context.performBlockAndWait {
|
||||
articles = Article.fetchRecentFiveBookmarks(self.context)
|
||||
}
|
||||
|
||||
var titles = [String]()
|
||||
var thumbDatas = [NSData]()
|
||||
for article in articles {
|
||||
guard let title = article.title,
|
||||
let data = article.thumbImageData else {continue}
|
||||
titles.append(title)
|
||||
thumbDatas.append(data)
|
||||
}
|
||||
let bookmarks = ["titles": titles, "thumbDatas": thumbDatas]
|
||||
defaults?.setObject(bookmarks, forKey: "bookmarks")
|
||||
|
||||
finish()
|
||||
}
|
||||
}
|
31
Kiwix/Tools/ArticleDataContainer.swift
Normal file
31
Kiwix/Tools/ArticleDataContainer.swift
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// ArticleDataContainer.swift
|
||||
// Kiwix
|
||||
//
|
||||
// Created by Chris Li on 7/21/16.
|
||||
// Copyright © 2016 Chris. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class ArticleDataContainer: NSObject, NSCoding {
|
||||
let title: String
|
||||
let thumbImageData: NSData
|
||||
|
||||
init(title: String, thumbImageData: NSData) {
|
||||
self.title = title
|
||||
self.thumbImageData = thumbImageData
|
||||
}
|
||||
|
||||
required convenience init?(coder aDecoder: NSCoder) {
|
||||
guard let title = aDecoder.decodeObjectForKey("title") as? String,
|
||||
let thumbImageData = aDecoder.decodeObjectForKey("thumbImageData") as? NSData else {return nil}
|
||||
self.init(title: title, thumbImageData: thumbImageData)
|
||||
}
|
||||
|
||||
func encodeWithCoder(aCoder: NSCoder) {
|
||||
aCoder.encodeObject(title, forKey: "title")
|
||||
aCoder.encodeObject(thumbImageData, forKey: "thumbImageData")
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user