Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
af56bdb
Albums functionality.
surinder-tsys Jun 2, 2025
cc7b787
Rename .java to .kt
surinder-tsys Jun 6, 2025
b17cb2e
Code refactoring and operation migrated to kotlin
surinder-tsys Jun 6, 2025
513eed4
Fix -> video click event, overflow menu item hide and theming add menu
surinder-tsys Jun 6, 2025
6c3d0d0
Fix: preview album items
surinder-tsys Jul 11, 2025
39ae6d2
upload files to album, hide video overlay icon, minor ui and bug fixes
surinder-tsys Jan 22, 2026
1e41b47
wip
tobiasKaminsky Jan 23, 2026
be12078
Albums functionality.
surinder-tsys Jun 2, 2025
c72fc2a
Rename .java to .kt
surinder-tsys Jun 6, 2025
86c7f50
Code refactoring and operation migrated to kotlin
surinder-tsys Jun 6, 2025
36467bb
upload files to album, hide video overlay icon, minor ui and bug fixes
surinder-tsys Jan 22, 2026
5fc8442
small fix
tobiasKaminsky Jan 26, 2026
51d2b06
code fixes
surinder-tsys Jan 29, 2026
2973e5f
album upload worker state handled via localbroadcastmanager
surinder-tsys Jan 30, 2026
9410492
simplify upload file calls
alperozturk96 Feb 2, 2026
7a7dcc8
separate worker parameters
alperozturk96 Feb 2, 2026
692541a
separate params
alperozturk96 Feb 2, 2026
61a877a
simplify album fragment
alperozturk96 Feb 2, 2026
eef363f
use optional generic function to access fragment
alperozturk96 Feb 3, 2026
d30a3eb
fix code analytics, simplify
alperozturk96 Feb 3, 2026
7072806
m3 card
alperozturk96 Feb 19, 2026
271fbb0
m3 card
alperozturk96 Feb 19, 2026
8cd7dd4
use fab
alperozturk96 Feb 19, 2026
678d75f
use action bottom sheet for album item actions
alperozturk96 Feb 19, 2026
5152331
use action bottom sheet for album item actions
alperozturk96 Feb 19, 2026
f9e298f
fix fab button appereance
alperozturk96 Feb 20, 2026
7f2787b
fix git conflict
alperozturk96 Feb 26, 2026
3d9e8f1
small typo fixes
alperozturk96 Feb 26, 2026
4597112
use outlined card
alperozturk96 Feb 26, 2026
c0ab913
album items fragment code cleanup
alperozturk96 Feb 26, 2026
7efd47e
fix(spotbugs): NAB: Needless Autoboxing
alperozturk96 Feb 26, 2026
0ac89a1
fix menu item highlighting
alperozturk96 Feb 26, 2026
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 @@ -16,6 +16,7 @@ import com.nextcloud.client.jobs.upload.FileUploadHelper
import com.nextcloud.client.jobs.upload.FileUploadWorker
import com.nextcloud.client.network.Connectivity
import com.nextcloud.client.network.ConnectivityService
import com.nextcloud.model.OCUploadLocalPathData
import com.owncloud.android.AbstractOnServerIT
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.datamodel.UploadsStorageManager
Expand Down Expand Up @@ -123,7 +124,7 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
fun testKeepLocalAndOverwriteRemoteStatic() {
val file = getDummyFile("chunkedFile.txt")

FileUploadHelper().uploadNewFiles(
val data = OCUploadLocalPathData(
user,
arrayOf(file.absolutePath),
arrayOf("/testFile.txt"),
Expand All @@ -135,6 +136,8 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
NameCollisionPolicy.DEFAULT
)

FileUploadHelper().uploadNewFiles(data)

longSleep()

val result = ReadFileRemoteOperation("/testFile.txt").execute(client)
Expand Down Expand Up @@ -239,7 +242,7 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
fun testKeepBothStatic() {
val file = getDummyFile("nonEmpty.txt")

FileUploadHelper().uploadNewFiles(
val data = OCUploadLocalPathData(
user,
arrayOf(file.absolutePath),
arrayOf("/testFile.txt"),
Expand All @@ -250,6 +253,7 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
false,
NameCollisionPolicy.DEFAULT
)
FileUploadHelper().uploadNewFiles(data)

longSleep()

Expand Down Expand Up @@ -347,7 +351,7 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
fun testKeepServerStatic() {
val file = getDummyFile("chunkedFile.txt")

FileUploadHelper().uploadNewFiles(
val data = OCUploadLocalPathData(
user,
arrayOf(file.absolutePath),
arrayOf("/testFile.txt"),
Expand All @@ -358,6 +362,7 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
false,
NameCollisionPolicy.DEFAULT
)
FileUploadHelper().uploadNewFiles(data)

longSleep()

Expand Down Expand Up @@ -451,7 +456,7 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
fun testKeepCancelStatic() {
val file = getDummyFile("chunkedFile.txt")

FileUploadHelper().uploadNewFiles(
val data = OCUploadLocalPathData(
user,
arrayOf(file.absolutePath),
arrayOf("/testFile.txt"),
Expand All @@ -462,6 +467,7 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
false,
NameCollisionPolicy.DEFAULT
)
FileUploadHelper().uploadNewFiles(data)

longSleep()

Expand Down
5 changes: 4 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Nextcloud - Android Client
~
~ SPDX-FileCopyrightText: 2024 TSI-mc <surinder.kumar@t-systems.com>
~ SPDX-FileCopyrightText: 2024-2025 TSI-mc <surinder.kumar@t-systems.com>
~ SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
-->
Expand Down Expand Up @@ -643,6 +643,9 @@
android:launchMode="singleTop"
android:theme="@style/Theme.ownCloud.Dialog.NoTitle"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".ui.activity.AlbumsPickerActivity"
android:exported="false" />
<activity
android:name=".ui.activity.ShareActivity"
android:exported="false"
Expand Down
22 changes: 21 additions & 1 deletion app/src/main/java/com/nextcloud/client/di/ComponentsModule.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-FileCopyrightText: 2024-2025 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
Expand Down Expand Up @@ -32,6 +32,7 @@
import com.nextcloud.ui.ImageDetailFragment;
import com.nextcloud.ui.SetOnlineStatusBottomSheet;
import com.nextcloud.ui.SetStatusMessageBottomSheet;
import com.nextcloud.ui.albumItemActions.AlbumItemActionsBottomSheet;
import com.nextcloud.ui.composeActivity.ComposeActivity;
import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
import com.nextcloud.ui.trashbinFileActions.TrashbinFileActionsBottomSheet;
Expand Down Expand Up @@ -82,6 +83,7 @@
import com.owncloud.android.ui.dialog.ChooseTemplateDialogFragment;
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
import com.owncloud.android.ui.dialog.ConflictsResolveDialog;
import com.owncloud.android.ui.dialog.CreateAlbumDialogFragment;
import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
import com.owncloud.android.ui.dialog.IndeterminateProgressDialog;
Expand Down Expand Up @@ -115,6 +117,9 @@
import com.owncloud.android.ui.fragment.OCFileListFragment;
import com.owncloud.android.ui.fragment.SharedListFragment;
import com.owncloud.android.ui.fragment.UnifiedSearchFragment;
import com.owncloud.android.ui.fragment.albums.AlbumItemsFragment;
import com.owncloud.android.ui.fragment.albums.AlbumsFragment;
import com.owncloud.android.ui.activity.AlbumsPickerActivity;
import com.owncloud.android.ui.fragment.contactsbackup.BackupFragment;
import com.owncloud.android.ui.fragment.contactsbackup.BackupListFragment;
import com.owncloud.android.ui.preview.FileDownloadFragment;
Expand Down Expand Up @@ -509,4 +514,19 @@ abstract class ComponentsModule {

@ContributesAndroidInjector
abstract SetStatusMessageBottomSheet setStatusMessageBottomSheet();

@ContributesAndroidInjector
abstract AlbumsPickerActivity albumsPickerActivity();

@ContributesAndroidInjector
abstract CreateAlbumDialogFragment createAlbumDialogFragment();

@ContributesAndroidInjector
abstract AlbumsFragment albumsFragment();

@ContributesAndroidInjector
abstract AlbumItemsFragment albumItemsFragment();

@ContributesAndroidInjector
abstract AlbumItemActionsBottomSheet albumItemActionsBottomSheet();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.nextcloud.client.jobs.BackgroundJobManager
import com.nextcloud.client.jobs.upload.FileUploadHelper
import com.nextcloud.client.jobs.upload.FileUploadWorker
import com.nextcloud.client.logger.Logger
import com.nextcloud.model.OCUploadLocalPathData
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.files.services.NameCollisionPolicy
import com.owncloud.android.operations.UploadFileOperation
Expand Down Expand Up @@ -166,17 +167,8 @@ class DocumentScanViewModel @Inject constructor(
uploadFolder + OCFile.PATH_SEPARATOR + File(it).name
}.toTypedArray()

FileUploadHelper.instance().uploadNewFiles(
currentAccountProvider.user,
pageList.toTypedArray(),
uploadPaths,
FileUploadWorker.LOCAL_BEHAVIOUR_DELETE,
true,
UploadFileOperation.CREATED_BY_USER,
false,
false,
NameCollisionPolicy.ASK_USER
)
val data = OCUploadLocalPathData.forDocument(currentAccountProvider.user, pageList.toTypedArray(), uploadPaths)
FileUploadHelper.instance().uploadNewFiles(data)
}

fun onExportCanceled() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.client.jobs.upload.FileUploadHelper
import com.nextcloud.client.jobs.upload.FileUploadWorker
import com.nextcloud.client.logger.Logger
import com.nextcloud.model.OCUploadLocalPathData
import com.owncloud.android.R
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.files.services.NameCollisionPolicy
Expand Down Expand Up @@ -108,18 +109,8 @@ class GeneratePdfFromImagesWork(
private fun uploadFile(user: User, uploadFolder: String, pdfPath: String) {
val uploadPath = uploadFolder + OCFile.PATH_SEPARATOR + File(pdfPath).name

FileUploadHelper().uploadNewFiles(
user,
arrayOf(pdfPath),
arrayOf(uploadPath),
// MIME type will be detected from file name
FileUploadWorker.LOCAL_BEHAVIOUR_DELETE,
true,
UploadFileOperation.CREATED_BY_USER,
false,
false,
NameCollisionPolicy.ASK_USER
)
val data = OCUploadLocalPathData.forDocument(user, arrayOf(pdfPath), arrayOf(uploadPath))
FileUploadHelper().uploadNewFiles(data)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.canhub.cropper.CropImageView
import com.nextcloud.client.di.Injectable
import com.nextcloud.client.jobs.upload.FileUploadHelper
import com.nextcloud.client.jobs.upload.FileUploadWorker
import com.nextcloud.model.OCUploadLocalPathData
import com.nextcloud.utils.extensions.getParcelableArgument
import com.owncloud.android.R
import com.owncloud.android.databinding.ActivityEditImageBinding
Expand Down Expand Up @@ -95,17 +96,18 @@ class EditImageActivity :
resultUri?.substring(resultUri.lastIndexOf('.'))

resultUri?.let {
FileUploadHelper().uploadNewFiles(
val data = OCUploadLocalPathData(
user = storageManager.user,
localPaths = arrayOf(it),
remotePaths = arrayOf(file.parentRemotePath + File.separator + newFileName),
createRemoteFolder = false,
createdBy = UploadFileOperation.CREATED_BY_USER,
creationType = UploadFileOperation.CREATED_BY_USER,
requiresWifi = false,
requiresCharging = false,
nameCollisionPolicy = NameCollisionPolicy.RENAME,
collisionPolicy = NameCollisionPolicy.RENAME,
localBehavior = FileUploadWorker.LOCAL_BEHAVIOUR_DELETE
)
FileUploadHelper().uploadNewFiles(data)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2026 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.jobs
Expand All @@ -28,6 +29,7 @@ import com.nextcloud.client.jobs.download.FileDownloadWorker
import com.nextcloud.client.jobs.folderDownload.FolderDownloadWorker
import com.nextcloud.client.jobs.metadata.MetadataWorker
import com.nextcloud.client.jobs.offlineOperations.OfflineOperationsWorker
import com.nextcloud.client.jobs.upload.AlbumFileUploadWorker
import com.nextcloud.client.jobs.upload.FileUploadWorker
import com.nextcloud.client.logger.Logger
import com.nextcloud.client.network.ConnectivityService
Expand Down Expand Up @@ -96,6 +98,7 @@ class BackgroundJobFactory @Inject constructor(
CalendarImportWork::class -> createCalendarImportWork(context, workerParameters)
FilesExportWork::class -> createFilesExportWork(context, workerParameters)
FileUploadWorker::class -> createFilesUploadWorker(context, workerParameters)
AlbumFileUploadWorker::class -> createAlbumsFilesUploadWorker(context, workerParameters)
FileDownloadWorker::class -> createFilesDownloadWorker(context, workerParameters)
GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters)
HealthStatusWork::class -> createHealthStatusWork(context, workerParameters)
Expand Down Expand Up @@ -251,6 +254,20 @@ class BackgroundJobFactory @Inject constructor(
params
)

private fun createAlbumsFilesUploadWorker(context: Context, params: WorkerParameters): AlbumFileUploadWorker =
AlbumFileUploadWorker(
uploadsStorageManager,
connectivityService,
powerManagementService,
accountManager,
viewThemeUtils.get(),
localBroadcastManager.get(),
backgroundJobManager.get(),
preferences,
context,
params
)

private fun createPDFGenerateWork(context: Context, params: WorkerParameters): GeneratePdfFromImagesWork =
GeneratePdfFromImagesWork(
appContext = context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2026 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.jobs
Expand Down Expand Up @@ -136,6 +137,7 @@ interface BackgroundJobManager {
fun startNotificationJob(subject: String, signature: String)
fun startAccountRemovalJob(accountName: String, remoteWipe: Boolean)
fun startFilesUploadJob(user: User, uploadIds: LongArray, showSameFileAlreadyExistsNotification: Boolean)
fun startAlbumFilesUploadJob(user: User, uploadIds: LongArray, albumName: String)
fun getFileUploads(user: User): LiveData<List<JobInfo>>
fun cancelFilesUploadJob(user: User)
fun isStartFileUploadJobScheduled(accountName: String): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2026 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.jobs
Expand Down Expand Up @@ -32,6 +33,7 @@ import com.nextcloud.client.jobs.download.FileDownloadWorker
import com.nextcloud.client.jobs.folderDownload.FolderDownloadWorker
import com.nextcloud.client.jobs.metadata.MetadataWorker
import com.nextcloud.client.jobs.offlineOperations.OfflineOperationsWorker
import com.nextcloud.client.jobs.upload.AlbumFileUploadWorker
import com.nextcloud.client.jobs.upload.FileUploadHelper
import com.nextcloud.client.jobs.upload.FileUploadWorker
import com.nextcloud.client.preferences.AppPreferences
Expand Down Expand Up @@ -87,6 +89,7 @@ internal class BackgroundJobManagerImpl(
const val JOB_NOTIFICATION = "notification"
const val JOB_ACCOUNT_REMOVAL = "account_removal"
const val JOB_FILES_UPLOAD = "files_upload"
const val ALBUM_JOB_FILES_UPLOAD = "album_files_upload"
const val JOB_FOLDER_DOWNLOAD = "folder_download"
const val JOB_FILES_DOWNLOAD = "files_download"
const val JOB_PDF_GENERATION = "pdf_generation"
Expand Down Expand Up @@ -608,6 +611,8 @@ internal class BackgroundJobManagerImpl(

private fun startFileUploadJobTag(accountName: String): String = JOB_FILES_UPLOAD + accountName

private fun startAlbumsFileUploadJobTag(accountName: String): String = ALBUM_JOB_FILES_UPLOAD + accountName

override fun isStartFileUploadJobScheduled(accountName: String): Boolean =
workManager.isWorkScheduled(startFileUploadJobTag(accountName))

Expand Down Expand Up @@ -671,6 +676,59 @@ internal class BackgroundJobManagerImpl(
}
}

/**
* This method supports uploading and copying selected files to Album
*
* @param user The user for whom the upload job is being created.
* @param uploadIds Array of upload IDs to be processed. These IDs originate from multiple sources
* and cannot be determined directly from the account name or a single function
* within the worker.
* @param albumName Album on which selected files should be copy after upload
*/
override fun startAlbumFilesUploadJob(user: User, uploadIds: LongArray, albumName: String) {
defaultDispatcherScope.launch {
val batchSize = FileUploadHelper.MAX_FILE_COUNT
val batches = uploadIds.toList().chunked(batchSize)
val tag = startAlbumsFileUploadJobTag(user.accountName)

val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()

val dataBuilder = Data.Builder()
.putString(AlbumFileUploadWorker.ACCOUNT, user.accountName)
.putInt(AlbumFileUploadWorker.TOTAL_UPLOAD_SIZE, uploadIds.size)
.putString(AlbumFileUploadWorker.ALBUM_NAME, albumName)

val workRequests = batches.mapIndexed { index, batch ->
dataBuilder
.putLongArray(AlbumFileUploadWorker.UPLOAD_IDS, batch.toLongArray())
.putInt(AlbumFileUploadWorker.CURRENT_BATCH_INDEX, index)

oneTimeRequestBuilder(AlbumFileUploadWorker::class, ALBUM_JOB_FILES_UPLOAD, user)
.addTag(tag)
.setInputData(dataBuilder.build())
.setConstraints(constraints)
.build()
}

// Chain the work requests sequentially
if (workRequests.isNotEmpty()) {
var workChain = workManager.beginUniqueWork(
tag,
ExistingWorkPolicy.APPEND_OR_REPLACE,
workRequests.first()
)

workRequests.drop(1).forEach { request ->
workChain = workChain.then(request)
}

workChain.enqueue()
}
}
}

private fun startFileDownloadJobTag(user: User, fileId: Long): String =
JOB_FOLDER_DOWNLOAD + user.accountName + fileId

Expand Down
Loading
Loading