Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ ownCloud admins and users.
* Enhancement - Add account ID to the user information: [#4605](https://github.com/owncloud/android/issues/4605)
* Enhancement - Create a new space: [#4606](https://github.com/owncloud/android/issues/4606)
* Enhancement - Edit a space: [#4607](https://github.com/owncloud/android/issues/4607)
* Enhancement - Disable/Remove a space: [#4611](https://github.com/owncloud/android/issues/4611)
* Enhancement - Update test in GitHub Actions: [#4663](https://github.com/owncloud/android/pull/4663)
* Enhancement - New workflow to generate a build from "latest" tag on demand: [#4681](https://github.com/owncloud/android/pull/4681)
* Enhancement - Make Update test more robust: [#4690](https://github.com/owncloud/android/pull/4690)
Expand Down Expand Up @@ -143,6 +144,15 @@ ownCloud admins and users.
https://github.com/owncloud/android/pull/4687
https://github.com/owncloud/android/pull/4694

* Enhancement - Disable/Remove a space: [#4611](https://github.com/owncloud/android/issues/4611)

New options to disable, enable and remove spaces have been added to the bottom
sheet, available only to users with the required permissions when the three-dot
menu button is tapped.

https://github.com/owncloud/android/issues/4611
https://github.com/owncloud/android/pull/4696

* Enhancement - Update test in GitHub Actions: [#4663](https://github.com/owncloud/android/pull/4663)

A new Github Actions workflow has been added, in order to check whether the
Expand Down
7 changes: 7 additions & 0 deletions changelog/unreleased/4696
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Disable/Remove a space

New options to disable, enable and remove spaces have been added to the bottom sheet, available only to users
with the required permissions when the three-dot menu button is tapped.

https://github.com/owncloud/android/issues/4611
https://github.com/owncloud/android/pull/4696
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ import com.owncloud.android.domain.sharing.shares.usecases.GetShareAsLiveDataUse
import com.owncloud.android.domain.sharing.shares.usecases.GetSharesAsLiveDataUseCase
import com.owncloud.android.domain.sharing.shares.usecases.RefreshSharesFromServerAsyncUseCase
import com.owncloud.android.domain.spaces.usecases.CreateSpaceUseCase
import com.owncloud.android.domain.spaces.usecases.DisableSpaceUseCase
import com.owncloud.android.domain.spaces.usecases.EditSpaceUseCase
import com.owncloud.android.domain.spaces.usecases.EnableSpaceUseCase
import com.owncloud.android.domain.spaces.usecases.FilterSpaceMenuOptionsUseCase
import com.owncloud.android.domain.spaces.usecases.GetPersonalAndProjectSpacesForAccountUseCase
import com.owncloud.android.domain.spaces.usecases.GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase
Expand Down Expand Up @@ -226,7 +228,9 @@ val useCaseModule = module {

// Spaces
factoryOf(::CreateSpaceUseCase)
factoryOf(::DisableSpaceUseCase)
factoryOf(::EditSpaceUseCase)
factoryOf(::EnableSpaceUseCase)
factoryOf(::FilterSpaceMenuOptionsUseCase)
factoryOf(::GetPersonalAndProjectSpacesForAccountUseCase)
factoryOf(::GetPersonalAndProjectSpacesWithSpecialsForAccountAsStreamUseCase)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ val viewModelModule = module {
get()) }
viewModel { ReceiveExternalFilesViewModel(get(), get(), get(), get()) }
viewModel { (accountName: String, showPersonalSpace: Boolean) ->
SpacesListViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), accountName, showPersonalSpace)
SpacesListViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), accountName,
showPersonalSpace)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ import com.owncloud.android.domain.spaces.model.SpaceMenuOption
fun SpaceMenuOption.toStringResId() =
when (this) {
SpaceMenuOption.EDIT -> R.string.edit_space
SpaceMenuOption.DISABLE -> R.string.disable_space
SpaceMenuOption.ENABLE -> R.string.enable_space
SpaceMenuOption.DELETE -> R.string.delete_space
}

fun SpaceMenuOption.toDrawableResId() =
when (this) {
SpaceMenuOption.EDIT -> R.drawable.ic_pencil
SpaceMenuOption.DISABLE -> R.drawable.ic_disable_space
SpaceMenuOption.ENABLE -> R.drawable.ic_enable_space
SpaceMenuOption.DELETE -> R.drawable.ic_action_delete_white
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package com.owncloud.android.presentation.spaces

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.core.content.ContextCompat
Expand Down Expand Up @@ -55,10 +56,13 @@ class SpacesListAdapter(
val spacesViewHolder = holder as SpacesViewHolder
spacesViewHolder.binding.apply {
val space = spacesList[position]

spacesListItemCard.setOnClickListener {
listener.onItemClick(space)
if (space.isDisabled) {
spacesListItemCard.isClickable = false
} else {
spacesListItemCard.setOnClickListener { listener.onItemClick(space) }
}
spacesListItemImage.alpha = if (space.isDisabled) 0.5f else 1f
spacesListItemDisabledLabel.visibility = if (space.isDisabled) View.VISIBLE else View.GONE
spacesListItemCard.setAccessibilityRole(className = Button::class.java)
spacesListItemName.contentDescription = holder.itemView.context.getString(R.string.content_description_space_name, space.name)
spacesThreeDotMenu.contentDescription = holder.itemView.context.getString(R.string.content_description_space_three_dot_menu, space.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

package com.owncloud.android.presentation.spaces

import android.content.DialogInterface
import android.content.res.Configuration
import android.os.Bundle
import android.view.LayoutInflater
Expand All @@ -44,7 +45,10 @@ import com.owncloud.android.databinding.SpacesListFragmentBinding
import com.owncloud.android.domain.files.model.FileListOption
import com.owncloud.android.domain.spaces.model.OCSpace
import com.owncloud.android.domain.spaces.model.SpaceMenuOption
import com.owncloud.android.domain.user.model.UserPermissions
import com.owncloud.android.domain.utils.Event
import com.owncloud.android.extensions.collectLatestLifecycleFlow
import com.owncloud.android.extensions.showAlertDialog
import com.owncloud.android.extensions.showErrorInSnackbar
import com.owncloud.android.extensions.showMessageInSnackbar
import com.owncloud.android.extensions.toDrawableRes
Expand All @@ -57,6 +61,7 @@ import com.owncloud.android.presentation.common.BottomSheetFragmentItemView
import com.owncloud.android.utils.DisplayUtils
import com.owncloud.android.presentation.common.UIResult
import com.owncloud.android.presentation.spaces.createspace.CreateSpaceDialogFragment
import kotlinx.coroutines.flow.SharedFlow
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import timber.log.Timber
Expand All @@ -71,7 +76,7 @@ class SpacesListFragment :
private val binding get() = _binding!!

private var isMultiPersonal = false
private var editSpacesPermission = false
private var userPermissions = mutableSetOf<UserPermissions>()
private var editQuotaPermission = false
private lateinit var currentSpace: OCSpace

Expand Down Expand Up @@ -136,7 +141,7 @@ class SpacesListFragment :
collectLatestLifecycleFlow(spacesListViewModel.spacesList) { uiState ->
if (uiState.searchFilter != "") {
var spacesToListFiltered =
uiState.spaces.filter { it.name.lowercase().contains(uiState.searchFilter.lowercase()) && !it.isPersonal && !it.isDisabled }
uiState.spaces.filter { it.name.lowercase().contains(uiState.searchFilter.lowercase()) && !it.isPersonal }
val personalSpace = uiState.spaces.find { it.isPersonal }
personalSpace?.let {
spacesToListFiltered = spacesToListFiltered.toMutableList().apply {
Expand All @@ -147,7 +152,7 @@ class SpacesListFragment :
spacesListAdapter.setData(spacesToListFiltered, isMultiPersonal)
} else {
showOrHideEmptyView(uiState.spaces)
spacesListAdapter.setData(uiState.spaces.filter { !it.isDisabled }, isMultiPersonal)
spacesListAdapter.setData(uiState.spaces, isMultiPersonal)
}
binding.swipeRefreshSpacesList.isRefreshing = uiState.refreshing
uiState.error?.let { showErrorInSnackbar(R.string.spaces_sync_failed, it) }
Expand Down Expand Up @@ -181,8 +186,9 @@ class SpacesListFragment :
Timber.d("The permissions for $accountName are: ${uiResult.data}")
uiResult.data?.let {
binding.fabCreateSpace.isVisible = it.contains(DRIVES_CREATE_ALL_PERMISSION)
editSpacesPermission = it.contains(DRIVES_READ_WRITE_ALL_PERMISSION)
if(it.contains(DRIVES_READ_WRITE_ALL_PERMISSION)) userPermissions.add(UserPermissions.CAN_EDIT_SPACES)
editQuotaPermission = it.contains(DRIVES_READ_WRITE_PROJECT_QUOTA_ALL_PERMISSION)
if(it.contains(DRIVES_DELETE_PROJECT_ALL_PERMISSION)) userPermissions.add(UserPermissions.CAN_DELETE_SPACES)
}
}
is UIResult.Loading -> { }
Expand All @@ -194,30 +200,28 @@ class SpacesListFragment :
}
}

collectLatestLifecycleFlow(spacesListViewModel.createSpaceFlow) { event ->
event?.let {
when (val uiResult = event.peekContent()) {
is UIResult.Success -> { showMessageInSnackbar(getString(R.string.create_space_correctly)) }
is UIResult.Loading -> { }
is UIResult.Error -> { showErrorInSnackbar(R.string.create_space_failed, uiResult.error) }
}
}
collectSpaceOperationsFlow(spacesListViewModel.createSpaceFlow, R.string.create_space_correctly, R.string.create_space_failed)
collectSpaceOperationsFlow(spacesListViewModel.editSpaceFlow, R.string.edit_space_correctly, R.string.edit_space_failed)
collectSpaceOperationsFlow(spacesListViewModel.disableSpaceFlow, R.string.disable_space_correctly, R.string.disable_space_failed)
collectSpaceOperationsFlow(spacesListViewModel.enableSpaceFlow, R.string.enable_space_correctly, R.string.enable_space_failed)
collectSpaceOperationsFlow(spacesListViewModel.deleteSpaceFlow, R.string.delete_space_correctly, R.string.delete_space_failed)

collectLatestLifecycleFlow(spacesListViewModel.menuOptions) { menuOptions ->
showSpaceMenuOptionsDialog(menuOptions)
}

collectLatestLifecycleFlow(spacesListViewModel.editSpaceFlow) { event ->
}

private fun collectSpaceOperationsFlow(flow: SharedFlow<Event<UIResult<Unit>>?>, successMessage: Int, errorMessage: Int) {
collectLatestLifecycleFlow(flow) { event ->
event?.let {
when (val uiResult = event.peekContent()) {
is UIResult.Success -> { showMessageInSnackbar(getString(R.string.edit_space_correctly)) }
is UIResult.Success -> { showMessageInSnackbar(getString(successMessage)) }
is UIResult.Loading -> { }
is UIResult.Error -> { showErrorInSnackbar(R.string.edit_space_failed, uiResult.error) }
is UIResult.Error -> { showErrorInSnackbar(errorMessage, uiResult.error) }
}
}
}

collectLatestLifecycleFlow(spacesListViewModel.menuOptions) { menuOptions ->
showSpaceMenuOptionsDialog(menuOptions)
}

}

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

override fun onThreeDotButtonClick(ocSpace: OCSpace) {
currentSpace = ocSpace
spacesListViewModel.filterMenuOptions(ocSpace, editSpacesPermission)
spacesListViewModel.filterMenuOptions(ocSpace, userPermissions)
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
Expand Down Expand Up @@ -337,6 +341,33 @@ class SpacesListFragment :
)
editDialog.show(requireActivity().supportFragmentManager, DIALOG_CREATE_SPACE)
}
SpaceMenuOption.DISABLE -> {
showAlertDialog(
title = getString(R.string.disable_space_dialog_title, currentSpace.name),
message = getString(R.string.disable_space_dialog_message),
positiveButtonText = getString(R.string.common_yes),
positiveButtonListener = { _: DialogInterface?, _: Int -> spacesListViewModel.disableSpace(currentSpace.id) },
negativeButtonText = getString(R.string.common_no)
)
}
SpaceMenuOption.ENABLE -> {
showAlertDialog(
title = getString(R.string.enable_space_dialog_title, currentSpace.name),
message = getString(R.string.enable_space_dialog_message),
positiveButtonText = getString(R.string.common_yes),
positiveButtonListener = { _: DialogInterface?, _: Int -> spacesListViewModel.enableSpace(currentSpace.id) },
negativeButtonText = getString(R.string.common_no)
)
}
SpaceMenuOption.DELETE -> {
showAlertDialog(
title = getString(R.string.delete_space_dialog_title, currentSpace.name),
message = getString(R.string.delete_space_dialog_message),
positiveButtonText = getString(R.string.common_yes),
positiveButtonListener = { _: DialogInterface?, _: Int -> spacesListViewModel.deleteSpace(currentSpace.id) },
negativeButtonText = getString(R.string.common_no)
)
}
}
}
}
Expand All @@ -351,6 +382,7 @@ class SpacesListFragment :
const val DRIVES_CREATE_ALL_PERMISSION = "Drives.Create.all"
const val DRIVES_READ_WRITE_ALL_PERMISSION = "Drives.ReadWrite.all"
const val DRIVES_READ_WRITE_PROJECT_QUOTA_ALL_PERMISSION = "Drives.ReadWriteProjectQuota.all"
const val DRIVES_DELETE_PROJECT_ALL_PERMISSION = "Drives.DeleteProject.all"

private const val DIALOG_CREATE_SPACE = "DIALOG_CREATE_SPACE"

Expand Down
Loading
Loading