diff --git a/app/src/main/java/com/infomaniak/drive/ui/publicShare/OnPublicShareItemClickListener.kt b/app/src/main/java/com/infomaniak/drive/ui/publicShare/OnPublicShareItemClickListener.kt index a3fe13bd72..5487b82bb3 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/publicShare/OnPublicShareItemClickListener.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/publicShare/OnPublicShareItemClickListener.kt @@ -17,19 +17,25 @@ */ package com.infomaniak.drive.ui.publicShare +import android.content.Intent import androidx.annotation.StringRes +import androidx.core.content.FileProvider +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope import com.infomaniak.drive.R import com.infomaniak.drive.data.models.File import com.infomaniak.drive.ui.fileList.BaseDownloadProgressDialog.DownloadAction import com.infomaniak.drive.ui.fileList.preview.PreviewDownloadProgressDialogArgs import com.infomaniak.drive.ui.fileList.preview.PreviewPDFHandler -import com.infomaniak.drive.utils.DrivePermissions -import com.infomaniak.drive.utils.IOFile +import com.infomaniak.drive.utils.* +import com.infomaniak.drive.utils.FilePresenter.openBookmarkIntent +import com.infomaniak.drive.utils.Utils.openWith import com.infomaniak.drive.views.FileInfoActionsView import com.infomaniak.drive.views.FileInfoActionsView.OnItemClickListener.Companion.downloadFile import com.infomaniak.lib.core.utils.safeNavigate import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import kotlinx.coroutines.invoke +import kotlinx.coroutines.launch interface OnPublicShareItemClickListener : FileInfoActionsView.OnItemClickListener { @@ -41,11 +47,19 @@ interface OnPublicShareItemClickListener : FileInfoActionsView.OnItemClickListen fun onDownloadSuccess() fun onDownloadError(@StringRes errorMessage: Int) - override fun openWith() = executeActionAndClose(DownloadAction.OPEN_WITH) + fun observeCacheFileForAction(viewLifecycleOwner: LifecycleOwner) { + viewLifecycleOwner.lifecycleScope.launch { + publicShareViewModel.fetchCacheFileForActionResult.collect { (cacheFile, action) -> + cacheFile?.let { file -> executeDownloadAction(action, file) } ?: onDownloadError(getErrorMessage(action)) + } + } + } - override fun shareFile() = executeActionAndClose(DownloadAction.SEND_COPY) + override fun openWith() = startAction(DownloadAction.OPEN_WITH) - override fun saveToKDrive() = executeActionAndClose(DownloadAction.SAVE_TO_DRIVE) + override fun shareFile() = startAction(DownloadAction.SEND_COPY) + + override fun saveToKDrive() = startAction(DownloadAction.SAVE_TO_DRIVE) override fun downloadFileClicked() { super.downloadFileClicked() @@ -56,12 +70,20 @@ interface OnPublicShareItemClickListener : FileInfoActionsView.OnItemClickListen super.printClicked() previewPDFHandler?.printClicked( context = currentContext, - onDefaultCase = { executeActionAndClose(DownloadAction.PRINT_PDF, R.string.errorFileNotFound) }, + onDefaultCase = { startAction(DownloadAction.PRINT_PDF) }, onError = { onDownloadError(R.string.errorFileNotFound) }, ) } - private suspend fun navigateToDownloadDialog() = withContext(Dispatchers.Main) { + private fun startAction(action: DownloadAction) { + publicShareViewModel.fetchCacheFileForAction( + file = currentFile, + action = action, + navigateToDownloadDialog = ::navigateToDownloadDialog, + ) + } + + private suspend fun navigateToDownloadDialog() = Dispatchers.Main { currentFile?.let { file -> ownerFragment?.safeNavigate( resId = R.id.previewDownloadProgressDialog, @@ -70,15 +92,27 @@ interface OnPublicShareItemClickListener : FileInfoActionsView.OnItemClickListen } } - private fun executeActionAndClose(action: DownloadAction, @StringRes errorMessageId: Int = R.string.errorDownload) { - publicShareViewModel.executeDownloadAction( - activityContext = currentContext, - downloadAction = action, - file = currentFile, - navigateToDownloadDialog = ::navigateToDownloadDialog, - onDownloadSuccess = ::onDownloadSuccess, - onDownloadError = { onDownloadError(errorMessageId) }, - ) + private fun executeDownloadAction(downloadAction: DownloadAction, cacheFile: IOFile) = runCatching { + val uri = FileProvider.getUriForFile(currentContext, currentContext.getString(R.string.FILE_AUTHORITY), cacheFile) + + when (downloadAction) { + DownloadAction.OPEN_WITH -> { + currentContext.openWith(uri, currentFile?.getMimeType(), Intent.FLAG_GRANT_READ_URI_PERMISSION) + } + DownloadAction.SEND_COPY -> currentContext.shareFile { uri } + DownloadAction.SAVE_TO_DRIVE -> currentContext.saveToKDrive(uri) + DownloadAction.OPEN_BOOKMARK -> currentContext.openBookmarkIntent(cacheFile.name, uri) + DownloadAction.PRINT_PDF -> currentContext.printPdf(cacheFile) + } + + onDownloadSuccess() + }.onFailure { exception -> + exception.printStackTrace() + onDownloadError(getErrorMessage(downloadAction)) + } + + private fun getErrorMessage(downloadAction: DownloadAction): Int { + return if (downloadAction == DownloadAction.PRINT_PDF) R.string.errorFileNotFound else R.string.errorDownload } override fun displayInfoClicked() = Unit diff --git a/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareFileActionsBottomSheetDialog.kt b/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareFileActionsBottomSheetDialog.kt index fe9e894d8b..c6bcf6f1d4 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareFileActionsBottomSheetDialog.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareFileActionsBottomSheetDialog.kt @@ -69,6 +69,8 @@ class PublicShareFileActionsBottomSheetDialog : BottomSheetDialogFragment(), OnP drivePermissions.registerPermissions(this@PublicShareFileActionsBottomSheetDialog) { authorized -> if (authorized) downloadFileClicked() } + + observeCacheFileForAction(viewLifecycleOwner) } private fun initBottomSheet() = with(binding.publicShareFileActionsView) { diff --git a/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareListFragment.kt b/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareListFragment.kt index a908fe6862..1789980d05 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareListFragment.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareListFragment.kt @@ -24,8 +24,10 @@ import android.view.View import android.view.ViewGroup import androidx.activity.addCallback import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult +import androidx.core.content.FileProvider import androidx.core.view.isGone import androidx.fragment.app.activityViewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.swiperefreshlayout.widget.SwipeRefreshLayout @@ -45,13 +47,16 @@ import com.infomaniak.drive.ui.publicShare.PublicShareViewModel.Companion.ROOT_S import com.infomaniak.drive.utils.AccountUtils import com.infomaniak.drive.utils.DrivePermissions import com.infomaniak.drive.utils.FilePresenter.displayFile +import com.infomaniak.drive.utils.FilePresenter.openBookmarkIntent import com.infomaniak.drive.utils.FilePresenter.openFolder +import com.infomaniak.drive.utils.IOFile import com.infomaniak.drive.views.FileInfoActionsView.OnItemClickListener.Companion.downloadFile import com.infomaniak.lib.core.utils.SnackbarUtils.showSnackbar import com.infomaniak.lib.core.utils.safeNavigate import com.infomaniak.lib.core.utils.whenResultIsOk import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import kotlinx.coroutines.invoke +import kotlinx.coroutines.launch import com.infomaniak.lib.core.R as RCore class PublicShareListFragment : FileListFragment() { @@ -119,6 +124,7 @@ class PublicShareListFragment : FileListFragment() { observeRootFile() observeFiles() + observeBookmarkAction() } private fun initFileAdapter() { @@ -204,6 +210,14 @@ class PublicShareListFragment : FileListFragment() { } } + private fun observeBookmarkAction() { + viewLifecycleOwner.lifecycleScope.launch { + publicShareViewModel.fetchCacheFileForActionResult.collect { (cacheFile, action) -> + if (action == DownloadAction.OPEN_BOOKMARK) executeOpenBookmarkAction(cacheFile) + } + } + } + private fun openFolder(folder: File) { openFolder( file = folder, @@ -215,24 +229,28 @@ class PublicShareListFragment : FileListFragment() { } private fun openBookmark(file: File) { - publicShareViewModel.executeDownloadAction( - activityContext = requireActivity(), - downloadAction = DownloadAction.OPEN_BOOKMARK, + publicShareViewModel.fetchCacheFileForAction( file = file, + action = DownloadAction.OPEN_BOOKMARK, navigateToDownloadDialog = { - withContext(Dispatchers.Main) { + Dispatchers.Main { safeNavigate( resId = R.id.previewDownloadProgressDialog, args = PreviewDownloadProgressDialogArgs(file.name).toBundle(), ) } }, - onDownloadError = { - showSnackbar( - title = R.string.errorGetBookmarkURL, - anchor = (requireActivity() as? PublicShareActivity)?.getMainButton(), - ) - }, + ) + } + + private fun executeOpenBookmarkAction(cacheFile: IOFile?) = runCatching { + val uri = FileProvider.getUriForFile(requireContext(), getString(R.string.FILE_AUTHORITY), cacheFile!!) + requireContext().openBookmarkIntent(cacheFile.name, uri) + }.onFailure { exception -> + exception.printStackTrace() + showSnackbar( + title = R.string.errorGetBookmarkURL, + anchor = (requireActivity() as? PublicShareActivity)?.getMainButton(), ) } diff --git a/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicSharePreviewSliderFragment.kt b/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicSharePreviewSliderFragment.kt index 57258439f5..37b21ee226 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicSharePreviewSliderFragment.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicSharePreviewSliderFragment.kt @@ -91,6 +91,7 @@ class PublicSharePreviewSliderFragment : BasePreviewSliderFragment(), OnPublicSh super.onViewCreated(view, savedInstanceState) initBottomSheet() + observeCacheFileForAction(viewLifecycleOwner) } private fun initBottomSheet() = with(bottomSheetView) { diff --git a/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareViewModel.kt b/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareViewModel.kt index d8bb926b8f..5a562a54e6 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareViewModel.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/publicShare/PublicShareViewModel.kt @@ -17,14 +17,12 @@ */ package com.infomaniak.drive.ui.publicShare -import android.content.Context -import android.content.Intent -import androidx.core.content.FileProvider +import android.app.Application +import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.infomaniak.drive.R +import com.infomaniak.drive.MainApplication import com.infomaniak.drive.data.api.ApiRepository import com.infomaniak.drive.data.api.CursorApiResponse import com.infomaniak.drive.data.cache.FolderFilesProvider.FolderFilesProviderArgs @@ -34,23 +32,27 @@ import com.infomaniak.drive.data.models.File import com.infomaniak.drive.data.models.File.SortType import com.infomaniak.drive.data.models.ShareLink import com.infomaniak.drive.ui.fileList.BaseDownloadProgressDialog.DownloadAction -import com.infomaniak.drive.utils.FilePresenter.openBookmarkIntent -import com.infomaniak.drive.utils.Utils.openWith -import com.infomaniak.drive.utils.printPdf -import com.infomaniak.drive.utils.saveToKDrive -import com.infomaniak.drive.utils.shareFile +import com.infomaniak.drive.utils.IOFile import com.infomaniak.lib.core.models.ApiError import com.infomaniak.lib.core.utils.SentryLog import com.infomaniak.lib.core.utils.SingleLiveEvent import kotlinx.coroutines.* +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.MutableSharedFlow -class PublicShareViewModel(val savedStateHandle: SavedStateHandle) : ViewModel() { +class PublicShareViewModel(application: Application, val savedStateHandle: SavedStateHandle) : AndroidViewModel(application) { + + private val appContext = getApplication() var rootSharedFile = SingleLiveEvent() val childrenLiveData = SingleLiveEvent, Boolean>>() var fileClicked: File? = null val downloadProgressLiveData = MutableLiveData(0) val buildArchiveResult = SingleLiveEvent>() + val fetchCacheFileForActionResult = MutableSharedFlow>( + extraBufferCapacity = 1, + onBufferOverflow = BufferOverflow.DROP_OLDEST, + ) val initPublicShareResult = SingleLiveEvent>() val submitPasswordResult = SingleLiveEvent() var hasBeenAuthenticated = false @@ -165,38 +167,21 @@ class PublicShareViewModel(val savedStateHandle: SavedStateHandle) : ViewModel() buildArchiveResult.postValue(result) } - fun executeDownloadAction( - activityContext: Context, - downloadAction: DownloadAction, - file: File?, - navigateToDownloadDialog: suspend () -> Unit, - onDownloadSuccess: (() -> Unit)? = null, - onDownloadError: () -> Unit, - ) = viewModelScope.launch(Dispatchers.IO) { - runCatching { - val cacheFile = file!!.convertToIOFile( - context = activityContext, - onProgress = downloadProgressLiveData::postValue, - navigateToDownloadDialog = navigateToDownloadDialog, - ) - - val uri = FileProvider.getUriForFile(activityContext, activityContext.getString(R.string.FILE_AUTHORITY), cacheFile) - - when (downloadAction) { - DownloadAction.OPEN_WITH -> { - activityContext.openWith(uri, file.getMimeType(), Intent.FLAG_GRANT_READ_URI_PERMISSION) - } - DownloadAction.SEND_COPY -> activityContext.shareFile { uri } - DownloadAction.SAVE_TO_DRIVE -> activityContext.saveToKDrive(uri) - DownloadAction.OPEN_BOOKMARK -> activityContext.openBookmarkIntent(file.name, uri) - DownloadAction.PRINT_PDF -> activityContext.printPdf(cacheFile) + fun fetchCacheFileForAction(file: File?, action: DownloadAction, navigateToDownloadDialog: suspend () -> Unit) { + viewModelScope.launch(Dispatchers.IO) { + runCatching { + fetchCacheFileForActionResult.emit( + file!!.convertToIOFile( + context = appContext, + onProgress = downloadProgressLiveData::postValue, + navigateToDownloadDialog = navigateToDownloadDialog, + ) to action + ) + }.onFailure { exception -> + fetchCacheFileForActionResult.emit(null to action) + downloadProgressLiveData.postValue(null) + exception.printStackTrace() } - - Dispatchers.Main { onDownloadSuccess?.invoke() } - }.onFailure { exception -> - downloadProgressLiveData.postValue(null) - exception.printStackTrace() - Dispatchers.Main { onDownloadError() } } }