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 24a9f9c3d59..97fd86940db 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt @@ -80,14 +80,14 @@ import com.owncloud.android.domain.sharing.shares.usecases.EditPublicShareAsyncU import com.owncloud.android.domain.sharing.shares.usecases.GetShareAsLiveDataUseCase import com.owncloud.android.domain.sharing.shares.usecases.GetSharesAsLiveDataUseCase import com.owncloud.android.domain.sharing.shares.usecases.RefreshSharesFromServerAsyncUseCase -import com.owncloud.android.domain.spaces.usecases.GetSpacesFromEveryAccountUseCase +import com.owncloud.android.domain.spaces.usecases.GetSpacesFromEveryAccountUseCaseAsStream import com.owncloud.android.domain.spaces.usecases.GetPersonalAndProjectSpacesForAccountUseCase import com.owncloud.android.domain.spaces.usecases.GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase import com.owncloud.android.domain.spaces.usecases.GetProjectSpacesWithSpecialsForAccountAsStreamUseCase import com.owncloud.android.domain.spaces.usecases.GetSpaceWithSpecialsByIdForAccountUseCase import com.owncloud.android.domain.spaces.usecases.RefreshSpacesFromServerAsyncUseCase import com.owncloud.android.domain.transfers.usecases.ClearSuccessfulTransfersUseCase -import com.owncloud.android.domain.transfers.usecases.GetAllTransfersAsLiveDataUseCase +import com.owncloud.android.domain.transfers.usecases.GetAllTransfersAsStreamUseCase import com.owncloud.android.domain.transfers.usecases.GetAllTransfersUseCase import com.owncloud.android.domain.transfers.usecases.UpdatePendingUploadsPathUseCase import com.owncloud.android.domain.user.usecases.GetStoredQuotaUseCase @@ -186,7 +186,7 @@ val useCaseModule = module { factory { RefreshSharesFromServerAsyncUseCase(get()) } // Spaces - factory { GetSpacesFromEveryAccountUseCase(get()) } + factory { GetSpacesFromEveryAccountUseCaseAsStream(get()) } factory { GetPersonalAndProjectSpacesForAccountUseCase(get()) } factory { GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase(get()) } factory { GetProjectSpacesWithSpecialsForAccountAsStreamUseCase(get()) } @@ -209,7 +209,7 @@ val useCaseModule = module { factory { CancelUploadsRecursivelyUseCase(get(), get(), get(), get()) } factory { RetryUploadFromSystemUseCase(get(), get(), get()) } factory { RetryUploadFromContentUriUseCase(get(), get(), get()) } - factory { GetAllTransfersAsLiveDataUseCase(get()) } + factory { GetAllTransfersAsStreamUseCase(get()) } factory { GetAllTransfersUseCase(get()) } factory { CancelUploadUseCase(get(), get(), get()) } factory { ClearFailedTransfersUseCase(get(), get(), 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 790f70e48e4..c7a88e41056 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt @@ -106,7 +106,6 @@ val viewModelModule = module { get(), get(), get(), - get(), initialFolderToDisplay, fileListOption, ) diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/FileListAdapter.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/FileListAdapter.kt index 8aa18fd9814..aa8bae15038 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/FileListAdapter.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/FileListAdapter.kt @@ -42,7 +42,6 @@ import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.domain.files.model.FileListOption import com.owncloud.android.domain.files.model.OCFileWithSyncInfo import com.owncloud.android.domain.files.model.OCFooterFile -import com.owncloud.android.domain.spaces.model.OCSpace import com.owncloud.android.presentation.authentication.AccountUtils import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimetypeIconUtil @@ -59,14 +58,10 @@ class FileListAdapter( private var account: Account? = AccountUtils.getCurrentOwnCloudAccount(context) private var fileListOption: FileListOption = FileListOption.ALL_FILES - fun updateFileList(filesToAdd: List, fileListOption: FileListOption, spaces: List) { - val fileItems = filesToAdd.map { fileWithSyncInfo -> - val space = spaces.firstOrNull { it.id == fileWithSyncInfo.file.spaceId && it.accountName == fileWithSyncInfo.file.owner } - FileItem(fileWithSyncInfo, space) - } + fun updateFileList(filesToAdd: List, fileListOption: FileListOption) { val listWithFooter = mutableListOf() - listWithFooter.addAll(fileItems) + listWithFooter.addAll(filesToAdd) if (listWithFooter.isNotEmpty()) { listWithFooter.add(OCFooterFile(manageListOfFilesAndGenerateText(filesToAdd))) @@ -139,7 +134,7 @@ class FileListAdapter( layoutManager.spanCount == 1 -> { ViewType.LIST_ITEM.ordinal } - (files[position] as FileItem).fileWithSyncInfo.file.isImage -> { + (files[position] as OCFileWithSyncInfo).file.isImage -> { ViewType.GRID_IMAGE.ordinal } else -> { @@ -179,8 +174,7 @@ class FileListAdapter( if (viewType != ViewType.FOOTER.ordinal) { // Is Item - val fileItem = files[position] as FileItem - val fileWithSyncInfo = fileItem.fileWithSyncInfo + val fileWithSyncInfo = files[position] as OCFileWithSyncInfo val file = fileWithSyncInfo.file val name = file.fileName val fileIcon = holder.itemView.findViewById(R.id.thumbnail).apply { @@ -211,12 +205,12 @@ class FileListAdapter( it.Filename.text = file.fileName it.fileListSize.text = DisplayUtils.bytesToHumanReadable(file.length, context) it.fileListLastMod.text = DisplayUtils.getRelativeTimestamp(context, file.modificationTimestamp) - if (fileListOption.isAvailableOffline() || (fileListOption.isSharedByLink() && fileItem.space == null)) { + if (fileListOption.isAvailableOffline() || (fileListOption.isSharedByLink() && fileWithSyncInfo.space == null)) { it.spacePathLine.path.apply { text = file.getParentRemotePath() isVisible = true } - fileItem.space?.let { space -> + fileWithSyncInfo.space?.let { space -> it.spacePathLine.spaceIcon.isVisible = true it.spacePathLine.spaceName.isVisible = true if (space.isPersonal) { @@ -406,8 +400,6 @@ class FileListAdapter( fun onLongItemClick(position: Int): Boolean = true } - data class FileItem(val fileWithSyncInfo: OCFileWithSyncInfo, val space: OCSpace?) - inner class GridViewHolder(val binding: GridItemBinding) : RecyclerView.ViewHolder(binding.root) inner class GridImageViewHolder(val binding: GridItemBinding) : RecyclerView.ViewHolder(binding.root) inner class ListViewHolder(val binding: ItemFileListBinding) : RecyclerView.ViewHolder(binding.root) diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/FileListDiffCallback.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/FileListDiffCallback.kt index e3701a35c5e..b72f1987c0d 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/FileListDiffCallback.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/FileListDiffCallback.kt @@ -23,6 +23,7 @@ package com.owncloud.android.presentation.files.filelist import androidx.recyclerview.widget.DiffUtil import com.owncloud.android.domain.files.model.FileListOption +import com.owncloud.android.domain.files.model.OCFileWithSyncInfo import com.owncloud.android.domain.files.model.OCFooterFile class FileListDiffCallback( @@ -48,8 +49,8 @@ class FileListDiffCallback( return true } - if (oldItem is FileListAdapter.FileItem && newItem is FileListAdapter.FileItem) { - return oldItem.fileWithSyncInfo.file.id == newItem.fileWithSyncInfo.file.id + if (oldItem is OCFileWithSyncInfo && newItem is OCFileWithSyncInfo) { + return oldItem.file.id == newItem.file.id } if (oldItem is OCFooterFile && newItem is OCFooterFile) { diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListFragment.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListFragment.kt index 3caee1e2bd3..09413ae70b6 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListFragment.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListFragment.kt @@ -240,7 +240,6 @@ class MainFileListFragment : Fragment(), fileListAdapter.updateFileList( filesToAdd = fileListUiState.folderContent, fileListOption = fileListUiState.fileListOption, - spaces = mainFileListViewModel.spaces.value, ) showOrHideEmptyView(fileListUiState) diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListViewModel.kt index 1c982a323ae..3ef98834acb 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListViewModel.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListViewModel.kt @@ -38,7 +38,6 @@ import com.owncloud.android.domain.files.usecases.GetSharedByLinkForAccountAsStr import com.owncloud.android.domain.files.usecases.SortFilesWithSyncInfoUseCase import com.owncloud.android.domain.spaces.model.OCSpace import com.owncloud.android.domain.spaces.usecases.GetSpaceWithSpecialsByIdForAccountUseCase -import com.owncloud.android.domain.spaces.usecases.GetSpacesFromEveryAccountUseCase import com.owncloud.android.presentation.files.SortOrder import com.owncloud.android.presentation.files.SortOrder.Companion.PREF_FILE_LIST_SORT_ORDER import com.owncloud.android.presentation.files.SortType @@ -68,7 +67,6 @@ class MainFileListViewModel( private val getSpaceWithSpecialsByIdForAccountUseCase: GetSpaceWithSpecialsByIdForAccountUseCase, private val sortFilesWithSyncInfoUseCase: SortFilesWithSyncInfoUseCase, private val synchronizeFolderUseCase: SynchronizeFolderUseCase, - private val getSpacesFromEveryAccountUseCase: GetSpacesFromEveryAccountUseCase, // TODO: To be deleted when adding the space to the file entity private val coroutinesDispatcherProvider: CoroutinesDispatcherProvider, private val sharedPreferencesProvider: SharedPreferencesProvider, initialFolderToDisplay: OCFile, @@ -83,10 +81,6 @@ class MainFileListViewModel( private val sortTypeAndOrder = MutableStateFlow(Pair(SortType.SORT_TYPE_BY_NAME, SortOrder.SORT_ORDER_ASCENDING)) val space: MutableStateFlow = MutableStateFlow(null) - private val _spaces: MutableStateFlow> = MutableStateFlow(emptyList()) - val spaces: StateFlow> - get() = _spaces - /** File list ui state combines the other fields and generate a new state whenever any of them changes */ val fileListUiState: StateFlow = combine( @@ -127,10 +121,6 @@ class MainFileListViewModel( ) ) } - viewModelScope.launch(coroutinesDispatcherProvider.io) { - val spacesList = getSpacesFromEveryAccountUseCase.execute(Unit) - _spaces.update { spacesList } - } } fun navigateToFolderId(folderId: Long) { diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransferListFragment.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransferListFragment.kt index 6770457e223..0ff268cccc3 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransferListFragment.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransferListFragment.kt @@ -34,6 +34,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.snackbar.Snackbar import com.owncloud.android.R import com.owncloud.android.databinding.FragmentTransferListBinding +import com.owncloud.android.domain.spaces.model.OCSpace import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferResult import com.owncloud.android.extensions.collectLatestLifecycleFlow @@ -99,7 +100,7 @@ class TransferListFragment : Fragment() { addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL)) } - transfersViewModel.transfersListLiveData.observe(viewLifecycleOwner) { transfers -> + collectLatestLifecycleFlow(transfersViewModel.transfersWithSpaceStateFlow) { transfers -> val recyclerViewState = binding.transfersRecyclerView.layoutManager?.onSaveInstanceState() setData(transfers) binding.transfersRecyclerView.layoutManager?.onRestoreInstanceState(recyclerViewState) @@ -111,10 +112,6 @@ class TransferListFragment : Fragment() { } } - collectLatestLifecycleFlow(transfersViewModel.spaces) { - transfersViewModel.transfersListLiveData.value?.let { transfers -> setData(transfers) } - } - } override fun onDestroy() { @@ -122,14 +119,14 @@ class TransferListFragment : Fragment() { _binding = null } - private fun setData(items: List) { - binding.transfersRecyclerView.isVisible = items.isNotEmpty() + private fun setData(transfersWithSpace: List>) { + binding.transfersRecyclerView.isVisible = transfersWithSpace.isNotEmpty() binding.transfersListEmpty.apply { - root.isVisible = items.isEmpty() + root.isVisible = transfersWithSpace.isEmpty() listEmptyDatasetIcon.setImageResource(R.drawable.ic_uploads) listEmptyDatasetTitle.setText(R.string.upload_list_empty) listEmptyDatasetSubTitle.setText(R.string.upload_list_empty_subtitle) } - transfersAdapter.setData(items, transfersViewModel.spaces.value) + transfersAdapter.setData(transfersWithSpace) } } diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransfersAdapter.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransfersAdapter.kt index 69d9cc8b926..00f9c625325 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransfersAdapter.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransfersAdapter.kt @@ -235,15 +235,14 @@ class TransfersAdapter( } } - fun setData(transfers: List, spaces: List) { - val transfersGroupedByStatus = transfers.groupBy { it.status } + fun setData(transfersWithSpace: List>) { + val transfersGroupedByStatus = transfersWithSpace.groupBy { it.first.status } val newTransferItemsList = mutableListOf() transfersGroupedByStatus.forEach { transferMap -> val headerItem = HeaderItem(transferMap.key, transferMap.value.size) newTransferItemsList.add(headerItem) - val transferItems = transferMap.value.sortedByDescending { it.transferEndTimestamp ?: it.id }.map { transfer -> - val space = spaces.firstOrNull { it.id == transfer.spaceId && it.accountName == transfer.accountName } - TransferItem(transfer, space) + val transferItems = transferMap.value.sortedByDescending { it.first.transferEndTimestamp ?: it.first.id }.map { transfersWithSpace -> + TransferItem(transfersWithSpace.first, transfersWithSpace.second) } newTransferItemsList.addAll(transferItems) } @@ -283,6 +282,7 @@ class TransfersAdapter( val transfer: OCTransfer, val space: OCSpace?, ) : TransferRecyclerItem + data class HeaderItem( val status: TransferStatus, val numberTransfers: Int, diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransfersViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransfersViewModel.kt index 31fcde0379b..5934dc6f071 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransfersViewModel.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransfersViewModel.kt @@ -28,10 +28,10 @@ import androidx.lifecycle.viewModelScope import androidx.work.WorkInfo import com.owncloud.android.domain.files.model.OCFile import com.owncloud.android.domain.spaces.model.OCSpace -import com.owncloud.android.domain.spaces.usecases.GetSpacesFromEveryAccountUseCase +import com.owncloud.android.domain.spaces.usecases.GetSpacesFromEveryAccountUseCaseAsStream import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.usecases.ClearSuccessfulTransfersUseCase -import com.owncloud.android.domain.transfers.usecases.GetAllTransfersAsLiveDataUseCase +import com.owncloud.android.domain.transfers.usecases.GetAllTransfersAsStreamUseCase import com.owncloud.android.providers.CoroutinesDispatcherProvider import com.owncloud.android.providers.WorkManagerProvider import com.owncloud.android.usecases.transfers.downloads.CancelDownloadForFileUseCase @@ -46,9 +46,10 @@ import com.owncloud.android.usecases.transfers.uploads.RetryUploadFromContentUri import com.owncloud.android.usecases.transfers.uploads.RetryUploadFromSystemUseCase import com.owncloud.android.usecases.transfers.uploads.UploadFilesFromContentUriUseCase import com.owncloud.android.usecases.transfers.uploads.UploadFilesFromSystemUseCase -import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch class TransfersViewModel( @@ -61,43 +62,39 @@ class TransfersViewModel( private val clearFailedTransfersUseCase: ClearFailedTransfersUseCase, private val retryFailedUploadsUseCase: RetryFailedUploadsUseCase, private val clearSuccessfulTransfersUseCase: ClearSuccessfulTransfersUseCase, - getAllTransfersAsLiveDataUseCase: GetAllTransfersAsLiveDataUseCase, + getAllTransfersAsStreamUseCase: GetAllTransfersAsStreamUseCase, private val cancelDownloadForFileUseCase: CancelDownloadForFileUseCase, private val cancelUploadForFileUseCase: CancelUploadForFileUseCase, private val cancelUploadsRecursivelyUseCase: CancelUploadsRecursivelyUseCase, private val cancelDownloadsRecursivelyUseCase: CancelDownloadsRecursivelyUseCase, - private val getSpacesFromEveryAccountUseCase: GetSpacesFromEveryAccountUseCase, + getSpacesFromEveryAccountUseCaseAsStream: GetSpacesFromEveryAccountUseCaseAsStream, private val coroutinesDispatcherProvider: CoroutinesDispatcherProvider, workManagerProvider: WorkManagerProvider, ) : ViewModel() { - - private val _transfersListLiveData = MediatorLiveData>() - val transfersListLiveData: LiveData> - get() = _transfersListLiveData - private val _workInfosListLiveData = MediatorLiveData>() val workInfosListLiveData: LiveData> get() = _workInfosListLiveData - private var transfersLiveData = getAllTransfersAsLiveDataUseCase.execute(Unit) + val transfersWithSpaceStateFlow: StateFlow>> = combine( + getAllTransfersAsStreamUseCase.execute(Unit), + getSpacesFromEveryAccountUseCaseAsStream.execute(Unit) + ) { transfers: List, spaces: List -> + transfers.map { transfer -> + val spaceForTransfer = spaces.firstOrNull { space -> transfer.spaceId == space.id && transfer.accountName == space.accountName } + Pair(transfer, spaceForTransfer) + } + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = emptyList() + ) private var workInfosLiveData = workManagerProvider.getRunningUploadsWorkInfosLiveData() - private val _spaces: MutableStateFlow> = MutableStateFlow(emptyList()) - val spaces: StateFlow> - get() = _spaces - init { - _transfersListLiveData.addSource(transfersLiveData) { transfers -> - _transfersListLiveData.postValue(transfers) - } _workInfosListLiveData.addSource(workInfosLiveData) { workInfos -> _workInfosListLiveData.postValue(workInfos) } - viewModelScope.launch(coroutinesDispatcherProvider.io) { - val spacesList = getSpacesFromEveryAccountUseCase.execute(Unit) - _spaces.update { spacesList } - } } fun uploadFilesFromContentUri( diff --git a/owncloudData/build.gradle b/owncloudData/build.gradle index fad65f4425f..f7dfdc315f2 100644 --- a/owncloudData/build.gradle +++ b/owncloudData/build.gradle @@ -71,6 +71,7 @@ dependencies { // Dependencies for instrumented tests androidTestImplementation project(":owncloudTestUtil") + androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$orgJetbrainsKotlinx" androidTestImplementation "androidx.test:runner:$androidxTest" androidTestImplementation "androidx.test.espresso:espresso-core:$androidxTestEspresso" androidTestImplementation "androidx.test.ext:junit:$androidxTestExt" diff --git a/owncloudData/src/androidTest/java/com/owncloud/android/data/spaces/db/SpacesDaoTest.kt b/owncloudData/src/androidTest/java/com/owncloud/android/data/spaces/db/SpacesDaoTest.kt index 3ef489e5f05..cb07acce53f 100644 --- a/owncloudData/src/androidTest/java/com/owncloud/android/data/spaces/db/SpacesDaoTest.kt +++ b/owncloudData/src/androidTest/java/com/owncloud/android/data/spaces/db/SpacesDaoTest.kt @@ -26,16 +26,21 @@ import androidx.test.platform.app.InstrumentationRegistry import com.owncloud.android.data.OwncloudDatabase import com.owncloud.android.data.spaces.datasources.implementation.OCLocalSpacesDataSource.Companion.toEntity import com.owncloud.android.data.spaces.datasources.implementation.OCLocalSpacesDataSource.Companion.toModel +import com.owncloud.android.domain.spaces.model.OCSpace.Companion.DRIVE_TYPE_PROJECT import com.owncloud.android.testutil.OC_SPACE_PROJECT_WITHOUT_IMAGE import com.owncloud.android.testutil.OC_SPACE_PROJECT_WITH_IMAGE import com.owncloud.android.testutil.OC_SPACE_SPECIAL_IMAGE import com.owncloud.android.testutil.OC_SPACE_SPECIAL_README +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Rule import org.junit.Test +@OptIn(ExperimentalCoroutinesApi::class) @MediumTest class SpacesDaoTest { @Rule @@ -53,7 +58,7 @@ class SpacesDaoTest { } @Test - fun insertOrDeleteSpacesWithEmptyDatabase() { + fun insertOrDeleteSpacesWithEmptyDatabase() = runTest { val accountName = OC_SPACE_PROJECT_WITHOUT_IMAGE.accountName val specialsToInsert = listOf( @@ -68,7 +73,10 @@ class SpacesDaoTest { spacesDao.insertOrDeleteSpaces(spacesToInsert, specialsToInsert) - val spacesInDatabase = spacesDao.getProjectSpacesWithSpecialsForAccount(accountName).map { it.toModel() } + val spacesInDatabase = spacesDao.getSpacesByDriveTypeWithSpecialsForAccountAsFlow( + accountName = accountName, + filterDriveTypes = setOf(DRIVE_TYPE_PROJECT), + ).first().map { it.toModel() } assertNotNull(spacesInDatabase) assertEquals(1, spacesInDatabase.size) @@ -76,7 +84,7 @@ class SpacesDaoTest { } @Test - fun insertOrDeleteSpacesWithSpacesAlreadyInDatabaseNotAttachedToAccountAnymore() { + fun insertOrDeleteSpacesWithSpacesAlreadyInDatabaseNotAttachedToAccountAnymore() = runTest { val accountName = OC_SPACE_PROJECT_WITHOUT_IMAGE.accountName val specialsAlreadyInDatabaseToInsert = listOf( @@ -90,7 +98,10 @@ class SpacesDaoTest { spacesDao.insertOrDeleteSpaces(spacesAlreadyInDatabaseToInsert, specialsAlreadyInDatabaseToInsert) - val spacesAlreadyInDatabase = spacesDao.getProjectSpacesWithSpecialsForAccount(accountName) + val spacesAlreadyInDatabase = spacesDao.getSpacesByDriveTypeWithSpecialsForAccountAsFlow( + accountName = accountName, + filterDriveTypes = setOf(DRIVE_TYPE_PROJECT), + ).first() assertEquals(1, spacesAlreadyInDatabase.size) assertEquals(2, spacesAlreadyInDatabase[0].specials.size) @@ -107,7 +118,11 @@ class SpacesDaoTest { spacesDao.insertOrDeleteSpaces(newSpacesToInsert, newSpecialsToInsert) - val spacesInDatabaseEntity = spacesDao.getProjectSpacesWithSpecialsForAccount(accountName) + val spacesInDatabaseEntity = spacesDao.getSpacesByDriveTypeWithSpecialsForAccountAsFlow( + accountName = accountName, + filterDriveTypes = setOf(DRIVE_TYPE_PROJECT), + ).first() + val spacesInDatabase = spacesInDatabaseEntity.map { it.toModel() } val specialsInDatabase = spacesInDatabaseEntity.flatMap { it.specials } @@ -118,7 +133,7 @@ class SpacesDaoTest { } @Test - fun insertOrDeleteSpacesWithSpacesAlreadyInDatabaseStillAttachedToAccount() { + fun insertOrDeleteSpacesWithSpacesAlreadyInDatabaseStillAttachedToAccount() = runTest { val accountName = OC_SPACE_PROJECT_WITHOUT_IMAGE.accountName val specialsAlreadyInDatabaseToInsert = listOf( @@ -132,7 +147,10 @@ class SpacesDaoTest { spacesDao.insertOrDeleteSpaces(spacesAlreadyInDatabaseToInsert, specialsAlreadyInDatabaseToInsert) - val spacesAlreadyInDatabase = spacesDao.getProjectSpacesWithSpecialsForAccount(accountName) + val spacesAlreadyInDatabase = spacesDao.getSpacesByDriveTypeWithSpecialsForAccountAsFlow( + accountName = accountName, + filterDriveTypes = setOf(DRIVE_TYPE_PROJECT), + ).first() assertEquals(1, spacesAlreadyInDatabase.size) assertEquals(2, spacesAlreadyInDatabase[0].specials.size) @@ -151,7 +169,10 @@ class SpacesDaoTest { spacesDao.insertOrDeleteSpaces(newSpacesToInsert, newSpecialsToInsert) - val spacesInDatabase = spacesDao.getProjectSpacesWithSpecialsForAccount(accountName) + val spacesInDatabase = spacesDao.getSpacesByDriveTypeWithSpecialsForAccountAsFlow( + accountName = accountName, + filterDriveTypes = setOf(DRIVE_TYPE_PROJECT), + ).first() val specialsInDatabase = spacesInDatabase.flatMap { it.specials } assertNotNull(spacesInDatabase) 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 bf57a3c2a62..025dc888efa 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 @@ -26,6 +26,7 @@ import com.owncloud.android.data.files.datasources.LocalFileDataSource import com.owncloud.android.data.files.db.FileDao import com.owncloud.android.data.files.db.OCFileAndFileSync import com.owncloud.android.data.files.db.OCFileEntity +import com.owncloud.android.data.spaces.datasources.implementation.OCLocalSpacesDataSource.Companion.toModel import com.owncloud.android.domain.availableoffline.model.AvailableOfflineStatus import com.owncloud.android.domain.files.model.MIME_DIR import com.owncloud.android.domain.files.model.MIME_PREFIX_IMAGE @@ -263,5 +264,6 @@ class OCLocalFileDataSource( uploadWorkerUuid = fileSync?.uploadWorkerUuid, downloadWorkerUuid = fileSync?.downloadWorkerUuid, isSynchronizing = fileSync?.isSynchronizing == true, + space = space?.toModel(), ) } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/db/OCFileAndFileSync.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/db/OCFileAndFileSync.kt index f3535dc6e7d..6f33aee45a4 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/files/db/OCFileAndFileSync.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/db/OCFileAndFileSync.kt @@ -22,6 +22,7 @@ package com.owncloud.android.data.files.db import androidx.room.Embedded import androidx.room.Relation +import com.owncloud.android.data.spaces.db.SpacesEntity data class OCFileAndFileSync( @Embedded val file: OCFileEntity, @@ -29,5 +30,10 @@ data class OCFileAndFileSync( parentColumn = "id", entityColumn = "fileId" ) - val fileSync: OCFileSyncEntity? + val fileSync: OCFileSyncEntity?, + @Relation( + parentColumn = "spaceId", + entityColumn = "space_id" + ) + val space: SpacesEntity? = null, ) diff --git a/owncloudData/src/main/java/com/owncloud/android/data/spaces/datasources/LocalSpacesDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/spaces/datasources/LocalSpacesDataSource.kt index 28360fecf33..3dfe328fb46 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/spaces/datasources/LocalSpacesDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/spaces/datasources/LocalSpacesDataSource.kt @@ -28,9 +28,8 @@ interface LocalSpacesDataSource { fun saveSpacesForAccount(listOfSpaces: List) fun getPersonalSpaceForAccount(accountName: String): OCSpace? fun getSharesSpaceForAccount(accountName: String): OCSpace? - fun getSpacesFromEveryAccount(): List - fun getProjectSpacesWithSpecialsForAccountAsFlow(accountName: String): Flow> - fun getPersonalAndProjectSpacesWithSpecialsForAccountAsFlow(accountName: String): Flow> + fun getSpacesFromEveryAccountAsStream(): Flow> + fun getSpacesByDriveTypeWithSpecialsForAccountAsFlow(accountName: String, filterDriveTypes: Set): Flow> fun getPersonalAndProjectSpacesForAccount(accountName: String): List fun getSpaceWithSpecialsByIdForAccount(spaceId: String?, accountName: String): OCSpace fun getWebDavUrlForSpace(spaceId: String?, accountName: String): String? diff --git a/owncloudData/src/main/java/com/owncloud/android/data/spaces/datasources/implementation/OCLocalSpacesDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/spaces/datasources/implementation/OCLocalSpacesDataSource.kt index 7858efee1e7..f06738e7c8d 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/spaces/datasources/implementation/OCLocalSpacesDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/spaces/datasources/implementation/OCLocalSpacesDataSource.kt @@ -30,6 +30,9 @@ import com.owncloud.android.data.spaces.db.SpacesDao import com.owncloud.android.data.spaces.db.SpacesEntity import com.owncloud.android.data.spaces.db.SpacesWithSpecials import com.owncloud.android.domain.spaces.model.OCSpace +import com.owncloud.android.domain.spaces.model.OCSpace.Companion.DRIVE_TYPE_PERSONAL +import com.owncloud.android.domain.spaces.model.OCSpace.Companion.DRIVE_TYPE_PROJECT +import com.owncloud.android.domain.spaces.model.OCSpace.Companion.SPACE_ID_SHARES import com.owncloud.android.domain.spaces.model.SpaceDeleted import com.owncloud.android.domain.spaces.model.SpaceFile import com.owncloud.android.domain.spaces.model.SpaceOwner @@ -60,27 +63,32 @@ class OCLocalSpacesDataSource( } override fun getPersonalSpaceForAccount(accountName: String): OCSpace? { - return spacesDao.getPersonalSpaceForAccount(accountName)?.toModel() + return spacesDao.getSpacesByDriveTypeForAccount( + accountName = accountName, + filterDriveTypes = setOf(DRIVE_TYPE_PERSONAL) + ).map { it.toModel() }.firstOrNull() } override fun getSharesSpaceForAccount(accountName: String): OCSpace? { - return spacesDao.getSharesSpaceForAccount(accountName)?.toModel() + return spacesDao.getSpaceByIdForAccount(spaceId = SPACE_ID_SHARES, accountName = accountName)?.toModel() } - override fun getSpacesFromEveryAccount(): List { - return spacesDao.getSpacesFromEveryAccount().map { it.toModel() } - } - - override fun getProjectSpacesWithSpecialsForAccountAsFlow(accountName: String): Flow> { - return spacesDao.getProjectSpacesWithSpecialsForAccountAsFlow(accountName).map { spacesWithSpecialsEntitiesList -> - spacesWithSpecialsEntitiesList.map { spacesWithSpecialsEntity -> - spacesWithSpecialsEntity.toModel() - } + override fun getSpacesFromEveryAccountAsStream(): Flow> { + return spacesDao.getSpacesByDriveTypeFromEveryAccountAsStream( + filterDriveTypes = setOf(DRIVE_TYPE_PERSONAL, DRIVE_TYPE_PROJECT) + ).map { spaceEntities -> + spaceEntities.map { spaceEntity -> spaceEntity.toModel() } } } - override fun getPersonalAndProjectSpacesWithSpecialsForAccountAsFlow(accountName: String): Flow> { - return spacesDao.getPersonalAndProjectSpacesWithSpecialsForAccountAsFlow(accountName).map { spacesWithSpecialsEntitiesList -> + override fun getSpacesByDriveTypeWithSpecialsForAccountAsFlow( + accountName: String, + filterDriveTypes: Set, + ): Flow> { + return spacesDao.getSpacesByDriveTypeWithSpecialsForAccountAsFlow( + accountName = accountName, + filterDriveTypes = filterDriveTypes, + ).map { spacesWithSpecialsEntitiesList -> spacesWithSpecialsEntitiesList.map { spacesWithSpecialsEntity -> spacesWithSpecialsEntity.toModel() } @@ -88,7 +96,10 @@ class OCLocalSpacesDataSource( } override fun getPersonalAndProjectSpacesForAccount(accountName: String): List { - return spacesDao.getPersonalAndProjectSpacesForAccount(accountName).map { it.toModel() } + return spacesDao.getSpacesByDriveTypeForAccount( + accountName = accountName, + filterDriveTypes = setOf(DRIVE_TYPE_PERSONAL, DRIVE_TYPE_PROJECT), + ).map { it.toModel() } } override fun getSpaceWithSpecialsByIdForAccount(spaceId: String?, accountName: String): OCSpace { diff --git a/owncloudData/src/main/java/com/owncloud/android/data/spaces/db/SpacesDao.kt b/owncloudData/src/main/java/com/owncloud/android/data/spaces/db/SpacesDao.kt index a8597151b3a..dd8f796ffb3 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/spaces/db/SpacesDao.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/spaces/db/SpacesDao.kt @@ -30,9 +30,6 @@ import com.owncloud.android.data.spaces.db.SpacesEntity.Companion.SPACES_ACCOUNT import com.owncloud.android.data.spaces.db.SpacesEntity.Companion.SPACES_DRIVE_TYPE import com.owncloud.android.data.spaces.db.SpacesEntity.Companion.SPACES_ID import com.owncloud.android.data.spaces.db.SpacesEntity.Companion.SPACES_ROOT_WEB_DAV_URL -import com.owncloud.android.domain.spaces.model.OCSpace.Companion.DRIVE_TYPE_PERSONAL -import com.owncloud.android.domain.spaces.model.OCSpace.Companion.DRIVE_TYPE_PROJECT -import com.owncloud.android.domain.spaces.model.OCSpace.Companion.SPACE_ID_SHARES import kotlinx.coroutines.flow.Flow @Dao @@ -65,45 +62,27 @@ interface SpacesDao { @Upsert fun upsertSpecials(listOfSpecialEntities: List) - @Query(SELECT_ALL_SPACES) - fun getSpacesFromEveryAccount(): List + @Query(SELECT_SPACES_BY_DRIVE_TYPE) + fun getSpacesByDriveTypeFromEveryAccountAsStream( + filterDriveTypes: Set, + ): Flow> @Query(SELECT_ALL_SPACES_FOR_ACCOUNT) fun getAllSpacesForAccount( accountName: String, ): List - @Query(SELECT_PERSONAL_SPACE_FOR_ACCOUNT) - fun getPersonalSpaceForAccount( - accountName: String, - ): SpacesEntity? - - @Query(SELECT_SHARES_SPACE_FOR_ACCOUNT) - fun getSharesSpaceForAccount( - accountName: String, - ): SpacesEntity? - - @Transaction - @Query(SELECT_PROJECT_SPACES_FOR_ACCOUNT) - fun getProjectSpacesWithSpecialsForAccount( - accountName: String, - ): List - - @Transaction - @Query(SELECT_PROJECT_SPACES_FOR_ACCOUNT) - fun getProjectSpacesWithSpecialsForAccountAsFlow( - accountName: String, - ): Flow> - - @Query(SELECT_PERSONAL_AND_PROJECT_SPACES_FOR_ACCOUNT) - fun getPersonalAndProjectSpacesForAccount( + @Query(SELECT_SPACES_BY_DRIVE_TYPE_FOR_ACCOUNT) + fun getSpacesByDriveTypeForAccount( accountName: String, + filterDriveTypes: Set, ): List @Transaction - @Query(SELECT_PERSONAL_AND_PROJECT_SPACES_FOR_ACCOUNT) - fun getPersonalAndProjectSpacesWithSpecialsForAccountAsFlow( + @Query(SELECT_SPACES_BY_DRIVE_TYPE_FOR_ACCOUNT) + fun getSpacesByDriveTypeWithSpecialsForAccountAsFlow( accountName: String, + filterDriveTypes: Set, ): Flow> @Transaction @@ -113,6 +92,12 @@ interface SpacesDao { accountName: String, ): SpacesWithSpecials + @Query(SELECT_SPACE_BY_ID_FOR_ACCOUNT) + fun getSpaceByIdForAccount( + spaceId: String?, + accountName: String, + ): SpacesEntity? + @Query(SELECT_WEB_DAV_URL_FOR_SPACE) fun getWebDavUrlForSpace( spaceId: String?, @@ -126,11 +111,10 @@ interface SpacesDao { fun deleteSpaceForAccountById(accountName: String, spaceId: String) companion object { - // TODO: Shares space (last OR) to be deleted from this query when adding the space to the file entity - private const val SELECT_ALL_SPACES = """ + private const val SELECT_SPACES_BY_DRIVE_TYPE = """ SELECT * FROM ${ProviderMeta.ProviderTableMeta.SPACES_TABLE_NAME} - WHERE $SPACES_DRIVE_TYPE LIKE '$DRIVE_TYPE_PROJECT' OR $SPACES_DRIVE_TYPE LIKE '$DRIVE_TYPE_PERSONAL' OR $SPACES_ID LIKE '$SPACE_ID_SHARES' + WHERE $SPACES_DRIVE_TYPE IN (:filterDriveTypes) """ private const val SELECT_ALL_SPACES_FOR_ACCOUNT = """ @@ -139,29 +123,10 @@ interface SpacesDao { WHERE $SPACES_ACCOUNT_NAME = :accountName """ - private const val SELECT_PERSONAL_SPACE_FOR_ACCOUNT = """ - SELECT * - FROM ${ProviderMeta.ProviderTableMeta.SPACES_TABLE_NAME} - WHERE $SPACES_ACCOUNT_NAME = :accountName AND $SPACES_DRIVE_TYPE LIKE '$DRIVE_TYPE_PERSONAL' - """ - - private const val SELECT_SHARES_SPACE_FOR_ACCOUNT = """ - SELECT * - FROM ${ProviderMeta.ProviderTableMeta.SPACES_TABLE_NAME} - WHERE $SPACES_ACCOUNT_NAME = :accountName AND $SPACES_ID LIKE '$SPACE_ID_SHARES' - """ - - private const val SELECT_PROJECT_SPACES_FOR_ACCOUNT = """ - SELECT * - FROM ${ProviderMeta.ProviderTableMeta.SPACES_TABLE_NAME} - WHERE $SPACES_ACCOUNT_NAME = :accountName AND $SPACES_DRIVE_TYPE LIKE '$DRIVE_TYPE_PROJECT' - ORDER BY name COLLATE NOCASE ASC - """ - - private const val SELECT_PERSONAL_AND_PROJECT_SPACES_FOR_ACCOUNT = """ + private const val SELECT_SPACES_BY_DRIVE_TYPE_FOR_ACCOUNT = """ SELECT * FROM ${ProviderMeta.ProviderTableMeta.SPACES_TABLE_NAME} - WHERE $SPACES_ACCOUNT_NAME = :accountName AND ($SPACES_DRIVE_TYPE LIKE '$DRIVE_TYPE_PROJECT' OR $SPACES_DRIVE_TYPE LIKE '$DRIVE_TYPE_PERSONAL') + WHERE $SPACES_ACCOUNT_NAME = :accountName AND ($SPACES_DRIVE_TYPE IN (:filterDriveTypes)) ORDER BY $SPACES_DRIVE_TYPE ASC, name COLLATE NOCASE ASC """ diff --git a/owncloudData/src/main/java/com/owncloud/android/data/spaces/repository/OCSpacesRepository.kt b/owncloudData/src/main/java/com/owncloud/android/data/spaces/repository/OCSpacesRepository.kt index 63cae605dcc..e5a2233f980 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/spaces/repository/OCSpacesRepository.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/spaces/repository/OCSpacesRepository.kt @@ -35,14 +35,11 @@ class OCSpacesRepository( } } - override fun getSpacesFromEveryAccount() = - localSpacesDataSource.getSpacesFromEveryAccount() + override fun getSpacesFromEveryAccountAsStream() = + localSpacesDataSource.getSpacesFromEveryAccountAsStream() - override fun getProjectSpacesWithSpecialsForAccountAsFlow(accountName: String) = - localSpacesDataSource.getProjectSpacesWithSpecialsForAccountAsFlow(accountName) - - override fun getPersonalAndProjectSpacesWithSpecialsForAccountAsFlow(accountName: String) = - localSpacesDataSource.getPersonalAndProjectSpacesWithSpecialsForAccountAsFlow(accountName) + override fun getSpacesByDriveTypeWithSpecialsForAccountAsFlow(accountName: String, filterDriveTypes: Set) = + localSpacesDataSource.getSpacesByDriveTypeWithSpecialsForAccountAsFlow(accountName = accountName, filterDriveTypes = filterDriveTypes) override fun getPersonalAndProjectSpacesForAccount(accountName: String) = localSpacesDataSource.getPersonalAndProjectSpacesForAccount(accountName) diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt index 21b13e3a673..4662bb6c452 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt @@ -20,10 +20,10 @@ package com.owncloud.android.data.transfers.datasources -import androidx.lifecycle.LiveData import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferResult import com.owncloud.android.domain.transfers.model.TransferStatus +import kotlinx.coroutines.flow.Flow interface LocalTransferDataSource { fun saveTransfer(transfer: OCTransfer): Long @@ -48,7 +48,7 @@ interface LocalTransferDataSource { fun deleteAllTransfersFromAccount(accountName: String) fun getTransferById(id: Long): OCTransfer? fun getAllTransfers(): List - fun getAllTransfersAsLiveData(): LiveData> + fun getAllTransfersAsStream(): Flow> fun getLastTransferFor(remotePath: String, accountName: String): OCTransfer? fun getCurrentAndPendingTransfers(): List fun getFailedTransfers(): List diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt index 529c84fdb6b..05104379ae8 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt @@ -20,8 +20,6 @@ package com.owncloud.android.data.transfers.datasources.implementation -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations import com.owncloud.android.data.transfers.datasources.LocalTransferDataSource import com.owncloud.android.data.transfers.db.OCTransferEntity import com.owncloud.android.data.transfers.db.TransferDao @@ -30,6 +28,8 @@ import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferResult import com.owncloud.android.domain.transfers.model.TransferStatus import com.owncloud.android.domain.transfers.model.UploadEnqueuedBy +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map class OCLocalTransferDataSource( private val transferDao: TransferDao @@ -89,8 +89,8 @@ class OCLocalTransferDataSource( } } - override fun getAllTransfersAsLiveData(): LiveData> { - return Transformations.map(transferDao.getAllTransfersAsLiveData()) { transferEntitiesList -> + override fun getAllTransfersAsStream(): Flow> { + return transferDao.getAllTransfersAsStream().map { transferEntitiesList -> val transfers = transferEntitiesList.map { transferEntity -> transferEntity.toModel() } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt index 344d696f37c..ce4b17e8bdc 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt @@ -20,12 +20,12 @@ package com.owncloud.android.data.transfers.db -import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.TRANSFERS_TABLE_NAME +import kotlinx.coroutines.flow.Flow @Dao interface TransferDao { @@ -42,7 +42,7 @@ interface TransferDao { fun getAllTransfers(): List @Query(SELECT_ALL_TRANSFERS) - fun getAllTransfersAsLiveData(): LiveData> + fun getAllTransfersAsStream(): Flow> @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertOrReplace(ocTransferEntity: OCTransferEntity): Long diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt index e8824b9e577..00f5e196fdc 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt @@ -20,12 +20,12 @@ package com.owncloud.android.data.transfers.repository -import androidx.lifecycle.LiveData import com.owncloud.android.data.transfers.datasources.LocalTransferDataSource import com.owncloud.android.domain.transfers.TransferRepository import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferResult import com.owncloud.android.domain.transfers.model.TransferStatus +import kotlinx.coroutines.flow.Flow class OCTransferRepository( private val localTransferDataSource: LocalTransferDataSource @@ -86,8 +86,8 @@ class OCTransferRepository( override fun getAllTransfers(): List = localTransferDataSource.getAllTransfers() - override fun getAllTransfersAsLiveData(): LiveData> = - localTransferDataSource.getAllTransfersAsLiveData() + override fun getAllTransfersAsStream(): Flow> = + localTransferDataSource.getAllTransfersAsStream() override fun getLastTransferFor(remotePath: String, accountName: String) = localTransferDataSource.getLastTransferFor(remotePath = remotePath, accountName = accountName) diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/files/model/OCFileWithSyncInfo.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/model/OCFileWithSyncInfo.kt index 2d9fb49862e..fa561de7205 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/files/model/OCFileWithSyncInfo.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/files/model/OCFileWithSyncInfo.kt @@ -20,14 +20,13 @@ package com.owncloud.android.domain.files.model -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.owncloud.android.domain.spaces.model.OCSpace import java.util.UUID -@Parcelize data class OCFileWithSyncInfo( val file: OCFile, val uploadWorkerUuid: UUID? = null, val downloadWorkerUuid: UUID? = null, - val isSynchronizing: Boolean = false -) : Parcelable + val isSynchronizing: Boolean = false, + val space: OCSpace? = null, +) diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/SpacesRepository.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/SpacesRepository.kt index 7f02afd7f3f..14ed75cf7b1 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/SpacesRepository.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/SpacesRepository.kt @@ -26,9 +26,8 @@ import kotlinx.coroutines.flow.Flow interface SpacesRepository { fun refreshSpacesForAccount(accountName: String) - fun getSpacesFromEveryAccount(): List - fun getProjectSpacesWithSpecialsForAccountAsFlow(accountName: String): Flow> - fun getPersonalAndProjectSpacesWithSpecialsForAccountAsFlow(accountName: String): Flow> + fun getSpacesFromEveryAccountAsStream(): Flow> + fun getSpacesByDriveTypeWithSpecialsForAccountAsFlow(accountName: String, filterDriveTypes: Set): Flow> fun getPersonalAndProjectSpacesForAccount(accountName: String): List fun getSpaceWithSpecialsByIdForAccount(spaceId: String?, accountName: String): OCSpace fun getWebDavUrlForSpace(accountName: String, spaceId: String?): String? diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase.kt index 9f93428eaeb..c98f872d3e2 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase.kt @@ -29,7 +29,10 @@ class GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase( private val spacesRepository: SpacesRepository ) : BaseUseCase>, GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase.Params>() { - override fun run(params: Params) = spacesRepository.getPersonalAndProjectSpacesWithSpecialsForAccountAsFlow(params.accountName) + override fun run(params: Params) = spacesRepository.getSpacesByDriveTypeWithSpecialsForAccountAsFlow( + accountName = params.accountName, + filterDriveTypes = setOf(OCSpace.DRIVE_TYPE_PERSONAL, OCSpace.DRIVE_TYPE_PROJECT), + ) data class Params( val accountName: String diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetProjectSpacesWithSpecialsForAccountAsStreamUseCase.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetProjectSpacesWithSpecialsForAccountAsStreamUseCase.kt index 92f3db4f63d..141c9626782 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetProjectSpacesWithSpecialsForAccountAsStreamUseCase.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetProjectSpacesWithSpecialsForAccountAsStreamUseCase.kt @@ -23,13 +23,17 @@ package com.owncloud.android.domain.spaces.usecases import com.owncloud.android.domain.BaseUseCase import com.owncloud.android.domain.spaces.SpacesRepository import com.owncloud.android.domain.spaces.model.OCSpace +import com.owncloud.android.domain.spaces.model.OCSpace.Companion.DRIVE_TYPE_PROJECT import kotlinx.coroutines.flow.Flow class GetProjectSpacesWithSpecialsForAccountAsStreamUseCase( private val spacesRepository: SpacesRepository ) : BaseUseCase>, GetProjectSpacesWithSpecialsForAccountAsStreamUseCase.Params>() { - override fun run(params: Params) = spacesRepository.getProjectSpacesWithSpecialsForAccountAsFlow(params.accountName) + override fun run(params: Params) = spacesRepository.getSpacesByDriveTypeWithSpecialsForAccountAsFlow( + accountName = params.accountName, + filterDriveTypes = setOf(DRIVE_TYPE_PROJECT), + ) data class Params( val accountName: String diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetSpacesFromEveryAccountUseCase.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetSpacesFromEveryAccountUseCaseAsStream.kt similarity index 84% rename from owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetSpacesFromEveryAccountUseCase.kt rename to owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetSpacesFromEveryAccountUseCaseAsStream.kt index c0f7ffe5ac0..512b714a4e6 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetSpacesFromEveryAccountUseCase.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/spaces/usecases/GetSpacesFromEveryAccountUseCaseAsStream.kt @@ -23,10 +23,11 @@ package com.owncloud.android.domain.spaces.usecases import com.owncloud.android.domain.BaseUseCase import com.owncloud.android.domain.spaces.SpacesRepository import com.owncloud.android.domain.spaces.model.OCSpace +import kotlinx.coroutines.flow.Flow -class GetSpacesFromEveryAccountUseCase( +class GetSpacesFromEveryAccountUseCaseAsStream( private val spacesRepository: SpacesRepository -) : BaseUseCase, Unit>() { +) : BaseUseCase>, Unit>() { override fun run(params: Unit) = - spacesRepository.getSpacesFromEveryAccount() + spacesRepository.getSpacesFromEveryAccountAsStream() } diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt index f23b7228fb8..23855a3a93c 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt @@ -20,10 +20,10 @@ package com.owncloud.android.domain.transfers -import androidx.lifecycle.LiveData import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferResult import com.owncloud.android.domain.transfers.model.TransferStatus +import kotlinx.coroutines.flow.Flow interface TransferRepository { fun saveTransfer(transfer: OCTransfer): Long @@ -37,16 +37,18 @@ interface TransferRepository { transferEndTimestamp: Long, lastResult: TransferResult ) + fun updateTransferStorageDirectoryInLocalPath( id: Long, oldDirectory: String, newDirectory: String ) + fun deleteTransferById(id: Long) fun deleteAllTransfersFromAccount(accountName: String) fun getTransferById(id: Long): OCTransfer? fun getAllTransfers(): List - fun getAllTransfersAsLiveData(): LiveData> + fun getAllTransfersAsStream(): Flow> fun getLastTransferFor(remotePath: String, accountName: String): OCTransfer? fun getCurrentAndPendingTransfers(): List fun getFailedTransfers(): List diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/GetAllTransfersAsLiveDataUseCase.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/GetAllTransfersAsStreamUseCase.kt similarity index 80% rename from owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/GetAllTransfersAsLiveDataUseCase.kt rename to owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/GetAllTransfersAsStreamUseCase.kt index 61f1e52241f..38a055c5d85 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/GetAllTransfersAsLiveDataUseCase.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/GetAllTransfersAsStreamUseCase.kt @@ -20,15 +20,15 @@ package com.owncloud.android.domain.transfers.usecases -import androidx.lifecycle.LiveData import com.owncloud.android.domain.BaseUseCase import com.owncloud.android.domain.transfers.TransferRepository import com.owncloud.android.domain.transfers.model.OCTransfer +import kotlinx.coroutines.flow.Flow -class GetAllTransfersAsLiveDataUseCase( +class GetAllTransfersAsStreamUseCase( private val transferRepository: TransferRepository, -) : BaseUseCase>, Unit>() { - override fun run(params: Unit): LiveData> = - transferRepository.getAllTransfersAsLiveData() +) : BaseUseCase>, Unit>() { + override fun run(params: Unit): Flow> = + transferRepository.getAllTransfersAsStream() }