Skip to main content

Working With Albums

This guide describes methods for working with albums. The guide is logically divided into two parts - Album Actions and Album Content Actions.

Album Actions#

This chapter describes methods for creating and modifying albums, excluding working with their contents.

Read Album List From Backend#

To get started with the albums, first of all get information about the family albums from the backend.

important

Since the download procedure takes some time (and, on the other hand, does not require permission from the user), it should be started as soon as the user is logged into the application.

For getting the list of albums from the backend, use the fetchAlbums() method. You need to pass a list of album types that you want to retrieve. All supported album types are listed in AlbumType data class. Example code:

var disposable: Disposable? = null
// ...
// This method returns OperationFetchAlbums object, which contains Completable. // You have to subscribe on returned completable in order to receive updates.disposable = PhotoManager.albums.fetchAlbums(    listOf(        AlbumType.SIMPLE,        AlbumType.FLASHBACK,        AlbumType.PLACE    ))    .completable    .observeOn(AndroidSchedulers.mainThread())    .subscribeBy(        onComplete = {            // Handle it        },        onError = { // it: Throwable            // Handle it        }    )
// ...
// You must call dispose() on disposable that returned by subscribe() method,// when it no longer needed, for example in your fragment’s onStop() or onPause().disposable?.dispose()

Seasonal, Favorite, and Shared with me albums should be requested separately. Use this methods to get them:

// ...
//PhotoManager.albums.fetchFavoriteAlbum()//PhotoManager.albums.fetchSharedWithMeAlbums()disposable = PhotoManager.albums.fetchSeasonalAlbums()    .completable    .observeOn(AndroidSchedulers.mainThread())    .subscribeBy(        onComplete = {            // Handle it        },        onError = { // it: Throwable            // Handle it        }    )
// ...

Get Albums List#

The Photos SDK provides information about albums for the client application as a paged list of AlbumItem objects.

To request a list of albums, you need to use the createPagingAlbumsFlow() method. This method creates a Flow that emits PagingData of AlbumItem every time there is a change to the local database. The method takes the following parameters:

  1. albumTypes - a list of album types that you want to retrieve. All supported album types are listed in the AlbumType class. The default value is listOf(AlbumType.SIMPLE, AlbumType.SHARED).
  2. minItemCount - the minimum number of items in an album for it to be included in the list. The default value is 0.
  3. limit - the number of items to retrieve. The default value is null.

To display the paginated list in the RecyclerView, you must use PagingDataAdapter from the Android Paging Library.

The Cloudike Photos SDK uses the following Android Paging Library.

// Pagingimplementation 'androidx.paging:paging-runtime-ktx:3.3.0'implementation 'androidx.paging:paging-rxjava2-ktx:3.3.0'

The following code example demonstrates getting a list of albums.

//ViewModelclass AlbumListViewModel(    private val albums: Albums) : ViewModel() {
    val contentFlow: Flow<PagingData<AlbumItem>> by lazy {        albums.createPagingAlbumsFlow(            listOf(AlbumType.SIMPLE, AlbumType.SHARED, AlbumType.PLACE),        )            .cachedIn(viewModelScope)    }}
// Fragmentclass AlbumListFrg : Fragment() {
    private val adapter: AlbumListAdapter // derived from PagingDataAdapter    private val albums = PhotoManager.albums    private val viewModel: AlbumListViewModel by viewModels { AlbumListViewModelFactory(albums) }    private var disposable: Disposable? = null        override fun onViewCreated() {        super.onViewCreated()
        // You have to subscribe to the returned Flow to receive updates.        viewLifecycleOwner.lifecycleScope.launch {            viewModel.contentFlow.collectLatest {                    adapter.submitData(it)                }        }    }}

To get a list of albums with types Shared with me, Memories, and Seasonal, use the following methods:

//ViewModelclass AlbumListViewModel(    private val albums: Albums) : ViewModel() {        // You can change the limit value to get more or less albums. Only for Memories and Seasonal albums.    val limit = 10
    val sharedWithMeAlbumsFlow: Flow<PagingData<AlbumItem>> by lazy {        albums.createPagingSharedAlbumsFlow()            .cachedIn(viewModelScope)    }        val memoriesAlbumFlow: Flow<PagingData<AlbumItem>> by lazy {        albums.createPagingMemoriesAlbumsFlow(limit)            .cachedIn(viewModelScope)    }        val seasonalAlbumsFlow: Flow<PagingData<AlbumItem>> by lazy {        albums.createPagingSeasonalAlbumsFlow(limit)            .cachedIn(viewModelScope)    }}

Get Album#

The following code example demonstrates getting an album.

var disposable: Disposable? = null
// Album name.val albumId: String = // "id"
// ...
// The returned Single emits an AlbumItem when the getting album operation is succeeded.// You have to subscribe to returned single in order to receive result.disposable = PhotoManager.albums.getAlbumItem(albumId)        .observeOn(AndroidSchedulers.mainThread())        .subscribeBy(                onSuccess = { // it: AlbumItem!                    // Handle it                },                onError = { // it: Throwable                    // Handle it                }        )
// ...
// You must call dispose() on disposable that returned by subscribe() method,// when it is no longer needed, for example in your fragment’s onStop() or onPause().disposable?.dispose()

Links - AlbumItem.

Create Album#

The following code example demonstrates creating an album.

var disposable: Disposable? = null
// Album name.val name: String = "AlbumName"
// Album type.val type: AlbumType = AlbumType.SIMPLE// Album can be one of the following types://     * SIMPLE - Simple album.//     * SHARED - Album that has a link for viewing and / or editing//                (depending on the isSharedForEdit parameter).

// List of media IDs to add to the new album. If the photos / videos specified for adding toval mediaIds: Set<Long> = setOf(1L, 2L, 3L)
// List of media URIs to add to the new album. If the photos / videos specified for adding toval mediaUris: List<Uri> = listOf("uri1", "uri2", "uri3")
val fromAnotherCloud: Boolean = false
// ...
// Returns an OperationCreateAlbum object from which information about the operation can be // obtained. For example, to know about the completion of an operation, you need to // subscribe to the single included in the operation object.disposable = PhotoManager.albums.createAlbum(name, type, mediaIds, mediaUris, fromAnotherCloud)        .single        .observeOn(AndroidSchedulers.mainThread())        .subscribeBy(                onSuccess = { // it: AlbumItem!                    // Handle it                },                onError = { // it: Throwable                    // Handle it                }        )
// ...
// You must call dispose() on disposable that returned by subscribe() method,// when it is no longer needed, for example in your fragment’s onStop() or onPause().disposable?.dispose()

Links - AlbumType, PhotoItem, OperationCreateAlbum.

Edit Album#

The following code example demonstrates editing an album.

var disposable: Disposable? = null
// Album id.val albumId: String = "AlbumId"
// Name of album.val name: String = "AlbumName"
// Album type.val type: AlbumType = AlbumItem.AlbumType.SIMPLE// Album can be one of the following types://     * SIMPLE - Simple album.//     * SHARED - Album that has a link for viewing and / or editing//                (depending on the isSharedForEdit parameter).
// Mark album as viewed.val isViewed: Boolean = true
// ...
// Returns an OperationEditAlbum object from which information about the operation can be // obtained. For example, to know about the completion of an operation, you need to // subscribe to the single included in the operation object.disposable = PhotoManager.albums.editAlbum(albumId, name, type, isViewed)        .single        .observeOn(AndroidSchedulers.mainThread())        .subscribeBy(                onSuccess = { // it: AlbumItem!                    // Handle it                },                onError = { // it: Throwable                    // Handle it                }        )
// ...
// You must call dispose() on disposable that returned by subscribe() method,// when it is no longer needed, for example in your fragment’s onStop() or onPause().disposable?.dispose()

Links - AlbumType, OperationEditAlbum.

Delete Album#

Sample code for deleting albums:

var disposable: Disposable? = null
// List of album IDs to be deleted. When you delete an album, the photos and videos included in it are not deleted, and are still available in the Timeline.val albumIdList: List<String> = listOf()
// ...
// Returns an OperationDeleteAlbums object from which information about the operation can be // obtained. For example, to know about the completion of an operation, you need to // subscribe to the single included in the operation object.disposable = PhotoManager.albums.deleteAlbums(albumIdList)        .completable        .observeOn(AndroidSchedulers.mainThread())        .subscribeBy(                onComplete = {                    // Handle it                },                onError = { // it: Throwable                    // Handle it                }        )
// ...
// You must call dispose() on disposable that returned by subscribe() method,// when it is no longer needed, for example in your fragment’s onStop() or onPause().disposable?.dispose()

Links - OperationDeleteAlbums.

Album Content Actions#

This chapter describes methods for creating and modifying albums, excluding working with their contents.

Read Album Content From Backend#

To get started with album content, get the actual content from the backend (list of photos in the album).

var disposable: Disposable? = null
// Album ID. It can be obtained from AlbumItem.val albumId: String = // Some "Id"
// ...
// You have to subscribe to returned observable in order to receive updates.disposable = PhotoManager.albums.fetchAlbumContent(albumId)        .completable        .observeOn(AndroidSchedulers.mainThread())        .subscribeBy(                onSuccess = { // it: AlbumItem!                    // Handle it                },                onError = { // it: Throwable                    // Handle it                }        )
// ...
// You must call dispose() on disposable that returned by subscribe() method,// when it is no longer needed, for example in your fragment’s onStop() or onPause().disposable?.dispose()

Links - AlbumItem.

Get Album Content#

The Cloudike Photos SDK provides information about photos and videos of an album to the client application as a paged list of PhotoItem objects. Working with this list is similar to the Timeline.

important

The createPagingAlbumContentObservable(albumId) function creates new Observable that emits a PagingData of PhotoItems every time there is a change to the local database. To display the paginated list in the RecyclerView, you must use PagingDataAdapter from the Android Paging Library.

The Cloudike Photos SDK uses the following Android Paging Library.

// Pagingimplementation 'androidx.paging:paging-runtime-ktx:3.3.0'implementation 'androidx.paging:paging-rxjava2-ktx:3.3.0'

The following code example demonstrates getting an album content.

// Declare view modelclass AlbumViewModel(    private val albumId: String,    private val albums: Albums) : ViewModel() {
    // NOTE: Your app can use either Observable or Flow. Both of them are created here for demo purposes only.        val contentObservable: Observable<PagingData<PhotoItem>> by lazy {        albums.createPagingAlbumContentObservable(albumId)            .cachedIn(viewModelScope)    }
    val contentFlow: Flow<PagingData<PhotoItem>> by lazy {        albums.createPagingAlbumContentFlow(albumId)            .cachedIn(viewModelScope)    }}
// Factory is required to pass albumId and albums singleton to the view modelprivate class AlbumViewModelFactory(    private val albumId: String,    private val albums: Albums) : ViewModelProvider.NewInstanceFactory() {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {        return AlbumViewModel(albumId, albums) as T    }}
// Fragmentclass AlbumFrg : Fragment() {
    private lateinit var albumId: String    private val adapter: AlbumAdapter // derived from PagingDataAdapter    private val albums = PhotoManager.albums    private val viewModel: AlbumViewModel by viewModels { AlbumViewModelFactory(albumId, albums) }    private var disposable: Disposable? = null
    override fun onStart() {        super.onStart()        // You have to subscribe to the returned Observable to receive updates.        disposable = viewModel.contentObservable            .subscribe { pagingData ->                // Update adapter                adapter.submitData(this.lifecycle, pagingData)            }    }
    override fun onStop() {        super.onStop()        // You must call dispose() on disposable that returned by the subscribe() method,        // when it is no longer needed, for example in your fragment’s onStop() or onPause().        disposable?.dispose()    }}

As an alternative to Observable, Flow is also available for getting media items of the album:

    override fun onStart() {        super.onStart()        lifecycleScope.launch {            viewModel.contentFlow                .collectLatest {                    adapter.submitData(it)                }        }    }

Links - PagingData, PhotoItem.

Add Photos To Album#

To add a photo / video to an existing album, use the PhotoManager.albums.addPhotos() function.

important

The same photo / video can be added to multiple albums.

important

If the photos / videos specified for adding to the album have not yet been uploaded to the cloud storage, then they will be automatically uploaded first, and only then added to the album. Uploading to cloud storage may take a while, depending on the amount of data.

The following code example demonstrates adding a photo to an album.

var disposable: Disposable? = null
// Album ID. It can be obtained from AlbumItem.val albumId: String = "Id"
// List of photos / videos to add to the album.val photoList: List<PhotoItem> = listOf()
// List of media URIs to add to the album.val mediaUris: List<Uri> = listOf()
// ...
// Returns an OperationAddPhotos object from which information about the operation can be // obtained. For example, to know about the completion of an operation, you need to // subscribe to the single included in the operation object.disposable = PhotoManager.albums.addPhotos(albumId, photoList) //or mediaUris        .single        .observeOn(AndroidSchedulers.mainThread())        .subscribeBy(                onSuccess = { // it: AlbumItem!                    // Handle it                },                onError = { // it: Throwable                    // Handle it                }        )
// ...
// You must call dispose() on disposable that returned by subscribe() method,// when it is no longer needed, for example in your fragment’s onStop() or onPause().disposable?.dispose()

Links - PhotoItem, OperationAddPhotos.

Remove Photos From Album#

To remove a photo / video from the existing album, use the PhotoManager.albums.deletePhotos() function.

important

When you delete items from an album, they are not deleted from the cloud storage, and will still be available in the Timeline.

var disposable: Disposable? = null
// Album ID. It can be obtained from AlbumItem.val albumId: String = "Id"
// List of photos / videos to remove from album.val photoList: List<PhotoItem> = listOf()
// ...
// Returns an OperationRemovePhotos object from which information about the operation can be // obtained. For example, to know about the completion of an operation, you need to // subscribe to the single included in the operation object.disposable = PhotoManager.albums.removePhotos(albumId, photoList)        .single        .observeOn(AndroidSchedulers.mainThread())        .subscribeBy(                onSuccess = { // it: AlbumItem!                    // Handle it                },                onError = { // it: Throwable                    // Handle it                }        )// ...
// You must call dispose() on disposable that returned by subscribe() method,// when it is no longer needed, for example in your fragment’s onStop() or onPause().disposable?.dispose()

Links - PhotoItem, OperationRemovePhotos.