A working today widget prototype

This commit is contained in:
Chris Li 2016-07-21 15:20:08 -04:00
parent 88639f7c28
commit dbf9f5dc42
15 changed files with 334 additions and 130 deletions

10
Articles.entitlements Normal file
View 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>

View File

@ -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() {

View File

@ -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

View File

@ -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>

View 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>

View File

@ -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>

View 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!
}

View File

@ -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)
}
}

View File

@ -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;

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -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
}
}
}

View 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()
}
}

View 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")
}
}