Getting Timeline
The CloudikePhotos SDK provides features for building a timeline from the device's gallery and server, as well as for automatic photo download from a device.
#
InitializationAssume that an instance of CloudikePhotos - the Photos Manager has been created.
let photosManager: CloudikePhotos
#
Read Photos from the Device GalleryThere are two ways to start CloudikePhotos: with the photo auto uploading enabled and without it.
public final class CloudikePhotos {// ...public func configureWithUploadSettings(_ uploadSettings: CloudikeAutoUploadSettings, in background: Bool = false, with completion: ((NSError?) -> Void)?)// ...}
// ...
photosManager.configureWithUploadSettings(...)
Flag background tells that app running in background mode. If the isAutoUploadEnabled flag in CloudikeAutoUploadSettings is false, to scan the local gallery, after calling the method for configuring the SDK, you need to call the method:
public final class CloudikePhotos {// ...public func updateLocal()// ...}
// ...
photosManager.updaLocal()
#
Error handlingMost of CloudikePhotosKit APIs returns CloudikePhotosError object in callback:
public enum CloudikePhotosError: Error { case unknown case cancelled case noInternet case unauthorized case lowStorageSpace case lowDeviceStorageSpace case forbidden case invalidParameters case preconditionFailed
// ...
}
CloudikePhotosError have following cases:
- unknown: unknown error- cancelled: operation was cancelled by requesting api- noInternet: no connection to internet- unauthorized: authorization cretentials invalid- lowStorageSpace: low cloud disk space- lowDeviceStorageSpace: low device disk space - forbidden: internal server error- invalidParameters: invalid request- preconditionFailed: invalid request conditions
#
Read Photos from the Cloud Storage and Timeline ReloadingTo initially get and update the gallery stored on the server, you need to call the method:
public protocol TimelineUpdateService { func update(_ completion: ((Bool, CloudikePhotosError?) -> ())?)}
// ...
photosManager.timelineService.update() { // completion block}
#
Timeline Building a list of Timeline PhotosCloudikePhotosKit provides photo information for the client application through the special TimelineAdapter object, which is based on NSFetchedResultsController.
To initialize CloudikeAlbumsTimelineAdapter, you need to call the following methods:
override func viewDidLoad() {// ...
let adapter = photosManager.timelineService.timelineAdapter(collectionView)
// ...}
collectionView is the instance of the UICollectionView object used to display photos in the Timeline.
#
UICollectionViewTo build the timeline, an adapter is provided. It implements the NSFetchedResultsController methods. Building a timeline can be implemented using UICollectionView for which the application needs to implement the uicollectionviewdelegate delegate methods and UICollectionViewDataSource
#
iOS13 or Higher SupportIn iOS13 or later, you should implement closures to initialize objects to display section headers and cells. For iOS13 or higher, the Timeline Adapter uses UICollectionViewDiffableDataSource which is HIGHLY RECOMMENDED for iOS13 or higher.
#
Timeline Cell Configuration for iOS13 or Higher - UICollectionViewCellRefer to the following documents.
var cell: ((UICollectionView, IndexPath)->UICollectionViewCell)?
Your code (probably in ViewDidLoad) might look like this:
override func viewDidLoad() {// ...
adapter.cell = { [weak self] collectionView, indexPath in let cell = collectionView.dequeueReusableCell(withReuseIdentifier: <YourCustomCellReuseIdentifier>, for: indexPath) // setup your header here... self?.yourCellConfigurationMethod(cell) return cell }
// ...}
#
Timeline Section Header Configuration for iOS13 or Higher - UICollectionReusableViewUicollectionreusableview is used for section headers. The headers are configured using closures:
var supplementaryView: ((_ collectionView: UICollectionView, _ kind: String, _ indexPath: IndexPath, _ data: CloudikeTimelineHeaderData?) -> UICollectionReusableView)?
Your code (probably in ViewDidLoad) might look lile this:
override func viewDidLoad() {// ...
adapter.supplementaryView = { [weak self] collectionView, kind, indexPath, _ in var header: UICollectionReusableView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, for: indexPath) // setup your header here...
let timelineSectionHeaderTitle = self.adapter.nameForSection(indexPath.section)
if let view = view as? YourCustomHeaderReusableView { view.title = timelineSectionHeaderTitle }
return header }
// ...}
#
Adapter Preparings for iOS13 or HigherThis method should be called after setting up the clousures:
override func viewDidLoad() {// ...
if #available(iOS 13.0, *) { self.adapter.configure() }
// ...}
#
iOS12 or Lower SupportTo display header and cell on devices with iOS12 or lower, you should implement the following delegate methods.
#
Timeline Cell Configuration for iOS12 or Lower - UICollectionViewCellTo display cells on iOS 12 or lower, use the delegate method, which is not called in the IOS 13 runtime if the UICollectionViewDiffableDataSource methods are implemented:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
Your code might look like this:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimelineCollectionViewAdapter.timelineCellReuseIdentifier, for: indexPath) // setup your header here... self?.yourCellConfigurationMethod(cell) return cell }
#
Timeline Section Header Configuration for iOS12 or Lower - UICollectionReusableViewTo display section headers on iOS 12 or lower, the delegate method is used, which is not called in the iOS13 runtime if the UICollectionViewDiffableDataSource methods are implemented:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
Your code might look like this:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { [weak self] in guard kind == UICollectionView.elementKindSectionHeader else { return UICollectionReusableView() } var view: TimelineHeaderReusableView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, for: indexPath) // setup your header here... let timelineSectionHeaderTitle = self.adapter.nameForSection(indexPath.section)
if let view = view as? YourCustomHeaderReusableView { view.title = timelineSectionHeaderTitle }
return view }
#
Timeline Cell ObjectsThe Timeline cell data is contained in the CloudikeMediaItem objects. If you want to track the status of uploading of an object to the server, then when you receive the CloudikeMediaItem object, you must configure a closure that returns the CloudikeUploadStatus object.
To get the data to configure the cell of the timeline, you need to call the method:
public protocol TimelineAdapter: BaseAdapter { func mediaItem(_ indexPath: IndexPath, with didUpdateBlock: ((CloudikeUploadStatus?) -> Void)?) -> CloudikeMediaItem?}
So, your code might look like this:
func yourCellConfigurationMethod(cell: UICollectionViewCell) { if let timelineCell = cell as? YourCustomTimelineCollectionViewCell { if let mediaItem = self.adapter.mediaItem(indexPath, with: { [weak timelineCell] uploadStatus in DispatchQueue.main.async { // Here you need to update the auto upload status for the cell. timelineCell?.yourUpdateUploadStatusMethod(uploadStatus) } }) { // Here we configure your custom cell.
} }}
#
UICollectionViewDataSourceFor implementing methods, the Delegate CloudikePhotosKit methods are used. You need to implement the UICollectionViewDataSource methods for your UICollectionView.
// MARK: - UICollectionViewDataSourcefunc collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.adapter.itemsCount(section)} func numberOfSections(in collectionView: UICollectionView) -> Int { return self.adapter.sectionsCount()}
#
Reaction for Changes in ContentTo perform additional actions when updating CloudikePhotosKit data, you can configure the closure:
adapter.didChangeContent = { ...your code here }
#
Timeline ReloadIt is recommended to update the timeline in this way:
public func update(fullRefresh: Bool, with completion: (() -> Void)?) { photosManager.timelineService.update(fullRefresh: fullRefresh) { [weak self] _ in self?.adapter.fetch{ completion?() } } }
#
PHAuthorizationStatusYou should request PHAuthorizationStatus before starting inintialization process for CloudikePhotosKit or you can allow framework to request PHAuthorizationStatus by setting the CloudikePhotosSettings's isPermissionsRequestAllowed parameter to TRUE
#
Plist file: Privacy - Photo Library Usage DescriptionYou should add the value Privacy - Photo Library Usage Description to your app's plist file.
#
LogoutTo shut down Cloudike Photos, stop auto upload and clear records in the database, for example, to change the user, you need to call the "logout" method.
photosManager.logout {// ... completion block}