Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ class BackgroundJobFactory @Inject constructor(
accountManager,
context,
viewThemeUtils.get(),
localBroadcastManager.get(),
params
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,8 @@ internal class BackgroundJobManagerImpl(

val request = oneTimeRequestBuilder(FolderDownloadWorker::class, JOB_DOWNLOAD_FOLDER)
.addTag(JOB_DOWNLOAD_FOLDER)
.addTag(FolderDownloadWorker.formatTag(folder.fileId))
.addTag(FolderDownloadWorker.formatParentTag(folder.parentId))
.setInputData(data)
.setConstraints(constraints)
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
package com.nextcloud.client.jobs.folderDownload

import android.content.Context
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.client.jobs.BackgroundJobManagerImpl
import com.nextcloud.client.jobs.download.FileDownloadHelper
import com.nextcloud.utils.AppConstants
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
Expand All @@ -35,20 +37,24 @@ class FolderDownloadWorker(
private val accountManager: UserAccountManager,
private val context: Context,
viewThemeUtils: ViewThemeUtils,
localBroadcastManager: LocalBroadcastManager,
params: WorkerParameters
) : CoroutineWorker(context, params) {

companion object {
private const val TAG = "📂" + "FolderDownloadWorker"
const val FOLDER_ID = "FOLDER_ID"
const val ACCOUNT_NAME = "ACCOUNT_NAME"
const val FILE_ID = "FILE_ID"
const val PREVIOUS_FILE_ID = "PREVIOUS_FILE_ID"
const val IS_FOLDER_DOWNLOADED = "IS_FOLDER_DOWNLOADED"
private val pendingDownloads: MutableSet<Long> = ConcurrentHashMap.newKeySet()
fun isDownloading(id: Long): Boolean = pendingDownloads.contains(id)
fun formatTag(folderId: Long): String = BackgroundJobManagerImpl.JOB_DOWNLOAD_FOLDER + folderId
fun formatParentTag(parentId: Long): String =
BackgroundJobManagerImpl.JOB_DOWNLOAD_FOLDER + "_parent_" + parentId
}

private val notificationManager = FolderDownloadWorkerNotificationManager(context, true, viewThemeUtils)
private val folderDownloadEventBroadcaster = FolderDownloadEventBroadcaster(context, localBroadcastManager)
private lateinit var storageManager: FileDataStorageManager

@Suppress("ReturnCount", "DEPRECATION")
Expand Down Expand Up @@ -82,7 +88,6 @@ class FolderDownloadWorker(
Log_OC.d(TAG, "🕒 started for ${user.accountName} | folder=${folder.fileName}")

trySetForeground(folder)
folderDownloadEventBroadcaster.sendDownloadEnqueued(folder.fileId)
pendingDownloads.add(folder.fileId)

val downloadHelper = FileDownloadHelper.instance()
Expand All @@ -100,6 +105,7 @@ class FolderDownloadWorker(
}

var overallSuccess = true
var previousFileId: Long? = null

files.forEachIndexed { index, file ->
if (isStopped) {
Expand All @@ -119,6 +125,7 @@ class FolderDownloadWorker(
files.size
)

setProgress(workDataOf(FILE_ID to file.fileId, PREVIOUS_FILE_ID to previousFileId))
val operation = DownloadFileOperation(user, file, context)
val operationResult = operation.execute(client)

Expand All @@ -132,6 +139,7 @@ class FolderDownloadWorker(
Log_OC.w(TAG, "⚠️ download failed for ${file.remotePath}: ${operationResult?.logMessage}")
overallSuccess = false
}
previousFileId = file.fileId
}

notificationManager.showCompletionNotification(folder.fileName, overallSuccess)
Expand All @@ -148,11 +156,11 @@ class FolderDownloadWorker(
notificationManager.showCompletionNotification(folder.fileName, false)
Result.failure()
} finally {
folderDownloadEventBroadcaster.sendDownloadCompleted(folder.fileId)
pendingDownloads.remove(folder.fileId)
setProgress(workDataOf(IS_FOLDER_DOWNLOADED to true))

// delay so that user can see the error or success notification
delay(2000)
delay(AppConstants.TWO_SECOND)
notificationManager.dismiss()
}
}
Expand Down Expand Up @@ -187,12 +195,10 @@ class FolderDownloadWorker(
}
}

private fun getOCFile(operation: DownloadFileOperation): OCFile? = operation.file?.fileId?.let {
storageManager.getFileById(it)
}
?: storageManager.getFileByDecryptedRemotePath(operation.file?.remotePath)
private fun getOCFile(operation: DownloadFileOperation): OCFile? = storageManager.getFileById(operation.file.fileId)
?: storageManager.getFileByDecryptedRemotePath(operation.file.remotePath)
?: run {
Log_OC.e(TAG, "could not resolve OCFile for save: ${operation.file?.remotePath}")
Log_OC.e(TAG, "could not resolve OCFile for save: ${operation.file.remotePath}")
null
}

Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/com/nextcloud/utils/AppConstants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ object AppConstants {
const val SECONDS_PER_MINUTE = 60
const val MINUTES_PER_HOUR = 60
val ONE_SECOND = 1.seconds
val TWO_SECOND = 2.seconds

const val BYTES_PER_KB = 1024
const val BYTES_PER_MB = BYTES_PER_KB * BYTES_PER_KB
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ import androidx.core.view.MenuItemCompat
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.dialog.MaterialAlertDialogBuilder
Expand All @@ -70,7 +72,6 @@ import com.nextcloud.client.files.DeepLinkHandler
import com.nextcloud.client.jobs.download.FileDownloadEventBroadcaster
import com.nextcloud.client.jobs.download.FileDownloadHelper
import com.nextcloud.client.jobs.download.FileDownloadWorker
import com.nextcloud.client.jobs.folderDownload.FolderDownloadEventBroadcaster
import com.nextcloud.client.jobs.upload.FileUploadEventBroadcaster
import com.nextcloud.client.jobs.upload.FileUploadHelper
import com.nextcloud.client.jobs.upload.FileUploadWorker
Expand Down Expand Up @@ -212,9 +213,6 @@ class FileDisplayActivity :
private val fileDownloadStartedReceiver = FileDownloadStartedReceiver()
private val fileDownloadCompletedReceiver = FileDownloadCompletedReceiver()

private val folderDownloadStartedReceiver = FolderDownloadStartedReceiver()
private val folderDownloadCompletedReceiver = FolderDownloadCompletedReceiver()

private lateinit var albumOperationListener: AlbumOperationListener

var mLastSslUntrustedServerResult: RemoteOperationResult<*>? = null
Expand Down Expand Up @@ -292,6 +290,11 @@ class FileDisplayActivity :

private lateinit var folderRefreshScheduler: FolderRefreshScheduler

override fun setFile(file: OCFile?) {
super.setFile(file)
file?.takeIf { it.isFolder }?.let { viewModel.setCurrentFolder(it.fileId) }
}

fun setFileIDForImmediatePreview(fileIDForImmediatePreview: Long) {
this.fileIDForImmediatePreview = fileIDForImmediatePreview
}
Expand Down Expand Up @@ -1536,14 +1539,6 @@ class FileDisplayActivity :
val uploadFinishedIntent = IntentFilter(FileUploadEventBroadcaster.ACTION_UPLOAD_COMPLETED)
registerReceiver(fileUploadCompletedReceiver, uploadFinishedIntent)

val folderDownloadStartedIntentFilter =
IntentFilter(FolderDownloadEventBroadcaster.ACTION_DOWNLOAD_ENQUEUED)
registerReceiver(folderDownloadStartedReceiver, folderDownloadStartedIntentFilter)

val folderDownloadFinishedIntentFilter =
IntentFilter(FolderDownloadEventBroadcaster.ACTION_DOWNLOAD_COMPLETED)
registerReceiver(folderDownloadCompletedReceiver, folderDownloadFinishedIntentFilter)

val fileDownloadStartedIntentFilter = IntentFilter(FileDownloadEventBroadcaster.ACTION_DOWNLOAD_ENQUEUED)
registerReceiver(fileDownloadStartedReceiver, fileDownloadStartedIntentFilter)

Expand All @@ -1568,8 +1563,6 @@ class FileDisplayActivity :
unregisterReceiver(fileUploadCompletedReceiver)
unregisterReceiver(fileDownloadStartedReceiver)
unregisterReceiver(fileDownloadCompletedReceiver)
unregisterReceiver(folderDownloadStartedReceiver)
unregisterReceiver(folderDownloadCompletedReceiver)
}
}
// endregion
Expand Down Expand Up @@ -1876,43 +1869,13 @@ class FileDisplayActivity :
ocFileListFragment?.adapter?.updateFileIndicator(state.iconId, file)
}

// region FolderDownloadWorker receivers
@Suppress("ReturnCount")
private fun getFolderFromFolderDownloadWorker(intent: Intent): OCFile? {
val id = intent.getLongExtra(FolderDownloadEventBroadcaster.EXTRA_FILE_ID, -1L)
if (id == -1L) {
Log_OC.e(TAG, "invalid id received")
return null
}

val folder = storageManager.getFileById(id)
if (folder == null) {
Log_OC.e(TAG, "folder not exists")
return null
}

return folder
// region FolderDownloadWorker observers
private fun onFolderFileDownloadProgress(fileId: Long, previousFileId: Long?) {
val adapter = ocFileListFragment?.adapter ?: return
previousFileId?.let { storageManager.getFileById(it) }?.let(adapter::replaceFile)
adapter.updateFileIndicator(fileId, FileDownloadIndicator.Downloading.iconId)
}

private inner class FolderDownloadStartedReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log_OC.d(TAG, "download worker started")
val folder = getFolderFromFolderDownloadWorker(intent) ?: return
updateFileDownloadIndicator(FileDownloadIndicator.Downloading, folder)
}
}

private inner class FolderDownloadCompletedReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log_OC.d(TAG, "download worker finished")
val folder = getFolderFromFolderDownloadWorker(intent) ?: return
updateFileDownloadIndicator(FileDownloadIndicator.Downloaded, folder)

if (folder.fileId == getCurrentDir()?.fileId) {
updateListOfFilesFragment()
}
}
}
// endregion

// region FileDownloadWorker receivers
Expand Down Expand Up @@ -2111,6 +2074,15 @@ class FileDisplayActivity :
refreshCurrentDirectory()
})
}

lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.observeFolderDownloadWorker(
onFileProgress = ::onFolderFileDownloadProgress,
onCompleted = ::updateListOfFilesFragment
)
}
}
}

fun canPreviewInMediaPager(file: OCFile?): Boolean =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,27 @@
package com.owncloud.android.ui.activity.filedisplayactivity

import androidx.lifecycle.ViewModel
import androidx.work.Data
import androidx.work.WorkInfo
import androidx.work.WorkManager
import com.nextcloud.client.jobs.BackgroundJobManagerImpl
import com.nextcloud.client.jobs.folderDownload.FolderDownloadWorker
import com.nextcloud.client.jobs.offlineOperations.OfflineOperationsWorker
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.merge
import javax.inject.Inject

class FileDisplayActivityViewModel @Inject constructor(private val workManager: WorkManager) : ViewModel() {

private val currentFolderId = MutableStateFlow<Long?>(null)

suspend fun observeOfflineWorker(onComplete: () -> Unit) {
workManager
.getWorkInfosByTagFlow(BackgroundJobManagerImpl.formatClassTag(OfflineOperationsWorker::class))
Expand All @@ -25,4 +38,40 @@ class FileDisplayActivityViewModel @Inject constructor(private val workManager:
}
}
}

fun setCurrentFolder(folderId: Long) {
currentFolderId.value = folderId
}

@OptIn(ExperimentalCoroutinesApi::class)
suspend fun observeFolderDownloadWorker(
onFileProgress: (fileId: Long, previousFileId: Long?) -> Unit,
onCompleted: () -> Unit
) {
currentFolderId
.filterNotNull()
.flatMapLatest { folderId ->
merge(
observeRunningProgress(FolderDownloadWorker.formatTag(folderId)),
observeRunningProgress(FolderDownloadWorker.formatParentTag(folderId))
.filter { it.isFolderDownloaded() }
)
}
.collect { progress ->
if (progress.isFolderDownloaded()) {
onCompleted()
return@collect
}

val fileId = progress.keyValueMap[FolderDownloadWorker.FILE_ID] as? Long ?: return@collect
onFileProgress(fileId, progress.keyValueMap[FolderDownloadWorker.PREVIOUS_FILE_ID] as? Long)
}
}

private fun observeRunningProgress(tag: String): Flow<Data> = workManager
.getWorkInfosByTagFlow(tag)
.mapNotNull { workInfos -> workInfos.firstOrNull { it.state == WorkInfo.State.RUNNING }?.progress }
.distinctUntilChanged()

private fun Data.isFolderDownloaded(): Boolean = getBoolean(FolderDownloadWorker.IS_FOLDER_DOWNLOADED, false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,13 @@ class OCFileListAdapter(
file?.let { notifyItemChangedIfPresent(it, iconId) }
}

fun updateFileIndicator(fileId: Long, iconId: Int) {
val index = files.indexOfFirst { it.fileId == fileId }
if (index != RecyclerView.NO_POSITION) {
notifyItemChanged(index + differ.headerOffset(), iconId)
}
}

@SuppressLint("NotifyDataSetChanged")
fun updateRecommendedFiles(value: List<OCFile>) {
recommendedFiles.clear()
Expand Down
Loading