Skip to content

Commit 8db3f87

Browse files
authored
Merge pull request #4696 from owncloud/feature/space_lifecycle_operations
[FEATURE REQUEST] Disable/Remove space
2 parents cfb23ab + 273015c commit 8db3f87

File tree

28 files changed

+650
-60
lines changed

28 files changed

+650
-60
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ ownCloud admins and users.
4949
* Enhancement - Add account ID to the user information: [#4605](https://github.com/owncloud/android/issues/4605)
5050
* Enhancement - Create a new space: [#4606](https://github.com/owncloud/android/issues/4606)
5151
* Enhancement - Edit a space: [#4607](https://github.com/owncloud/android/issues/4607)
52+
* Enhancement - Disable/Remove a space: [#4611](https://github.com/owncloud/android/issues/4611)
5253
* Enhancement - Update test in GitHub Actions: [#4663](https://github.com/owncloud/android/pull/4663)
5354
* Enhancement - New workflow to generate a build from "latest" tag on demand: [#4681](https://github.com/owncloud/android/pull/4681)
5455
* Enhancement - Make Update test more robust: [#4690](https://github.com/owncloud/android/pull/4690)
@@ -143,6 +144,15 @@ ownCloud admins and users.
143144
https://github.com/owncloud/android/pull/4687
144145
https://github.com/owncloud/android/pull/4694
145146

147+
* Enhancement - Disable/Remove a space: [#4611](https://github.com/owncloud/android/issues/4611)
148+
149+
New options to disable, enable and remove spaces have been added to the bottom
150+
sheet, available only to users with the required permissions when the three-dot
151+
menu button is tapped.
152+
153+
https://github.com/owncloud/android/issues/4611
154+
https://github.com/owncloud/android/pull/4696
155+
146156
* Enhancement - Update test in GitHub Actions: [#4663](https://github.com/owncloud/android/pull/4663)
147157

148158
A new Github Actions workflow has been added, in order to check whether the

changelog/unreleased/4696

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Enhancement: Disable/Remove a space
2+
3+
New options to disable, enable and remove spaces have been added to the bottom sheet, available only to users
4+
with the required permissions when the three-dot menu button is tapped.
5+
6+
https://github.com/owncloud/android/issues/4611
7+
https://github.com/owncloud/android/pull/4696

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ import com.owncloud.android.domain.sharing.shares.usecases.GetShareAsLiveDataUse
9090
import com.owncloud.android.domain.sharing.shares.usecases.GetSharesAsLiveDataUseCase
9191
import com.owncloud.android.domain.sharing.shares.usecases.RefreshSharesFromServerAsyncUseCase
9292
import com.owncloud.android.domain.spaces.usecases.CreateSpaceUseCase
93+
import com.owncloud.android.domain.spaces.usecases.DisableSpaceUseCase
9394
import com.owncloud.android.domain.spaces.usecases.EditSpaceUseCase
95+
import com.owncloud.android.domain.spaces.usecases.EnableSpaceUseCase
9496
import com.owncloud.android.domain.spaces.usecases.FilterSpaceMenuOptionsUseCase
9597
import com.owncloud.android.domain.spaces.usecases.GetPersonalAndProjectSpacesForAccountUseCase
9698
import com.owncloud.android.domain.spaces.usecases.GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase
@@ -226,7 +228,9 @@ val useCaseModule = module {
226228

227229
// Spaces
228230
factoryOf(::CreateSpaceUseCase)
231+
factoryOf(::DisableSpaceUseCase)
229232
factoryOf(::EditSpaceUseCase)
233+
factoryOf(::EnableSpaceUseCase)
230234
factoryOf(::FilterSpaceMenuOptionsUseCase)
231235
factoryOf(::GetPersonalAndProjectSpacesForAccountUseCase)
232236
factoryOf(::GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase)

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +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(), accountName, showPersonalSpace)
105+
SpacesListViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), accountName,
106+
showPersonalSpace)
106107
}
107108
}

owncloudApp/src/main/java/com/owncloud/android/extensions/SpaceMenuOptionExt.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,15 @@ import com.owncloud.android.domain.spaces.model.SpaceMenuOption
2626
fun SpaceMenuOption.toStringResId() =
2727
when (this) {
2828
SpaceMenuOption.EDIT -> R.string.edit_space
29+
SpaceMenuOption.DISABLE -> R.string.disable_space
30+
SpaceMenuOption.ENABLE -> R.string.enable_space
31+
SpaceMenuOption.DELETE -> R.string.delete_space
2932
}
3033

3134
fun SpaceMenuOption.toDrawableResId() =
3235
when (this) {
3336
SpaceMenuOption.EDIT -> R.drawable.ic_pencil
37+
SpaceMenuOption.DISABLE -> R.drawable.ic_disable_space
38+
SpaceMenuOption.ENABLE -> R.drawable.ic_enable_space
39+
SpaceMenuOption.DELETE -> R.drawable.ic_action_delete_white
3440
}

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
package com.owncloud.android.presentation.spaces
2525

2626
import android.view.LayoutInflater
27+
import android.view.View
2728
import android.view.ViewGroup
2829
import android.widget.Button
2930
import androidx.core.content.ContextCompat
@@ -55,10 +56,13 @@ class SpacesListAdapter(
5556
val spacesViewHolder = holder as SpacesViewHolder
5657
spacesViewHolder.binding.apply {
5758
val space = spacesList[position]
58-
59-
spacesListItemCard.setOnClickListener {
60-
listener.onItemClick(space)
59+
if (space.isDisabled) {
60+
spacesListItemCard.isClickable = false
61+
} else {
62+
spacesListItemCard.setOnClickListener { listener.onItemClick(space) }
6163
}
64+
spacesListItemImage.alpha = if (space.isDisabled) 0.5f else 1f
65+
spacesListItemDisabledLabel.visibility = if (space.isDisabled) View.VISIBLE else View.GONE
6266
spacesListItemCard.setAccessibilityRole(className = Button::class.java)
6367
spacesListItemName.contentDescription = holder.itemView.context.getString(R.string.content_description_space_name, space.name)
6468
spacesThreeDotMenu.contentDescription = holder.itemView.context.getString(R.string.content_description_space_three_dot_menu, space.name)

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

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
package com.owncloud.android.presentation.spaces
2424

25+
import android.content.DialogInterface
2526
import android.content.res.Configuration
2627
import android.os.Bundle
2728
import android.view.LayoutInflater
@@ -44,7 +45,10 @@ import com.owncloud.android.databinding.SpacesListFragmentBinding
4445
import com.owncloud.android.domain.files.model.FileListOption
4546
import com.owncloud.android.domain.spaces.model.OCSpace
4647
import com.owncloud.android.domain.spaces.model.SpaceMenuOption
48+
import com.owncloud.android.domain.user.model.UserPermissions
49+
import com.owncloud.android.domain.utils.Event
4750
import com.owncloud.android.extensions.collectLatestLifecycleFlow
51+
import com.owncloud.android.extensions.showAlertDialog
4852
import com.owncloud.android.extensions.showErrorInSnackbar
4953
import com.owncloud.android.extensions.showMessageInSnackbar
5054
import com.owncloud.android.extensions.toDrawableRes
@@ -57,6 +61,7 @@ import com.owncloud.android.presentation.common.BottomSheetFragmentItemView
5761
import com.owncloud.android.utils.DisplayUtils
5862
import com.owncloud.android.presentation.common.UIResult
5963
import com.owncloud.android.presentation.spaces.createspace.CreateSpaceDialogFragment
64+
import kotlinx.coroutines.flow.SharedFlow
6065
import org.koin.androidx.viewmodel.ext.android.viewModel
6166
import org.koin.core.parameter.parametersOf
6267
import timber.log.Timber
@@ -71,7 +76,7 @@ class SpacesListFragment :
7176
private val binding get() = _binding!!
7277

7378
private var isMultiPersonal = false
74-
private var editSpacesPermission = false
79+
private var userPermissions = mutableSetOf<UserPermissions>()
7580
private var editQuotaPermission = false
7681
private lateinit var currentSpace: OCSpace
7782

@@ -136,7 +141,7 @@ class SpacesListFragment :
136141
collectLatestLifecycleFlow(spacesListViewModel.spacesList) { uiState ->
137142
if (uiState.searchFilter != "") {
138143
var spacesToListFiltered =
139-
uiState.spaces.filter { it.name.lowercase().contains(uiState.searchFilter.lowercase()) && !it.isPersonal && !it.isDisabled }
144+
uiState.spaces.filter { it.name.lowercase().contains(uiState.searchFilter.lowercase()) && !it.isPersonal }
140145
val personalSpace = uiState.spaces.find { it.isPersonal }
141146
personalSpace?.let {
142147
spacesToListFiltered = spacesToListFiltered.toMutableList().apply {
@@ -147,7 +152,7 @@ class SpacesListFragment :
147152
spacesListAdapter.setData(spacesToListFiltered, isMultiPersonal)
148153
} else {
149154
showOrHideEmptyView(uiState.spaces)
150-
spacesListAdapter.setData(uiState.spaces.filter { !it.isDisabled }, isMultiPersonal)
155+
spacesListAdapter.setData(uiState.spaces, isMultiPersonal)
151156
}
152157
binding.swipeRefreshSpacesList.isRefreshing = uiState.refreshing
153158
uiState.error?.let { showErrorInSnackbar(R.string.spaces_sync_failed, it) }
@@ -181,8 +186,9 @@ class SpacesListFragment :
181186
Timber.d("The permissions for $accountName are: ${uiResult.data}")
182187
uiResult.data?.let {
183188
binding.fabCreateSpace.isVisible = it.contains(DRIVES_CREATE_ALL_PERMISSION)
184-
editSpacesPermission = it.contains(DRIVES_READ_WRITE_ALL_PERMISSION)
189+
if(it.contains(DRIVES_READ_WRITE_ALL_PERMISSION)) userPermissions.add(UserPermissions.CAN_EDIT_SPACES)
185190
editQuotaPermission = it.contains(DRIVES_READ_WRITE_PROJECT_QUOTA_ALL_PERMISSION)
191+
if(it.contains(DRIVES_DELETE_PROJECT_ALL_PERMISSION)) userPermissions.add(UserPermissions.CAN_DELETE_SPACES)
186192
}
187193
}
188194
is UIResult.Loading -> { }
@@ -194,30 +200,28 @@ class SpacesListFragment :
194200
}
195201
}
196202

197-
collectLatestLifecycleFlow(spacesListViewModel.createSpaceFlow) { event ->
198-
event?.let {
199-
when (val uiResult = event.peekContent()) {
200-
is UIResult.Success -> { showMessageInSnackbar(getString(R.string.create_space_correctly)) }
201-
is UIResult.Loading -> { }
202-
is UIResult.Error -> { showErrorInSnackbar(R.string.create_space_failed, uiResult.error) }
203-
}
204-
}
203+
collectSpaceOperationsFlow(spacesListViewModel.createSpaceFlow, R.string.create_space_correctly, R.string.create_space_failed)
204+
collectSpaceOperationsFlow(spacesListViewModel.editSpaceFlow, R.string.edit_space_correctly, R.string.edit_space_failed)
205+
collectSpaceOperationsFlow(spacesListViewModel.disableSpaceFlow, R.string.disable_space_correctly, R.string.disable_space_failed)
206+
collectSpaceOperationsFlow(spacesListViewModel.enableSpaceFlow, R.string.enable_space_correctly, R.string.enable_space_failed)
207+
collectSpaceOperationsFlow(spacesListViewModel.deleteSpaceFlow, R.string.delete_space_correctly, R.string.delete_space_failed)
208+
209+
collectLatestLifecycleFlow(spacesListViewModel.menuOptions) { menuOptions ->
210+
showSpaceMenuOptionsDialog(menuOptions)
205211
}
206212

207-
collectLatestLifecycleFlow(spacesListViewModel.editSpaceFlow) { event ->
213+
}
214+
215+
private fun collectSpaceOperationsFlow(flow: SharedFlow<Event<UIResult<Unit>>?>, successMessage: Int, errorMessage: Int) {
216+
collectLatestLifecycleFlow(flow) { event ->
208217
event?.let {
209218
when (val uiResult = event.peekContent()) {
210-
is UIResult.Success -> { showMessageInSnackbar(getString(R.string.edit_space_correctly)) }
219+
is UIResult.Success -> { showMessageInSnackbar(getString(successMessage)) }
211220
is UIResult.Loading -> { }
212-
is UIResult.Error -> { showErrorInSnackbar(R.string.edit_space_failed, uiResult.error) }
221+
is UIResult.Error -> { showErrorInSnackbar(errorMessage, uiResult.error) }
213222
}
214223
}
215224
}
216-
217-
collectLatestLifecycleFlow(spacesListViewModel.menuOptions) { menuOptions ->
218-
showSpaceMenuOptionsDialog(menuOptions)
219-
}
220-
221225
}
222226

223227
private fun showOrHideEmptyView(spacesList: List<OCSpace>) {
@@ -243,7 +247,7 @@ class SpacesListFragment :
243247

244248
override fun onThreeDotButtonClick(ocSpace: OCSpace) {
245249
currentSpace = ocSpace
246-
spacesListViewModel.filterMenuOptions(ocSpace, editSpacesPermission)
250+
spacesListViewModel.filterMenuOptions(ocSpace, userPermissions)
247251
}
248252

249253
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@@ -337,6 +341,33 @@ class SpacesListFragment :
337341
)
338342
editDialog.show(requireActivity().supportFragmentManager, DIALOG_CREATE_SPACE)
339343
}
344+
SpaceMenuOption.DISABLE -> {
345+
showAlertDialog(
346+
title = getString(R.string.disable_space_dialog_title, currentSpace.name),
347+
message = getString(R.string.disable_space_dialog_message),
348+
positiveButtonText = getString(R.string.common_yes),
349+
positiveButtonListener = { _: DialogInterface?, _: Int -> spacesListViewModel.disableSpace(currentSpace.id) },
350+
negativeButtonText = getString(R.string.common_no)
351+
)
352+
}
353+
SpaceMenuOption.ENABLE -> {
354+
showAlertDialog(
355+
title = getString(R.string.enable_space_dialog_title, currentSpace.name),
356+
message = getString(R.string.enable_space_dialog_message),
357+
positiveButtonText = getString(R.string.common_yes),
358+
positiveButtonListener = { _: DialogInterface?, _: Int -> spacesListViewModel.enableSpace(currentSpace.id) },
359+
negativeButtonText = getString(R.string.common_no)
360+
)
361+
}
362+
SpaceMenuOption.DELETE -> {
363+
showAlertDialog(
364+
title = getString(R.string.delete_space_dialog_title, currentSpace.name),
365+
message = getString(R.string.delete_space_dialog_message),
366+
positiveButtonText = getString(R.string.common_yes),
367+
positiveButtonListener = { _: DialogInterface?, _: Int -> spacesListViewModel.deleteSpace(currentSpace.id) },
368+
negativeButtonText = getString(R.string.common_no)
369+
)
370+
}
340371
}
341372
}
342373
}
@@ -351,6 +382,7 @@ class SpacesListFragment :
351382
const val DRIVES_CREATE_ALL_PERMISSION = "Drives.Create.all"
352383
const val DRIVES_READ_WRITE_ALL_PERMISSION = "Drives.ReadWrite.all"
353384
const val DRIVES_READ_WRITE_PROJECT_QUOTA_ALL_PERMISSION = "Drives.ReadWriteProjectQuota.all"
385+
const val DRIVES_DELETE_PROJECT_ALL_PERMISSION = "Drives.DeleteProject.all"
354386

355387
private const val DIALOG_CREATE_SPACE = "DIALOG_CREATE_SPACE"
356388

0 commit comments

Comments
 (0)