From 7ef5742451a762a9256864a0396c52830cbbab07 Mon Sep 17 00:00:00 2001 From: Fernando Sanz Date: Thu, 25 Nov 2021 08:55:11 +0100 Subject: [PATCH 1/2] Retrieve data from DB as LiveData has been implemented. --- .../dependecyinjection/UseCaseModule.kt | 2 ++ .../dependecyinjection/ViewModelModule.kt | 2 +- .../owncloud/android/presentation/UIResult.kt | 13 +++++++ .../ui/files/filelist/MainFileListFragment.kt | 6 +--- .../files/filelist/MainFileListViewModel.kt | 17 ++++------ .../files/datasources/LocalFileDataSource.kt | 2 ++ .../implementation/OCLocalFileDataSource.kt | 9 +++++ .../owncloud/android/data/files/db/FileDao.kt | 6 ++++ .../data/files/repository/OCFileRepository.kt | 4 +++ .../android/domain/files/FileRepository.kt | 2 ++ .../GetFolderContentAsLiveDataUseCase.kt | 34 +++++++++++++++++++ 11 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 owncloudDomain/src/main/java/com/owncloud/android/domain/files/usecases/GetFolderContentAsLiveDataUseCase.kt diff --git a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt index 7cc35c34e26..fb049488fdc 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt @@ -41,6 +41,7 @@ import com.owncloud.android.domain.files.usecases.CreateFolderAsyncUseCase import com.owncloud.android.domain.files.usecases.GetFileByIdUseCase import com.owncloud.android.domain.files.usecases.GetFileByRemotePathUseCase import com.owncloud.android.domain.files.usecases.GetFilesSharedByLinkUseCase +import com.owncloud.android.domain.files.usecases.GetFolderContentAsLiveDataUseCase import com.owncloud.android.domain.files.usecases.GetFolderContentUseCase import com.owncloud.android.domain.files.usecases.GetFolderImagesUseCase import com.owncloud.android.domain.files.usecases.MoveFileUseCase @@ -92,6 +93,7 @@ val useCaseModule = module { factory { GetFileByIdUseCase(get()) } factory { GetFileByRemotePathUseCase(get()) } factory { GetFolderContentUseCase(get()) } + factory { GetFolderContentAsLiveDataUseCase(get()) } factory { GetFolderImagesUseCase(get()) } factory { MoveFileUseCase(get()) } factory { RefreshFolderFromServerAsyncUseCase(get()) } diff --git a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt index a9f6936ce56..b1a19596fbe 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt @@ -75,5 +75,5 @@ val viewModelModule = module { viewModel { PreviewImageViewModel(get(), get(), get()) } viewModel { FileDetailsViewModel(get(), get(), get(), get(), get()) } viewModel { FileOperationViewModel(get(), get(), get(), get(), get(), get()) } - viewModel { MainFileListViewModel(get(), get()) } + viewModel { MainFileListViewModel(get(), get(), get()) } } diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/UIResult.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/UIResult.kt index f08e2a6aa47..c18073c2ae0 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/UIResult.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/UIResult.kt @@ -19,6 +19,8 @@ package com.owncloud.android.presentation +import com.owncloud.android.domain.UseCaseResult + sealed class UIResult { data class Loading(val data: T? = null) : UIResult() data class Success(val data: T? = null) : UIResult() @@ -41,6 +43,15 @@ sealed class UIResult { is Error -> error else -> null } + + companion object { + fun fromResult(result: UseCaseResult): UIResult = + if (result.isSuccess) { + Success(result.getDataOrNull()) + } else { + Error(result.getThrowableOrNull()) + } + } } fun UIResult.onLoading(action: (data: T?) -> Unit): UIResult { @@ -69,3 +80,5 @@ fun UIResult.fold( is UIResult.Error -> onFailure(error) } } + +fun UseCaseResult.toUIResult() = UIResult.fromResult(this) diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListFragment.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListFragment.kt index 8877eb385c8..e73ec971051 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListFragment.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListFragment.kt @@ -30,8 +30,6 @@ import com.owncloud.android.databinding.MainFileListFragmentBinding import com.owncloud.android.domain.files.model.OCFile import com.owncloud.android.domain.utils.Event import com.owncloud.android.presentation.adapters.filelist.FileListAdapter -import com.owncloud.android.presentation.onError -import com.owncloud.android.presentation.onLoading import com.owncloud.android.presentation.onSuccess import org.koin.androidx.viewmodel.ext.android.viewModel @@ -69,15 +67,13 @@ class MainFileListFragment : Fragment() { } private fun subscribeToViewModels() { - //Observe the action of retrieving the list of files. + //Observe the action of retrieving the list of files from BBDD. mainFileListViewModel.getFilesListStatusLiveData.observe(viewLifecycleOwner, Event.EventObserver { - it.onLoading { /*TODO Manage Loading*/ } it.onSuccess { data -> val files = data ?: emptyList() fileListAdapter.updateFileList(filesToAdd = files) mainFileListViewModel.manageListOfFiles(files) } - it.onError { /*TODO Manage Error*/ } }) mainFileListViewModel.numberOfFilesPerType.observe(viewLifecycleOwner, Event.EventObserver { diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListViewModel.kt index 65b8729a7be..5ce8a466e50 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListViewModel.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListViewModel.kt @@ -25,18 +25,19 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.owncloud.android.R -import com.owncloud.android.domain.UseCaseResult import com.owncloud.android.domain.files.model.OCFile import com.owncloud.android.domain.files.usecases.GetFolderContentUseCase import com.owncloud.android.domain.utils.Event import com.owncloud.android.presentation.UIResult +import com.owncloud.android.presentation.toUIResult import com.owncloud.android.providers.ContextProvider -import kotlinx.coroutines.Dispatchers +import com.owncloud.android.providers.CoroutinesDispatcherProvider import kotlinx.coroutines.launch class MainFileListViewModel( - private val getFolderContentUseCase: GetFolderContentUseCase, + private val getFolderContentAsFlowUseCase: GetFolderContentUseCase, private val contextProvider: ContextProvider, + private val coroutinesDispatcherProvider: CoroutinesDispatcherProvider, ) : ViewModel() { private var file: OCFile? = null @@ -54,13 +55,9 @@ class MainFileListViewModel( get() = _footerText private fun getFilesList(folderId: Long) { - viewModelScope.launch(Dispatchers.IO) { - _getFilesListStatusLiveData.postValue(Event(UIResult.Loading())) - getFolderContentUseCase.execute(GetFolderContentUseCase.Params(folderId = folderId)).let { - when (it) { - is UseCaseResult.Error -> _getFilesListStatusLiveData.postValue(Event(UIResult.Error(it.getThrowableOrNull()))) - is UseCaseResult.Success -> _getFilesListStatusLiveData.postValue(Event(UIResult.Success(it.getDataOrNull()))) - } + viewModelScope.launch(coroutinesDispatcherProvider.io) { + with(getFolderContentAsFlowUseCase.execute(GetFolderContentUseCase.Params(folderId = folderId)).toUIResult()) { + _getFilesListStatusLiveData.postValue(Event(this)) } } } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/LocalFileDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/LocalFileDataSource.kt index f2c3822a068..3f328412a93 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/LocalFileDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/LocalFileDataSource.kt @@ -20,6 +20,7 @@ package com.owncloud.android.data.files.datasources +import androidx.lifecycle.LiveData import com.owncloud.android.domain.files.model.OCFile interface LocalFileDataSource { @@ -27,6 +28,7 @@ interface LocalFileDataSource { fun getFileById(fileId: Long): OCFile? fun getFileByRemotePath(remotePath: String, owner: String): OCFile? fun getFolderContent(folderId: Long): List + fun getFolderContentAsLiveData(folderId: Long): LiveData> fun getFolderImages(folderId: Long): List fun getFilesSharedByLink(owner: String): List fun moveFile(sourceFile: OCFile, targetFile: OCFile, finalRemotePath: String, finalStoragePath: String) diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCLocalFileDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCLocalFileDataSource.kt index 49b7c4f8a29..eebf2ecdf00 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCLocalFileDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/datasources/implementation/OCLocalFileDataSource.kt @@ -19,6 +19,8 @@ package com.owncloud.android.data.files.datasources.implementation import androidx.annotation.VisibleForTesting +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations import com.owncloud.android.data.files.datasources.LocalFileDataSource import com.owncloud.android.data.files.db.FileDao import com.owncloud.android.data.files.db.OCFileEntity @@ -67,6 +69,13 @@ class OCLocalFileDataSource( it.toModel() } + override fun getFolderContentAsLiveData(folderId: Long): LiveData> = + Transformations.map(fileDao.getFolderContentAsLiveData(folderId = folderId)) { list -> + list.map { + it.toModel() + } + } + override fun getFolderImages(folderId: Long): List = fileDao.getFolderByMimeType(folderId = folderId, mimeType = MIME_PREFIX_IMAGE).map { it.toModel() diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/db/FileDao.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/db/FileDao.kt index b1df362a9fd..273ffa511d7 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/files/db/FileDao.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/db/FileDao.kt @@ -18,6 +18,7 @@ */ package com.owncloud.android.data.files.db +import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy @@ -45,6 +46,11 @@ abstract class FileDao { folderId: Long ): List + @Query(SELECT_FOLDER_CONTENT) + abstract fun getFolderContentAsLiveData( + folderId: Long + ): LiveData> + @Query(SELECT_FOLDER_BY_MIMETYPE) abstract fun getFolderByMimeType( folderId: Long, diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt index 64cd0ec495d..23939010a95 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt @@ -20,6 +20,7 @@ package com.owncloud.android.data.files.repository +import androidx.lifecycle.LiveData import com.owncloud.android.data.files.datasources.LocalFileDataSource import com.owncloud.android.data.files.datasources.RemoteFileDataSource import com.owncloud.android.data.storage.LocalStorageProvider @@ -113,6 +114,9 @@ class OCFileRepository( override fun getFolderContent(folderId: Long): List = localFileDataSource.getFolderContent(folderId) + override fun getFolderContentAsLiveData(folderId: Long): LiveData> = + localFileDataSource.getFolderContentAsLiveData(folderId) + override fun getFolderImages(folderId: Long): List = localFileDataSource.getFolderImages(folderId) diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/files/FileRepository.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/FileRepository.kt index ed1ac8c04e1..63d3fc1e467 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/files/FileRepository.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/FileRepository.kt @@ -20,6 +20,7 @@ package com.owncloud.android.domain.files +import androidx.lifecycle.LiveData import com.owncloud.android.domain.files.model.OCFile interface FileRepository { @@ -28,6 +29,7 @@ interface FileRepository { fun getFileById(fileId: Long): OCFile? fun getFileByRemotePath(remotePath: String, owner: String): OCFile? fun getFolderContent(folderId: Long): List + fun getFolderContentAsLiveData(folderId: Long): LiveData> fun getFolderImages(folderId: Long): List fun getFilesSharedByLink(owner: String): List fun moveFile(listOfFilesToMove: List, targetFile: OCFile) diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/files/usecases/GetFolderContentAsLiveDataUseCase.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/usecases/GetFolderContentAsLiveDataUseCase.kt new file mode 100644 index 00000000000..d3a9e5834a7 --- /dev/null +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/usecases/GetFolderContentAsLiveDataUseCase.kt @@ -0,0 +1,34 @@ +/** + * ownCloud Android client application + * + * @author Abel GarcĂ­a de Prada + * Copyright (C) 2020 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.domain.files.usecases + +import androidx.lifecycle.LiveData +import com.owncloud.android.domain.BaseUseCase +import com.owncloud.android.domain.files.FileRepository +import com.owncloud.android.domain.files.model.OCFile + +class GetFolderContentAsLiveDataUseCase( + private val repository: FileRepository +) : BaseUseCase>, GetFolderContentAsLiveDataUseCase.Params>() { + + override fun run(params: Params) = repository.getFolderContentAsLiveData(params.folderId) + + data class Params(val folderId: Long) + +} From db6c7636350727f96043e4af8eba767550ef0eb1 Mon Sep 17 00:00:00 2001 From: Fernando Sanz Date: Thu, 25 Nov 2021 10:05:06 +0100 Subject: [PATCH 2/2] First part of CR done. --- .../dependecyinjection/ViewModelModule.kt | 2 +- .../owncloud/android/presentation/UIResult.kt | 13 ----------- .../files/filelist/MainFileListViewModel.kt | 23 +++++++++---------- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt index b1a19596fbe..a9f6936ce56 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt @@ -75,5 +75,5 @@ val viewModelModule = module { viewModel { PreviewImageViewModel(get(), get(), get()) } viewModel { FileDetailsViewModel(get(), get(), get(), get(), get()) } viewModel { FileOperationViewModel(get(), get(), get(), get(), get(), get()) } - viewModel { MainFileListViewModel(get(), get(), get()) } + viewModel { MainFileListViewModel(get(), get()) } } diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/UIResult.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/UIResult.kt index c18073c2ae0..f08e2a6aa47 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/UIResult.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/UIResult.kt @@ -19,8 +19,6 @@ package com.owncloud.android.presentation -import com.owncloud.android.domain.UseCaseResult - sealed class UIResult { data class Loading(val data: T? = null) : UIResult() data class Success(val data: T? = null) : UIResult() @@ -43,15 +41,6 @@ sealed class UIResult { is Error -> error else -> null } - - companion object { - fun fromResult(result: UseCaseResult): UIResult = - if (result.isSuccess) { - Success(result.getDataOrNull()) - } else { - Error(result.getThrowableOrNull()) - } - } } fun UIResult.onLoading(action: (data: T?) -> Unit): UIResult { @@ -80,5 +69,3 @@ fun UIResult.fold( is UIResult.Error -> onFailure(error) } } - -fun UseCaseResult.toUIResult() = UIResult.fromResult(this) diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListViewModel.kt index 5ce8a466e50..462703005a3 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListViewModel.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/ui/files/filelist/MainFileListViewModel.kt @@ -21,28 +21,24 @@ package com.owncloud.android.presentation.ui.files.filelist import androidx.lifecycle.LiveData +import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.owncloud.android.R import com.owncloud.android.domain.files.model.OCFile -import com.owncloud.android.domain.files.usecases.GetFolderContentUseCase +import com.owncloud.android.domain.files.usecases.GetFolderContentAsLiveDataUseCase import com.owncloud.android.domain.utils.Event import com.owncloud.android.presentation.UIResult -import com.owncloud.android.presentation.toUIResult import com.owncloud.android.providers.ContextProvider -import com.owncloud.android.providers.CoroutinesDispatcherProvider -import kotlinx.coroutines.launch class MainFileListViewModel( - private val getFolderContentAsFlowUseCase: GetFolderContentUseCase, + private val getFolderContentAsLiveDataUseCase: GetFolderContentAsLiveDataUseCase, private val contextProvider: ContextProvider, - private val coroutinesDispatcherProvider: CoroutinesDispatcherProvider, ) : ViewModel() { private var file: OCFile? = null - private val _getFilesListStatusLiveData = MutableLiveData>>>() + private val _getFilesListStatusLiveData = MediatorLiveData>>>() val getFilesListStatusLiveData: LiveData>>> get() = _getFilesListStatusLiveData @@ -55,10 +51,11 @@ class MainFileListViewModel( get() = _footerText private fun getFilesList(folderId: Long) { - viewModelScope.launch(coroutinesDispatcherProvider.io) { - with(getFolderContentAsFlowUseCase.execute(GetFolderContentUseCase.Params(folderId = folderId)).toUIResult()) { - _getFilesListStatusLiveData.postValue(Event(this)) - } + val filesListLiveData: LiveData> = + getFolderContentAsLiveDataUseCase.execute(GetFolderContentAsLiveDataUseCase.Params(folderId = folderId)) + + _getFilesListStatusLiveData.addSource(filesListLiveData) { + _getFilesListStatusLiveData.postValue(Event(UIResult.Success(it))) } } @@ -137,3 +134,5 @@ class MainFileListViewModel( getFilesList(directory.id!!) } } + +