Skip to content

Commit

Permalink
add cancel upload functionality
Browse files Browse the repository at this point in the history
Signed-off-by: parneet-guraya <[email protected]>
  • Loading branch information
parneet-guraya committed Jan 8, 2024
1 parent 3e5d7b0 commit cdd0fcc
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil
import com.nextcloud.talk.utils.preferences.AppPreferences
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import java.io.File
import javax.inject.Inject

@AutoInjector(NextcloudTalkApplication::class)
Expand Down Expand Up @@ -91,6 +92,9 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
lateinit var roomToken: String
lateinit var conversationName: String
lateinit var currentUser: User
private var isChunkedUploading = false
private var file: File? = null
private var chunkedFileUploader: ChunkedFileUploader? = null

@Suppress("Detekt.TooGenericExceptionCaught")
override fun doWork(): Result {
Expand Down Expand Up @@ -120,28 +124,30 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa

val sourceFileUri = Uri.parse(sourceFile)
fileName = FileUtils.getFileName(sourceFileUri, context)
val file = FileUtils.getFileFromUri(context, sourceFileUri)
file = FileUtils.getFileFromUri(context, sourceFileUri)
val remotePath = getRemotePath(currentUser)
val uploadSuccess: Boolean

initNotificationSetup()

file?.let { isChunkedUploading = it.length() > CHUNK_UPLOAD_THRESHOLD_SIZE }
if (file == null) {
uploadSuccess = false
} else if (file.length() > CHUNK_UPLOAD_THRESHOLD_SIZE) {
Log.d(TAG, "starting chunked upload because size is " + file.length())
} else if (isChunkedUploading) {
Log.d(TAG, "starting chunked upload because size is " + file!!.length())

initNotificationWithPercentage()
val mimeType = context.contentResolver.getType(sourceFileUri)?.toMediaTypeOrNull()

uploadSuccess = ChunkedFileUploader(
chunkedFileUploader = ChunkedFileUploader(
okHttpClient,
currentUser,
roomToken,
metaData,
this
).upload(
file,
)

uploadSuccess = chunkedFileUploader!!.upload(
file!!,
mimeType,
remotePath
)
Expand All @@ -164,6 +170,9 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
if (uploadSuccess) {
mNotifyManager?.cancel(notificationId)
return Result.success()
} else if (isStopped) {
// since work is cancelled the result would be ignored anyways
return Result.failure()
}

Log.e(TAG, "Something went wrong when trying to upload file")
Expand Down Expand Up @@ -195,6 +204,15 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
mNotifyManager!!.notify(notificationId, notification)
}

override fun onStopped() {
if (file != null && isChunkedUploading) {
chunkedFileUploader?.abortUpload {
mNotifyManager?.cancel(notificationId)
}
}
super.onStopped()
}

private fun initNotificationSetup() {
mNotifyManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
mBuilder = NotificationCompat.Builder(
Expand All @@ -206,13 +224,17 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa

private fun initNotificationWithPercentage() {
notification = mBuilder!!
.setContentTitle(context.resources.getString(R.string.nc_upload_in_progess))
.setContentTitle(getResourceString(context, R.string.nc_upload_in_progess))
.setContentText(getNotificationContentText(ZERO_PERCENT))
.setSmallIcon(R.drawable.upload_white)
.setOngoing(true)
.setProgress(HUNDRED_PERCENT, ZERO_PERCENT, false)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setContentIntent(getIntentToOpenConversation())
.addAction(
R.drawable.ic_cancel_white_24dp, getResourceString(context, R.string.nc_cancel),
getCancelUploadIntent()
)
.build()

notificationId = SystemClock.uptimeMillis().toInt()
Expand All @@ -221,7 +243,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa

private fun getNotificationContentText(percentage: Int): String {
return String.format(
context.resources.getString(R.string.nc_upload_notification_text),
getResourceString(context, R.string.nc_upload_notification_text),
getShortenedFileName(),
conversationName,
percentage
Expand All @@ -236,6 +258,11 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
}
}

private fun getCancelUploadIntent(): PendingIntent {
return WorkManager.getInstance(applicationContext)
.createCancelPendingIntent(id)
}

private fun getIntentToOpenConversation(): PendingIntent? {
val bundle = Bundle()
val intent = Intent(context, MainActivity::class.java)
Expand All @@ -257,9 +284,9 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
}

private fun showFailedToUploadNotification() {
val failureTitle = context.resources.getString(R.string.nc_upload_failed_notification_title)
val failureTitle = getResourceString(context, R.string.nc_upload_failed_notification_title)
val failureText = String.format(
context.resources.getString(R.string.nc_upload_failed_notification_text),
getResourceString(context, R.string.nc_upload_failed_notification_text),
fileName
)
notification = mBuilder!!
Expand All @@ -275,6 +302,10 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
mNotifyManager!!.notify(SystemClock.uptimeMillis().toInt(), notification)
}

private fun getResourceString(context: Context, resourceId: Int): String {
return context.resources.getString(resourceId)
}

companion object {
private val TAG = UploadAndShareFilesWorker::class.simpleName
private const val DEVICE_SOURCE_FILE = "DEVICE_SOURCE_FILE"
Expand All @@ -301,6 +332,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
REQUEST_PERMISSION
)
}

Build.VERSION.SDK_INT > Build.VERSION_CODES.Q -> {
activity.requestPermissions(
arrayOf(
Expand All @@ -309,6 +341,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
REQUEST_PERMISSION
)
}

else -> {
activity.requestPermissions(
arrayOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class ChunkedFileUploader(

private var okHttpClientNoRedirects: OkHttpClient? = null
private var remoteChunkUrl: String
private var uploadFolderUri: String = ""
private var isUploadAborted = false

init {
initHttpClient(okHttpClient, currentUser)
Expand All @@ -85,7 +87,7 @@ class ChunkedFileUploader(
@Suppress("Detekt.TooGenericExceptionCaught")
fun upload(localFile: File, mimeType: MediaType?, targetPath: String): Boolean {
try {
val uploadFolderUri: String = remoteChunkUrl + "/" + FileUtils.md5Sum(localFile)
uploadFolderUri = remoteChunkUrl + "/" + FileUtils.md5Sum(localFile)
val davResource = DavResource(
okHttpClientNoRedirects!!,
uploadFolderUri.toHttpUrlOrNull()!!
Expand All @@ -100,6 +102,7 @@ class ChunkedFileUploader(
Log.d(TAG, "missingChunks: " + missingChunks.size)

for (missingChunk in missingChunks) {
if (isUploadAborted) return false
uploadChunk(localFile, uploadFolderUri, mimeType, missingChunk, missingChunk.length())
}

Expand Down Expand Up @@ -327,6 +330,19 @@ class ChunkedFileUploader(
}
}

fun abortUpload(onSuccess: () -> Unit) {
isUploadAborted = true
DavResource(
okHttpClientNoRedirects!!,
uploadFolderUri.toHttpUrlOrNull()!!
).delete { response: Response ->
when {
response.isSuccessful -> onSuccess()
else -> isUploadAborted = false
}
}
}

private fun getModelFromResponse(response: at.bitfire.dav4jvm.Response, remotePath: String): RemoteFileBrowserItem {
val remoteFileBrowserItem = RemoteFileBrowserItem()
remoteFileBrowserItem.path = Uri.decode(remotePath)
Expand All @@ -353,30 +369,39 @@ class ChunkedFileUploader(
is OCId -> {
remoteFileBrowserItem.remoteId = property.ocId
}

is ResourceType -> {
remoteFileBrowserItem.isFile = !property.types.contains(ResourceType.COLLECTION)
}

is GetLastModified -> {
remoteFileBrowserItem.modifiedTimestamp = property.lastModified
}

is GetContentType -> {
remoteFileBrowserItem.mimeType = property.type
}

is OCSize -> {
remoteFileBrowserItem.size = property.ocSize
}

is NCPreview -> {
remoteFileBrowserItem.hasPreview = property.isNcPreview
}

is OCFavorite -> {
remoteFileBrowserItem.isFavorite = property.isOcFavorite
}

is DisplayName -> {
remoteFileBrowserItem.displayName = property.displayName
}

is NCEncrypted -> {
remoteFileBrowserItem.isEncrypted = property.isNcEncrypted
}

is NCPermission -> {
remoteFileBrowserItem.permissions = property.ncPermission
}
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/ic_cancel_white_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z"/>
</vector>

0 comments on commit cdd0fcc

Please sign in to comment.