Skip to content

Commit d12d832

Browse files
committed
feat: show a message when there are no matches for users and groups
1 parent ff47f47 commit d12d832

File tree

4 files changed

+56
-30
lines changed

4 files changed

+56
-30
lines changed

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

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import android.os.Bundle
2424
import android.view.LayoutInflater
2525
import android.view.View
2626
import android.view.ViewGroup
27+
import androidx.core.view.isVisible
2728
import androidx.fragment.app.Fragment
2829
import androidx.recyclerview.widget.LinearLayoutManager
2930
import androidx.recyclerview.widget.RecyclerView
@@ -33,7 +34,6 @@ import com.owncloud.android.domain.spaces.model.OCSpace
3334
import com.owncloud.android.domain.spaces.model.SpaceMember
3435
import com.owncloud.android.extensions.collectLatestLifecycleFlow
3536
import com.owncloud.android.extensions.showErrorInSnackbar
36-
import com.owncloud.android.presentation.common.UIResult
3737
import org.koin.androidx.viewmodel.ext.android.viewModel
3838
import org.koin.core.parameter.parametersOf
3939
import timber.log.Timber
@@ -68,24 +68,17 @@ class AddMemberFragment: Fragment() {
6868

6969
val spaceMembers = requireArguments().getParcelableArrayList<SpaceMember>(ARG_SPACE_MEMBERS) ?: arrayListOf()
7070

71-
collectLatestLifecycleFlow(spaceMembersViewModel.members) { event ->
72-
event?.let {
73-
when (val uiResult = event.peekContent()) {
74-
is UIResult.Success -> {
75-
uiResult.data?.let { listOfMembers ->
76-
val listOfMembersFiltered = listOfMembers.filter { member ->
77-
!spaceMembers.any { spaceMember ->
78-
spaceMember.id == "u:${member.id}" || spaceMember.id == "g:${member.id}" }
79-
}
80-
searchMembersAdapter.setMembers(listOfMembersFiltered)
81-
}
82-
}
83-
is UIResult.Loading -> { }
84-
is UIResult.Error -> {
85-
Timber.e(uiResult.error, "Failed to retrieve available users and groups")
86-
showErrorInSnackbar(R.string.members_search_failed, uiResult.error)
87-
}
88-
}
71+
collectLatestLifecycleFlow(spaceMembersViewModel.members) { uiState ->
72+
val listOfMembersFiltered = uiState.members.filter { member ->
73+
!spaceMembers.any { spaceMember ->
74+
spaceMember.id == "u:${member.id}" || spaceMember.id == "g:${member.id}" }
75+
}
76+
val hasMembers = listOfMembersFiltered.isNotEmpty()
77+
showOrHideEmptyView(hasMembers)
78+
if (hasMembers) searchMembersAdapter.setMembers(listOfMembersFiltered)
79+
uiState.error?.let {
80+
Timber.e(uiState.error, "Failed to retrieve available users and groups")
81+
showErrorInSnackbar(R.string.members_search_failed, uiState.error)
8982
}
9083
}
9184

@@ -102,6 +95,19 @@ class AddMemberFragment: Fragment() {
10295
}
10396
}
10497

98+
private fun showOrHideEmptyView(hasMembers: Boolean) {
99+
binding.membersRecyclerView.isVisible = hasMembers
100+
binding.emptyDataParent.apply {
101+
val shouldShow = !hasMembers && binding.searchBar.query.length > 2
102+
root.isVisible = shouldShow
103+
if (shouldShow) {
104+
listEmptyDatasetIcon.setImageResource(R.drawable.ic_share_generic_white)
105+
listEmptyDatasetTitle.setText(R.string.members_search_failed)
106+
listEmptyDatasetSubTitle.setText(R.string.members_search_empty)
107+
}
108+
}
109+
}
110+
105111
override fun onActivityCreated(savedInstanceState: Bundle?) {
106112
super.onActivityCreated(savedInstanceState)
107113
requireActivity().setTitle(R.string.members_add)

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

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
package com.owncloud.android.presentation.spaces.members
2222

2323
import androidx.lifecycle.ViewModel
24+
import androidx.lifecycle.viewModelScope
25+
import com.owncloud.android.domain.UseCaseResult
2426
import com.owncloud.android.domain.members.model.OCMember
2527
import com.owncloud.android.domain.roles.model.OCRole
2628
import com.owncloud.android.domain.spaces.model.OCSpace
@@ -33,8 +35,11 @@ import com.owncloud.android.domain.utils.Event
3335
import com.owncloud.android.extensions.ViewModelExt.runUseCaseWithResult
3436
import com.owncloud.android.presentation.common.UIResult
3537
import com.owncloud.android.providers.CoroutinesDispatcherProvider
38+
import kotlinx.coroutines.flow.MutableSharedFlow
3639
import kotlinx.coroutines.flow.MutableStateFlow
40+
import kotlinx.coroutines.flow.SharedFlow
3741
import kotlinx.coroutines.flow.StateFlow
42+
import kotlinx.coroutines.launch
3843

3944
class SpaceMembersViewModel(
4045
private val getRolesAsyncUseCase: GetRolesAsyncUseCase,
@@ -55,8 +60,8 @@ class SpaceMembersViewModel(
5560
private val _spacePermissions = MutableStateFlow<Event<UIResult<List<String>>>?>(null)
5661
val spacePermissions: StateFlow<Event<UIResult<List<String>>>?> = _spacePermissions
5762

58-
private val _members = MutableStateFlow<Event<UIResult<List<OCMember>>>?>(null)
59-
val members: StateFlow<Event<UIResult<List<OCMember>>>?> = _members
63+
private val _members: MutableSharedFlow<MembersUIState> = MutableSharedFlow()
64+
val members: SharedFlow<MembersUIState> = _members
6065

6166
init {
6267
runUseCaseWithResult(
@@ -88,16 +93,23 @@ class SpaceMembersViewModel(
8893
requiresConnection = true
8994
)
9095

91-
fun searchMembers(query: String) = runUseCaseWithResult(
92-
coroutineDispatcher = coroutineDispatcherProvider.io,
93-
flow = _members,
94-
useCase = searchMembersUseCase,
95-
useCaseParams = SearchMembersUseCase.Params(accountName = accountName, query = query),
96-
showLoading = false,
97-
requiresConnection = true
98-
)
96+
fun searchMembers(query: String) {
97+
viewModelScope.launch(coroutineDispatcherProvider.io) {
98+
when (val result = searchMembersUseCase(SearchMembersUseCase.Params(accountName, query))) {
99+
is UseCaseResult.Success -> _members.emit(MembersUIState(members = result.data, error = null))
100+
is UseCaseResult.Error -> _members.emit(MembersUIState(members = emptyList(), error = result.getThrowableOrNull()))
101+
}
102+
}
103+
}
99104

100105
fun clearSearch() {
101-
_members.value = Event(UIResult.Success(emptyList()))
106+
viewModelScope.launch(coroutineDispatcherProvider.io) {
107+
_members.emit(MembersUIState(members = emptyList(), error = null))
108+
}
102109
}
110+
111+
data class MembersUIState (
112+
val members: List<OCMember>,
113+
val error: Throwable?
114+
)
103115
}

owncloudApp/src/main/res/layout/add_member_fragment.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@
4646
android:scrollbars="vertical"
4747
android:visibility="visible" />
4848

49+
<include
50+
android:id="@+id/empty_data_parent"
51+
layout="@layout/item_empty_dataset"
52+
android:visibility="gone"
53+
app:layout_constraintBottom_toBottomOf="parent"
54+
app:layout_constraintTop_toTopOf="parent" />
55+
4956
</LinearLayout>
5057

5158
</ScrollView>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,7 @@
880880
<string name="members_title">Members</string>
881881
<string name="members_add">Add member</string>
882882
<string name="members_search_failed">No results found</string>
883+
<string name="members_search_empty">No user or groups matches your search</string>
883884
<string name="member_type_user">User</string>
884885
<string name="member_type_group">Group</string>
885886

0 commit comments

Comments
 (0)