Skip to main content

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.

Initialization#

Assume that an instance of CloudikePhotos - the Photos Manager has been created.

let photosManager: CloudikePhotos

Read Photos from the Device Gallery#

There 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 handling#

Most 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 Reloading#

To 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 Photos#

CloudikePhotosKit 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.

UICollectionView#

To 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 Support#

In 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 - UICollectionViewCell#

Refer 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 - UICollectionReusableView#

Uicollectionreusableview 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 Higher#

This method should be called after setting up the clousures:


override func viewDidLoad() {// ...
    if #available(iOS 13.0, *) {            self.adapter.configure()        }
// ...}

iOS12 or Lower Support#

To display header and cell on devices with iOS12 or lower, you should implement the following delegate methods.

Timeline Cell Configuration for iOS12 or Lower - UICollectionViewCell#

To 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 - UICollectionReusableView#

To 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 Objects#

The 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.
            }    }}

UICollectionViewDataSource#

For 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 Content#

To perform additional actions when updating CloudikePhotosKit data, you can configure the closure:

    adapter.didChangeContent = {        ...your code here    }

Timeline Reload#

It 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?()            }        }    }

PHAuthorizationStatus#

You 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 Description#

You should add the value Privacy - Photo Library Usage Description to your app's plist file.

Logout#

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