Skip to content

Commit 2bdef05

Browse files
authored
Merge pull request #4608 from owncloud/feature/sync_operations_over_kiteworks_servers
[FEATURE REQUEST] Polishment of sync operations over Kiteworks servers
2 parents 210997d + 160362e commit 2bdef05

15 files changed

Lines changed: 136 additions & 39 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ ownCloud admins and users.
5252
* Enhancement - Shares space in Android native file explorer: [#4515](https://github.com/owncloud/android/issues/4515)
5353
* Enhancement - Accessibility reports in 4.5.1: [#4568](https://github.com/owncloud/android/issues/4568)
5454
* Enhancement - Support for Kiteworks servers without client secret: [#4588](https://github.com/owncloud/android/issues/4588)
55+
* Enhancement - Polish UI and sync operations over Kiteworks servers: [#4591](https://github.com/owncloud/android/issues/4591)
5556
* Enhancement - Integration of instrumented tests in GitHub Actions: [#4595](https://github.com/owncloud/android/issues/4595)
5657
* Enhancement - SBOM (Software Bill of Materials): [#4598](https://github.com/owncloud/android/issues/4598)
5758

@@ -188,6 +189,14 @@ ownCloud admins and users.
188189
https://github.com/owncloud/android/issues/4588
189190
https://github.com/owncloud/android/pull/4589
190191

192+
* Enhancement - Polish UI and sync operations over Kiteworks servers: [#4591](https://github.com/owncloud/android/issues/4591)
193+
194+
The UI and navigation behaviour after performing a sync operation have been
195+
refined for accounts associated with Kiteworks servers.
196+
197+
https://github.com/owncloud/android/issues/4591
198+
https://github.com/owncloud/android/pull/4608
199+
191200
* Enhancement - Integration of instrumented tests in GitHub Actions: [#4595](https://github.com/owncloud/android/issues/4595)
192201

193202
A new workflow has been added to run instrumented tests in GitHub Actions in

changelog/unreleased/4608

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Enhancement: Polish UI and sync operations over Kiteworks servers
2+
3+
The UI and navigation behaviour after performing a sync operation
4+
have been refined for accounts associated with Kiteworks servers.
5+
6+
https://github.com/owncloud/android/issues/4591
7+
https://github.com/owncloud/android/pull/4608

owncloudApp/src/main/java/com/owncloud/android/presentation/documentsprovider/DocumentsStorageProvider.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
* @author Abel García de Prada
88
* @author Shashvat Kedia
99
* @author Juan Carlos Garrote Gascón
10+
* @author Jorge Aguado Recio
1011
*
1112
* Copyright (C) 2015 Bartosz Przybylski
12-
* Copyright (C) 2023 ownCloud GmbH.
13+
* Copyright (C) 2025 ownCloud GmbH.
1314
*
1415
* This program is free software: you can redistribute it and/or modify
1516
* it under the terms of the GNU General Public License version 2,
@@ -198,6 +199,14 @@ class DocumentsStorageProvider : DocumentsProvider() {
198199
val getPersonalAndProjectSpacesForAccountUseCase: GetPersonalAndProjectSpacesForAccountUseCase by inject()
199200
val getSpaceByIdForAccountUseCase: GetSpaceByIdForAccountUseCase by inject()
200201
val getFileByRemotePathUseCase: GetFileByRemotePathUseCase by inject()
202+
val getStoredCapabilitiesUseCase: GetStoredCapabilitiesUseCase by inject()
203+
val capabilities = getStoredCapabilitiesUseCase(
204+
GetStoredCapabilitiesUseCase.Params(
205+
accountName = parentDocumentId
206+
)
207+
)
208+
val isMultiPersonal = capabilities?.spaces?.hasMultiplePersonalSpaces == true
209+
201210

202211
getPersonalAndProjectSpacesForAccountUseCase(
203212
GetPersonalAndProjectSpacesForAccountUseCase.Params(
@@ -212,7 +221,7 @@ class DocumentsStorageProvider : DocumentsProvider() {
212221
spaceId = space.id,
213222
)
214223
).getDataOrNull()?.let { rootFolder ->
215-
resultCursor.addSpace(space, rootFolder, context)
224+
resultCursor.addSpace(space, rootFolder, context, isMultiPersonal)
216225
}
217226
}
218227
}

owncloudApp/src/main/java/com/owncloud/android/presentation/documentsprovider/cursors/SpaceCursor.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
* ownCloud Android client application
33
*
44
* @author Juan Carlos Garrote Gascón
5+
* @author Jorge Aguado Recio
56
*
6-
* Copyright (C) 2023 ownCloud GmbH.
7+
* Copyright (C) 2025 ownCloud GmbH.
78
*
89
* This program is free software: you can redistribute it and/or modify
910
* it under the terms of the GNU General Public License version 2,
@@ -39,14 +40,14 @@ class SpaceCursor(projection: Array<String>?) : MatrixCursor(projection ?: DEFAU
3940
cursorExtras = Bundle().apply { putBoolean(DocumentsContract.EXTRA_LOADING, hasMoreToSync) }
4041
}
4142

42-
fun addSpace(space: OCSpace, rootFolder: OCFile, context: Context?) {
43+
fun addSpace(space: OCSpace, rootFolder: OCFile, context: Context?, isMultiPersonal: Boolean = false) {
4344
val flags = if (rootFolder.hasAddFilePermission && rootFolder.hasAddSubdirectoriesPermission) {
4445
Document.FLAG_DIR_SUPPORTS_CREATE
4546
} else {
4647
0
4748
}
4849

49-
val name = if (space.isPersonal) context?.getString(R.string.bottom_nav_personal) else space.name
50+
val name = if (space.isPersonal && !isMultiPersonal) context?.getString(R.string.bottom_nav_personal) else space.name
5051

5152
newRow()
5253
.add(Document.COLUMN_DOCUMENT_ID, rootFolder.id)

owncloudApp/src/main/java/com/owncloud/android/presentation/files/details/FileDetailsFragment.kt

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
* @author Abel García de Prada
55
* @author Juan Carlos Garrote Gascón
66
* @author Aitor Ballesteros Pavón
7+
* @author Jorge Aguado Recio
78
*
8-
* Copyright (C) 2024 ownCloud GmbH.
9+
* Copyright (C) 2025 ownCloud GmbH.
910
*
1011
* This program is free software: you can redistribute it and/or modify
1112
* it under the terms of the GNU General Public License version 2,
@@ -107,6 +108,8 @@ class FileDetailsFragment : FileFragment() {
107108

108109
private var openInWebProviders: Map<String, Int> = hashMapOf()
109110

111+
private var isMultiPersonal = false
112+
110113
override fun onCreateView(
111114
inflater: LayoutInflater, container: ViewGroup?,
112115
savedInstanceState: Bundle?
@@ -121,15 +124,9 @@ class FileDetailsFragment : FileFragment() {
121124

122125
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
123126
super.onViewCreated(view, savedInstanceState)
127+
isMultiPersonal = requireArguments().getBoolean(ARG_IS_MULTIPERSONAL)
124128

125-
collectLatestLifecycleFlow(fileDetailsViewModel.currentFile) { ocFileWithSyncInfo: OCFileWithSyncInfo? ->
126-
if (ocFileWithSyncInfo != null) {
127-
file = ocFileWithSyncInfo.file
128-
updateDetails(ocFileWithSyncInfo)
129-
} else {
130-
requireActivity().onBackPressed()
131-
}
132-
}
129+
observeCurrentFile()
133130

134131
collectLatestLifecycleFlow(fileDetailsViewModel.appRegistryMimeType) { appRegistryMimeType ->
135132
if (appRegistryMimeType != null) {
@@ -382,7 +379,7 @@ class FileDetailsFragment : FileFragment() {
382379
binding.fdSpace.visibility = View.VISIBLE
383380
binding.fdSpaceLabel.visibility = View.VISIBLE
384381
binding.fdIconSpace.visibility = View.VISIBLE
385-
if (space.isPersonal) {
382+
if (space.isPersonal && !isMultiPersonal) {
386383
binding.fdSpace.text = getString(R.string.bottom_nav_personal)
387384
} else {
388385
binding.fdSpace.text = space.name
@@ -598,6 +595,17 @@ class FileDetailsFragment : FileFragment() {
598595
fileOperationsViewModel.setLastUsageFile(fileWaitingToPreview)
599596
}
600597

598+
private fun observeCurrentFile() {
599+
collectLatestLifecycleFlow(fileDetailsViewModel.currentFile) { ocFileWithSyncInfo: OCFileWithSyncInfo? ->
600+
if (ocFileWithSyncInfo != null) {
601+
file = ocFileWithSyncInfo.file
602+
updateDetails(ocFileWithSyncInfo)
603+
} else {
604+
requireActivity().onBackPressed()
605+
}
606+
}
607+
}
608+
601609
override fun updateViewForSyncInProgress() {
602610
// Not yet implemented
603611
}
@@ -622,6 +630,7 @@ class FileDetailsFragment : FileFragment() {
622630
private const val ARG_FILE = "FILE"
623631
private const val ARG_ACCOUNT = "ACCOUNT"
624632
private const val ARG_SYNC_FILE_AT_OPEN = "SYNC_FILE_AT_OPEN"
633+
private const val ARG_IS_MULTIPERSONAL = "IS_MULTIPERSONAL"
625634
private const val ZERO_MILLISECOND_TIME = 0
626635

627636
/**
@@ -632,12 +641,13 @@ class FileDetailsFragment : FileFragment() {
632641
* @param account An ownCloud account; needed to start downloads
633642
* @return New fragment with arguments set
634643
*/
635-
fun newInstance(fileToDetail: OCFile, account: Account, syncFileAtOpen: Boolean = true): FileDetailsFragment =
644+
fun newInstance(fileToDetail: OCFile, account: Account, syncFileAtOpen: Boolean = true, isMultiPersonal: Boolean): FileDetailsFragment =
636645
FileDetailsFragment().apply {
637646
arguments = Bundle().apply {
638647
putParcelable(ARG_FILE, fileToDetail)
639648
putParcelable(ARG_ACCOUNT, account)
640649
putBoolean(ARG_SYNC_FILE_AT_OPEN, syncFileAtOpen)
650+
putBoolean(ARG_IS_MULTIPERSONAL, isMultiPersonal)
641651
}
642652
}
643653
}

owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/FileListAdapter.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
* @author Juan Carlos Garrote Gascón
66
* @author Manuel Plazas Palacio
77
* @author Aitor Ballesteros Pavón
8+
* @author Jorge Aguado Recio
89
*
9-
* Copyright (C) 2024 ownCloud GmbH.
10+
* Copyright (C) 2025 ownCloud GmbH.
1011
*
1112
* This program is free software: you can redistribute it and/or modify
1213
* it under the terms of the GNU General Public License version 2,
@@ -55,6 +56,7 @@ class FileListAdapter(
5556
private val isPickerMode: Boolean,
5657
private val layoutManager: StaggeredGridLayoutManager,
5758
private val listener: FileListAdapterListener,
59+
private val isMultiPersonal: Boolean,
5860
) : SelectableAdapter<RecyclerView.ViewHolder>() {
5961

6062
var files = mutableListOf<Any>()
@@ -279,7 +281,12 @@ class FileListAdapter(
279281
view.binding.let {
280282
it.fileListConstraintLayout.filterTouchesWhenObscured = PreferenceUtils.shouldDisallowTouchesWithOtherVisibleWindows(context)
281283
it.Filename.text = file.fileName
282-
it.fileListSize.text = DisplayUtils.bytesToHumanReadable(file.length, context, true)
284+
val isFolderInKw = isMultiPersonal && file.isFolder
285+
it.fileListSize.text = if (isFolderInKw) "" else DisplayUtils.bytesToHumanReadable(file.length, context, true)
286+
it.fileListSeparator.visibility = if (isFolderInKw) View.GONE else View.VISIBLE
287+
it.fileListLastMod.layoutParams = (it.fileListLastMod.layoutParams as ViewGroup.MarginLayoutParams).also {
288+
params -> params.marginStart = if (isFolderInKw) 0 else
289+
context.resources.getDimensionPixelSize(R.dimen.standard_quarter_margin) }
283290
it.fileListLastMod.text = DisplayUtils.getRelativeTimestamp(context, file.modificationTimestamp)
284291
it.threeDotMenu.isVisible = getCheckedItems().isEmpty()
285292
it.threeDotMenu.contentDescription = context.getString(R.string.content_description_file_operations, file.fileName)
@@ -291,7 +298,7 @@ class FileListAdapter(
291298
fileWithSyncInfo.space?.let { space ->
292299
it.spacePathLine.spaceIcon.isVisible = true
293300
it.spacePathLine.spaceName.isVisible = true
294-
if (space.isPersonal) {
301+
if (space.isPersonal && !isMultiPersonal) {
295302
it.spacePathLine.spaceIcon.setImageResource(R.drawable.ic_folder)
296303
it.spacePathLine.spaceName.setText(R.string.bottom_nav_personal)
297304
} else {

owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListFragment.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* @author Jorge Aguado Recio
99
* @author Aitor Ballesteros Pavón
1010
*
11-
* Copyright (C) 2024 ownCloud GmbH.
11+
* Copyright (C) 2025 ownCloud GmbH.
1212
*
1313
* This program is free software: you can redistribute it and/or modify
1414
* it under the terms of the GNU General Public License version 2,
@@ -385,6 +385,7 @@ class MainFileListFragment : Fragment(),
385385
layoutManager = layoutManager,
386386
isPickerMode = isPickingAFolder(),
387387
listener = this@MainFileListFragment,
388+
isMultiPersonal = isMultiPersonal
388389
)
389390

390391
binding.recyclerViewMainFileList.adapter = fileListAdapter
@@ -633,10 +634,17 @@ class MainFileListFragment : Fragment(),
633634
fileNameBottomSheet.text = file.fileName
634635

635636
val fileSizeBottomSheet = fileOptionsBottomSheetSingleFile.findViewById<TextView>(R.id.file_size_bottom_sheet)
636-
fileSizeBottomSheet.text = DisplayUtils.bytesToHumanReadable(file.length, requireContext(), true)
637+
val isFolderInKw = isMultiPersonal && file.isFolder
638+
fileSizeBottomSheet.text = if (isFolderInKw) "" else DisplayUtils.bytesToHumanReadable(file.length, requireContext(), true)
639+
640+
val fileSeparatorBottomSheet = fileOptionsBottomSheetSingleFile.findViewById<TextView>(R.id.file_separator_bottom_sheet)
641+
fileSeparatorBottomSheet.visibility = if (isFolderInKw) View.GONE else View.VISIBLE
637642

638643
val fileLastModBottomSheet = fileOptionsBottomSheetSingleFile.findViewById<TextView>(R.id.file_last_mod_bottom_sheet)
639644
fileLastModBottomSheet.text = DisplayUtils.getRelativeTimestamp(requireContext(), file.modificationTimestamp)
645+
fileLastModBottomSheet.layoutParams = (fileLastModBottomSheet.layoutParams as ViewGroup.MarginLayoutParams).also {
646+
params -> params.marginStart = if (isFolderInKw) 0 else
647+
requireContext().resources.getDimensionPixelSize(R.dimen.standard_quarter_margin) }
640648

641649
fileOptionsBottomSheetSingleFileLayout = fileOptionsBottomSheetSingleFile.findViewById(R.id.file_options_bottom_sheet_layout)
642650
menuOptions.forEach { menuOption ->

owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransferListFragment.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
* ownCloud Android client application
33
*
44
* @author Juan Carlos Garrote Gascón
5+
* @author Jorge Aguado Recio
56
*
6-
* Copyright (C) 2023 ownCloud GmbH.
7+
* Copyright (C) 2025 ownCloud GmbH.
78
*
89
* This program is free software: you can redistribute it and/or modify
910
* it under the terms of the GNU General Public License version 2,
@@ -20,6 +21,7 @@
2021

2122
package com.owncloud.android.presentation.transfers
2223

24+
import android.accounts.Account
2325
import android.net.Uri
2426
import android.os.Bundle
2527
import android.view.LayoutInflater
@@ -39,13 +41,22 @@ import com.owncloud.android.domain.transfers.model.OCTransfer
3941
import com.owncloud.android.domain.transfers.model.TransferResult
4042
import com.owncloud.android.extensions.collectLatestLifecycleFlow
4143
import com.owncloud.android.presentation.authentication.AccountUtils
44+
import com.owncloud.android.presentation.capabilities.CapabilityViewModel
4245
import com.owncloud.android.ui.activity.FileActivity
4346
import org.koin.androidx.viewmodel.ext.android.viewModel
47+
import org.koin.core.parameter.parametersOf
4448
import java.io.File
4549

46-
class TransferListFragment : Fragment() {
50+
class TransferListFragment(
51+
private val account: Account
52+
) : Fragment() {
4753

4854
private val transfersViewModel by viewModel<TransfersViewModel>()
55+
private val capabilityViewModel: CapabilityViewModel by viewModel {
56+
parametersOf(
57+
account.name,
58+
)
59+
}
4960

5061
private var _binding: FragmentTransferListBinding? = null
5162
val binding get() = _binding!!
@@ -92,6 +103,7 @@ class TransferListFragment : Fragment() {
92103
clearSuccessful = {
93104
transfersViewModel.clearSuccessfulTransfers()
94105
},
106+
isMultipersonal = capabilityViewModel.checkMultiPersonal()
95107
)
96108
binding.transfersRecyclerView.apply {
97109
layoutManager = LinearLayoutManager(context)

owncloudApp/src/main/java/com/owncloud/android/presentation/transfers/TransfersAdapter.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
* ownCloud Android client application
33
*
44
* @author Juan Carlos Garrote Gascón
5+
* @author Jorge Aguado Recio
56
*
6-
* Copyright (C) 2023 ownCloud GmbH.
7+
* Copyright (C) 2025 ownCloud GmbH.
78
*
89
* This program is free software: you can redistribute it and/or modify
910
* it under the terms of the GNU General Public License version 2,
@@ -55,6 +56,7 @@ class TransfersAdapter(
5556
val clearFailed: () -> Unit,
5657
val retryFailed: () -> Unit,
5758
val clearSuccessful: () -> Unit,
59+
private val isMultipersonal: Boolean,
5860
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
5961

6062
private val transferItemsList = mutableListOf<TransferRecyclerItem>()
@@ -113,7 +115,7 @@ class TransfersAdapter(
113115
transferItem.space?.let {
114116
spacePathLine.spaceName.isVisible = true
115117
spacePathLine.spaceIcon.isVisible = true
116-
if (it.isPersonal) {
118+
if (it.isPersonal && !isMultipersonal) {
117119
spacePathLine.spaceIcon.setImageResource(R.drawable.ic_folder)
118120
spacePathLine.spaceName.setText(R.string.bottom_nav_personal)
119121
} else {

owncloudApp/src/main/java/com/owncloud/android/ui/ReceiveExternalFilesViewModel.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* ownCloud Android client application
33
*
4-
* Copyright (C) 2024 ownCloud GmbH.
4+
* Copyright (C) 2025 ownCloud GmbH.
55
* <p>
66
* This program is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU General Public License version 2,
@@ -44,11 +44,16 @@ class ReceiveExternalFilesViewModel(
4444
private val _spacesAreAllowed = MutableLiveData<Boolean>()
4545
val spacesAreAllowed: LiveData<Boolean> = _spacesAreAllowed
4646

47+
private val _isMultiPersonal = MutableLiveData<Boolean>()
48+
val isMultiPersonal: LiveData<Boolean> = _isMultiPersonal
49+
4750
init {
4851
viewModelScope.launch(coroutinesDispatcherProvider.io) {
4952
val capabilities = getStoredCapabilitiesUseCase(GetStoredCapabilitiesUseCase.Params(accountName))
5053
val spacesAvailableForAccount = capabilities?.isSpacesAllowed() == true
5154
_spacesAreAllowed.postValue(spacesAvailableForAccount)
55+
val isMultiPersonalCapability = capabilities?.spaces?.hasMultiplePersonalSpaces == true
56+
_isMultiPersonal.postValue(isMultiPersonalCapability)
5257
}
5358
}
5459

0 commit comments

Comments
 (0)