Skip to content

Commit e0d2ab8

Browse files
committed
feat: implement methods and network operation to update the space image on the server
1 parent c3bf3f6 commit e0d2ab8

File tree

13 files changed

+203
-2
lines changed

13 files changed

+203
-2
lines changed

owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ import com.owncloud.android.domain.sharing.shares.usecases.GetSharesAsLiveDataUs
9191
import com.owncloud.android.domain.sharing.shares.usecases.RefreshSharesFromServerAsyncUseCase
9292
import com.owncloud.android.domain.spaces.usecases.CreateSpaceUseCase
9393
import com.owncloud.android.domain.spaces.usecases.DisableSpaceUseCase
94+
import com.owncloud.android.domain.spaces.usecases.EditSpaceImageUseCase
9495
import com.owncloud.android.domain.spaces.usecases.EditSpaceUseCase
9596
import com.owncloud.android.domain.spaces.usecases.EnableSpaceUseCase
9697
import com.owncloud.android.domain.spaces.usecases.FilterSpaceMenuOptionsUseCase
@@ -229,6 +230,7 @@ val useCaseModule = module {
229230
// Spaces
230231
factoryOf(::CreateSpaceUseCase)
231232
factoryOf(::DisableSpaceUseCase)
233+
factoryOf(::EditSpaceImageUseCase)
232234
factoryOf(::EditSpaceUseCase)
233235
factoryOf(::EnableSpaceUseCase)
234236
factoryOf(::FilterSpaceMenuOptionsUseCase)

owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ val viewModelModule = module {
102102
get()) }
103103
viewModel { ReceiveExternalFilesViewModel(get(), get(), get(), get()) }
104104
viewModel { (accountName: String, showPersonalSpace: Boolean) ->
105-
SpacesListViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), accountName,
105+
SpacesListViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), accountName,
106106
showPersonalSpace)
107107
}
108108
}

owncloudApp/src/main/java/com/owncloud/android/presentation/spaces/SpacesListFragment.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import androidx.appcompat.widget.SearchView
3737
import androidx.core.content.res.ResourcesCompat
3838
import androidx.core.os.bundleOf
3939
import androidx.core.view.isVisible
40+
import androidx.documentfile.provider.DocumentFile
4041
import androidx.fragment.app.Fragment
4142
import androidx.fragment.app.setFragmentResult
4243
import androidx.recyclerview.widget.GridLayoutManager
@@ -48,6 +49,7 @@ import com.owncloud.android.databinding.SpacesListFragmentBinding
4849
import com.owncloud.android.domain.files.model.FileListOption
4950
import com.owncloud.android.domain.spaces.model.OCSpace
5051
import com.owncloud.android.domain.spaces.model.SpaceMenuOption
52+
import com.owncloud.android.domain.transfers.model.TransferStatus
5153
import com.owncloud.android.domain.user.model.UserPermissions
5254
import com.owncloud.android.domain.utils.Event
5355
import com.owncloud.android.extensions.collectLatestLifecycleFlow
@@ -82,6 +84,8 @@ class SpacesListFragment :
8284
private var isMultiPersonal = false
8385
private var userPermissions = mutableSetOf<UserPermissions>()
8486
private var editQuotaPermission = false
87+
private var lastUpdatedRemotePath: String? = null
88+
private var selectedImageName: String? = null
8589
private lateinit var currentSpace: OCSpace
8690

8791
private val spacesListViewModel: SpacesListViewModel by viewModel {
@@ -103,6 +107,8 @@ class SpacesListFragment :
103107

104108
val selectedImageUri = result.data?.data ?: return@registerForActivityResult
105109
val accountName = requireArguments().getString(BUNDLE_ACCOUNT_NAME) ?: return@registerForActivityResult
110+
val documentFile = DocumentFile.fromSingleUri(requireContext(), selectedImageUri) ?: return@registerForActivityResult
111+
selectedImageName = documentFile.name
106112

107113
transfersViewModel.uploadFilesFromContentUri(
108114
accountName = accountName,
@@ -222,6 +228,7 @@ class SpacesListFragment :
222228

223229
collectSpaceOperationsFlow(spacesListViewModel.createSpaceFlow, R.string.create_space_correctly, R.string.create_space_failed)
224230
collectSpaceOperationsFlow(spacesListViewModel.editSpaceFlow, R.string.edit_space_correctly, R.string.edit_space_failed)
231+
collectSpaceOperationsFlow(spacesListViewModel.editSpaceImageFlow, R.string.edit_space_image_correctly, R.string.edit_space_image_failed)
225232
collectSpaceOperationsFlow(spacesListViewModel.disableSpaceFlow, R.string.disable_space_correctly, R.string.disable_space_failed)
226233
collectSpaceOperationsFlow(spacesListViewModel.enableSpaceFlow, R.string.enable_space_correctly, R.string.enable_space_failed)
227234
collectSpaceOperationsFlow(spacesListViewModel.deleteSpaceFlow, R.string.delete_space_correctly, R.string.delete_space_failed)
@@ -230,6 +237,17 @@ class SpacesListFragment :
230237
showSpaceMenuOptionsDialog(menuOptions)
231238
}
232239

240+
collectLatestLifecycleFlow(transfersViewModel.transfersWithSpaceStateFlow) { transfersWithSpace->
241+
val remotePath = SPACE_CONFIG_DIR + selectedImageName
242+
val matchedTransfer = transfersWithSpace.map { it.first }.find { it.remotePath == remotePath }
243+
244+
if (matchedTransfer != null && matchedTransfer.status == TransferStatus.TRANSFER_SUCCEEDED &&
245+
lastUpdatedRemotePath != matchedTransfer.remotePath && lastUpdatedRemotePath != null) {
246+
spacesListViewModel.editSpaceImage(currentSpace.id, matchedTransfer.remotePath)
247+
lastUpdatedRemotePath = matchedTransfer.remotePath
248+
}
249+
}
250+
233251
}
234252

235253
private fun collectSpaceOperationsFlow(flow: SharedFlow<Event<UIResult<Unit>>?>, successMessage: Int, errorMessage: Int) {

owncloudApp/src/main/java/com/owncloud/android/presentation/spaces/SpacesListViewModel.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import com.owncloud.android.domain.spaces.model.OCSpace
3333
import com.owncloud.android.domain.spaces.model.SpaceMenuOption
3434
import com.owncloud.android.domain.spaces.usecases.CreateSpaceUseCase
3535
import com.owncloud.android.domain.spaces.usecases.DisableSpaceUseCase
36+
import com.owncloud.android.domain.spaces.usecases.EditSpaceImageUseCase
3637
import com.owncloud.android.domain.spaces.usecases.EditSpaceUseCase
3738
import com.owncloud.android.domain.spaces.usecases.EnableSpaceUseCase
3839
import com.owncloud.android.domain.spaces.usecases.FilterSpaceMenuOptionsUseCase
@@ -66,6 +67,7 @@ class SpacesListViewModel(
6667
private val createSpaceUseCase: CreateSpaceUseCase,
6768
private val filterSpaceMenuOptionsUseCase: FilterSpaceMenuOptionsUseCase,
6869
private val editSpaceUseCase: EditSpaceUseCase,
70+
private val editSpaceImageUseCase: EditSpaceImageUseCase,
6971
private val disableSpaceUseCase: DisableSpaceUseCase,
7072
private val enableSpaceUseCase: EnableSpaceUseCase,
7173
private val coroutinesDispatcherProvider: CoroutinesDispatcherProvider,
@@ -92,6 +94,9 @@ class SpacesListViewModel(
9294
private val _editSpaceFlow = MutableSharedFlow<Event<UIResult<Unit>>?>()
9395
val editSpaceFlow: SharedFlow<Event<UIResult<Unit>>?> = _editSpaceFlow
9496

97+
private val _editSpaceImageFlow = MutableSharedFlow<Event<UIResult<Unit>>?>()
98+
val editSpaceImageFlow: SharedFlow<Event<UIResult<Unit>>?> = _editSpaceImageFlow
99+
95100
private val _disableSpaceFlow = MutableSharedFlow<Event<UIResult<Unit>>?>()
96101
val disableSpaceFlow: SharedFlow<Event<UIResult<Unit>>?> = _disableSpaceFlow
97102

@@ -224,6 +229,14 @@ class SpacesListViewModel(
224229
)
225230
}
226231

232+
fun editSpaceImage(spaceId: String, remotePath: String) {
233+
runSpaceOperation(
234+
flow = _editSpaceImageFlow,
235+
useCase = editSpaceImageUseCase,
236+
useCaseParams = EditSpaceImageUseCase.Params(accountName, spaceId, remotePath)
237+
)
238+
}
239+
227240
private fun <Params> runSpaceOperation(
228241
flow: MutableSharedFlow<Event<UIResult<Unit>>?>,
229242
useCase: BaseUseCaseWithResult<Unit, Params>,

owncloudApp/src/main/res/values/strings.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,9 +849,11 @@
849849
<string name="create_space_correctly">Space created correctly</string>
850850
<string name="create_space_failed">Space could not be created</string>
851851
<string name="edit_space">Edit space</string>
852-
<string name="edit_space_image">Edit space image</string>
853852
<string name="edit_space_correctly">Space updated correctly</string>
854853
<string name="edit_space_failed">Space could not be updated</string>
854+
<string name="edit_space_image">Edit space image</string>
855+
<string name="edit_space_image_correctly">Space image updated correctly</string>
856+
<string name="edit_space_image_failed">Space image could not be updated</string>
855857
<string name="disable_space">Disable space</string>
856858
<string name="disable_space_dialog_title">Do you really want to disable the space: %1$s?</string>
857859
<string name="disable_space_dialog_message">If you disable the selected space, it can no longer be accessed. Only Space managers will still have access. Note: No files will be deleted from the server.</string>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* ownCloud Android client application
3+
*
4+
* @author Jorge Aguado Recio
5+
*
6+
* Copyright (C) 2025 ownCloud GmbH.
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License version 2,
10+
* as published by the Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
22+
package com.owncloud.android.lib.resources.spaces
23+
24+
import com.owncloud.android.lib.common.OwnCloudClient
25+
import com.owncloud.android.lib.common.http.HttpConstants
26+
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_JSON
27+
import com.owncloud.android.lib.common.http.methods.nonwebdav.PatchMethod
28+
import com.owncloud.android.lib.common.operations.RemoteOperation
29+
import com.owncloud.android.lib.common.operations.RemoteOperationResult
30+
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
31+
import com.owncloud.android.lib.resources.spaces.responses.SpaceResponse
32+
import com.squareup.moshi.JsonAdapter
33+
import com.squareup.moshi.Moshi
34+
import okhttp3.MediaType.Companion.toMediaType
35+
import okhttp3.RequestBody.Companion.toRequestBody
36+
import org.json.JSONArray
37+
import org.json.JSONObject
38+
import timber.log.Timber
39+
import java.net.URL
40+
41+
class EditRemoteSpaceImageOperation(
42+
private val spaceId: String,
43+
private val imageId: String
44+
): RemoteOperation<SpaceResponse>() {
45+
override fun run(client: OwnCloudClient): RemoteOperationResult<SpaceResponse> {
46+
var result: RemoteOperationResult<SpaceResponse>
47+
try {
48+
val moshi = Moshi.Builder().build()
49+
50+
val uriBuilder = client.baseUri.buildUpon().apply {
51+
appendEncodedPath(GRAPH_API_SPACES_PATH)
52+
appendEncodedPath(spaceId)
53+
}
54+
55+
val specialFolder = JSONObject().apply {
56+
put(SPACE_NAME_BODY_PARAM, SPACE_NAME_BODY_PARAM_VALUE)
57+
}
58+
59+
val specialEntry = JSONObject().apply {
60+
put(SPACE_ID_BODY_PARAM, imageId)
61+
put(SPACE_SPECIAL_FOLDER_BODY_PARAM, specialFolder)
62+
}
63+
64+
val requestBody = JSONObject().apply {
65+
put(SPACE_SPECIAL_BODY_PARAM, JSONArray().apply { put(specialEntry) })
66+
}.toString().toRequestBody(CONTENT_TYPE_JSON.toMediaType())
67+
68+
69+
val patchMethod = PatchMethod(URL(uriBuilder.build().toString()), requestBody)
70+
71+
val status = client.executeHttpMethod(patchMethod)
72+
73+
val response = patchMethod.getResponseBodyAsString()
74+
75+
if (status == HttpConstants.HTTP_OK) {
76+
Timber.d("Successful response: $response")
77+
78+
val responseAdapter: JsonAdapter<SpaceResponse> = moshi.adapter(SpaceResponse::class.java)
79+
80+
result = RemoteOperationResult(ResultCode.OK)
81+
result.data = responseAdapter.fromJson(response)
82+
83+
Timber.d("Update of space completed and parsed to ${result.data}")
84+
} else {
85+
result = RemoteOperationResult(patchMethod)
86+
Timber.e("Failed response while updating the space; status code: $status, response: $response")
87+
}
88+
} catch (e: Exception) {
89+
result = RemoteOperationResult(e)
90+
Timber.e(e, "Exception while updating the space $spaceId")
91+
}
92+
return result
93+
}
94+
95+
companion object {
96+
private const val GRAPH_API_SPACES_PATH = "graph/v1.0/drives/"
97+
private const val SPACE_SPECIAL_BODY_PARAM = "special"
98+
private const val SPACE_ID_BODY_PARAM = "id"
99+
private const val SPACE_SPECIAL_FOLDER_BODY_PARAM = "specialFolder"
100+
private const val SPACE_NAME_BODY_PARAM = "name"
101+
private const val SPACE_NAME_BODY_PARAM_VALUE = "image"
102+
}
103+
104+
}

owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/spaces/services/OCSpacesService.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.owncloud.android.lib.common.OwnCloudClient
2626
import com.owncloud.android.lib.common.operations.RemoteOperationResult
2727
import com.owncloud.android.lib.resources.spaces.CreateRemoteSpaceOperation
2828
import com.owncloud.android.lib.resources.spaces.DisableRemoteSpaceOperation
29+
import com.owncloud.android.lib.resources.spaces.EditRemoteSpaceImageOperation
2930
import com.owncloud.android.lib.resources.spaces.EditRemoteSpaceOperation
3031
import com.owncloud.android.lib.resources.spaces.EnableRemoteSpaceOperation
3132
import com.owncloud.android.lib.resources.spaces.GetRemoteSpacePermissionsOperation
@@ -45,6 +46,9 @@ class OCSpacesService(override val client: OwnCloudClient) : SpacesService {
4546
override fun editSpace(spaceId: String, spaceName: String, spaceSubtitle: String, spaceQuota: Long?): RemoteOperationResult<SpaceResponse> =
4647
EditRemoteSpaceOperation(spaceId, spaceName, spaceSubtitle, spaceQuota).execute(client)
4748

49+
override fun editSpaceImage(spaceId: String, imageId: String): RemoteOperationResult<SpaceResponse> =
50+
EditRemoteSpaceImageOperation(spaceId, imageId).execute(client)
51+
4852
override fun disableSpace(spaceId: String, deleteMode: Boolean): RemoteOperationResult<Unit> =
4953
DisableRemoteSpaceOperation(spaceId, deleteMode).execute(client)
5054

owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/spaces/services/SpacesService.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ interface SpacesService : Service {
3131
fun createSpace(spaceName: String, spaceSubtitle: String, spaceQuota: Long): RemoteOperationResult<SpaceResponse>
3232
fun getSpacePermissions(spaceId: String): RemoteOperationResult<List<String>>
3333
fun editSpace(spaceId: String, spaceName: String, spaceSubtitle: String, spaceQuota: Long?): RemoteOperationResult<SpaceResponse>
34+
fun editSpaceImage(spaceId: String, imageId: String): RemoteOperationResult<SpaceResponse>
3435
fun disableSpace(spaceId: String, deleteMode: Boolean): RemoteOperationResult<Unit>
3536
fun enableSpace(spaceId: String): RemoteOperationResult<SpaceResponse>
3637
}

owncloudData/src/main/java/com/owncloud/android/data/spaces/datasources/RemoteSpacesDataSource.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ interface RemoteSpacesDataSource {
2727
fun createSpace(accountName: String, spaceName: String, spaceSubtitle: String, spaceQuota: Long): OCSpace
2828
fun getSpacePermissions(accountName: String, spaceId: String): List<String>
2929
fun editSpace(accountName: String, spaceId: String, spaceName: String, spaceSubtitle: String, spaceQuota: Long?): OCSpace
30+
fun editSpaceImage(accountName: String, spaceId: String, imageId: String): OCSpace
3031
fun disableSpace(accountName: String, spaceId: String, deleteMode: Boolean)
3132
fun enableSpace(accountName: String, spaceId: String)
3233
}

owncloudData/src/main/java/com/owncloud/android/data/spaces/datasources/implementation/OCRemoteSpacesDataSource.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ class OCRemoteSpacesDataSource(
6464
return spaceResponse.toModel(accountName)
6565
}
6666

67+
override fun editSpaceImage(accountName: String, spaceId: String, imageId: String): OCSpace {
68+
val spaceResponse = executeRemoteOperation {
69+
clientManager.getSpacesService(accountName).editSpaceImage(spaceId, imageId)
70+
}
71+
return spaceResponse.toModel(accountName)
72+
}
73+
6774
override fun disableSpace(accountName: String, spaceId: String, deleteMode: Boolean) {
6875
executeRemoteOperation { clientManager.getSpacesService(accountName).disableSpace(spaceId, deleteMode) }
6976
}

0 commit comments

Comments
 (0)