From 35c2e66e6552052c857f73e474eeb14e71ee3693 Mon Sep 17 00:00:00 2001 From: Taras <tarassmakula@gmail.com> Date: Tue, 1 Mar 2022 20:26:41 +0200 Subject: [PATCH] Add search logic --- .../extensions/SearchViewExtensions.kt | 24 +++++++++++++ .../InviteMembersDialogFragment.kt | 6 ++++ .../group_invite/InviteMembersViewModel.kt | 19 ++++++++++ .../data_source/InviteMembersDataSource.kt | 36 ++++++++++++++++++- .../futo/circles/mapping/MatrixUserMapping.kt | 10 ++++++ .../layout/invite_members_dialog_fragment.xml | 1 + 6 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/futo/circles/extensions/SearchViewExtensions.kt create mode 100644 app/src/main/java/com/futo/circles/mapping/MatrixUserMapping.kt diff --git a/app/src/main/java/com/futo/circles/extensions/SearchViewExtensions.kt b/app/src/main/java/com/futo/circles/extensions/SearchViewExtensions.kt new file mode 100644 index 000000000..a76978cbb --- /dev/null +++ b/app/src/main/java/com/futo/circles/extensions/SearchViewExtensions.kt @@ -0,0 +1,24 @@ +package com.futo.circles.extensions + +import androidx.appcompat.widget.SearchView +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +fun SearchView.getQueryTextChangeStateFlow(): StateFlow<String> { + + val query = MutableStateFlow("") + + setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + return true + } + + override fun onQueryTextChange(newText: String): Boolean { + query.value = newText + return true + } + }) + + return query + +} diff --git a/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersDialogFragment.kt b/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersDialogFragment.kt index 22853086f..ecbb830d9 100644 --- a/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersDialogFragment.kt +++ b/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersDialogFragment.kt @@ -6,6 +6,7 @@ import androidx.navigation.fragment.navArgs import com.futo.circles.R import com.futo.circles.base.BaseFullscreenDialogFragment import com.futo.circles.databinding.InviteMembersDialogFragmentBinding +import com.futo.circles.extensions.getQueryTextChangeStateFlow import com.futo.circles.extensions.observeData import com.futo.circles.feature.group_invite.list.InviteMembersListAdapter import com.futo.circles.model.RoomMemberListItem @@ -35,6 +36,7 @@ class InviteMembersDialogFragment : super.onViewCreated(view, savedInstanceState) binding.toolbar.setNavigationOnClickListener { activity?.onBackPressed() } binding.rvUsers.adapter = listAdapter + viewModel.initSearchListener(binding.searchView.getQueryTextChangeStateFlow()) setupObservers() } @@ -42,6 +44,10 @@ class InviteMembersDialogFragment : viewModel.titleLiveData.observeData(this) { binding.toolbar.title = it } + + viewModel.usersLiveData.observeData(this) { users -> + setUserList(users) + } } private fun setUserList(users: List<RoomMemberListItem>) { diff --git a/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersViewModel.kt b/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersViewModel.kt index dc3a86c9f..380096d8c 100644 --- a/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersViewModel.kt +++ b/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersViewModel.kt @@ -1,8 +1,12 @@ package com.futo.circles.feature.group_invite +import android.util.Log import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import com.futo.circles.extensions.launchUi import com.futo.circles.feature.group_invite.data_source.InviteMembersDataSource +import com.futo.circles.model.RoomMemberListItem +import kotlinx.coroutines.flow.* class InviteMembersViewModel( private val dataSource: InviteMembersDataSource @@ -10,5 +14,20 @@ class InviteMembersViewModel( val titleLiveData = MutableLiveData(dataSource.getInviteTitle()) + val usersLiveData = MutableLiveData<List<RoomMemberListItem>>() + + fun initSearchListener(queryFlow: StateFlow<String>) { + launchUi { + queryFlow + .debounce(500) + .distinctUntilChanged() + .flatMapLatest { query -> dataSource.search(query) } + .collectLatest { members -> + usersLiveData.postValue(members) + Log.d("MyLog", members.size.toString()) + } + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/futo/circles/feature/group_invite/data_source/InviteMembersDataSource.kt b/app/src/main/java/com/futo/circles/feature/group_invite/data_source/InviteMembersDataSource.kt index 2772decb8..258a426ea 100644 --- a/app/src/main/java/com/futo/circles/feature/group_invite/data_source/InviteMembersDataSource.kt +++ b/app/src/main/java/com/futo/circles/feature/group_invite/data_source/InviteMembersDataSource.kt @@ -1,20 +1,54 @@ package com.futo.circles.feature.group_invite.data_source import android.content.Context +import androidx.lifecycle.asFlow import com.futo.circles.R import com.futo.circles.extensions.nameOrId +import com.futo.circles.mapping.toRoomMember import com.futo.circles.provider.MatrixSessionProvider +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.* +import org.matrix.android.sdk.api.session.user.model.User class InviteMembersDataSource( private val roomId: String, private val context: Context ) { - private val room = MatrixSessionProvider.currentSession?.getRoom(roomId) + private val session = MatrixSessionProvider.currentSession + private val room = session?.getRoom(roomId) + + private val existingMembersIds = room?.roomSummary()?.otherMemberIds?.toSet().orEmpty() fun getInviteTitle() = context.getString( R.string.invite_members_to_format, room?.roomSummary()?.nameOrId() ?: roomId ) + suspend fun search(query: String) = combine(searchKnownUsers(query), searchSuggestions(query)) + { knowUsers, suggestions -> + (knowUsers + suggestions).distinctBy { it.userId }.map { it.toRoomMember() } + }.flowOn(Dispatchers.IO).distinctUntilChanged() + + + private fun searchKnownUsers(query: String) = session?.getUsersLive()?.asFlow() + ?.map { list -> + list.filter { user -> + (user.displayName?.contains(query, true) ?: false + || user.userId.contains(query, true)) + && existingMembersIds.contains(user.userId).not() + } + } ?: flowOf() + + + private suspend fun searchSuggestions(query: String): Flow<List<User>> = flow { + val users = session?.searchUsersDirectory(query, MAX_SUGGESTION_COUNT, existingMembersIds) + emit(users ?: emptyList()) + } + + + private companion object { + private const val MAX_SUGGESTION_COUNT = 50 + } + } \ No newline at end of file diff --git a/app/src/main/java/com/futo/circles/mapping/MatrixUserMapping.kt b/app/src/main/java/com/futo/circles/mapping/MatrixUserMapping.kt new file mode 100644 index 000000000..a837f7780 --- /dev/null +++ b/app/src/main/java/com/futo/circles/mapping/MatrixUserMapping.kt @@ -0,0 +1,10 @@ +package com.futo.circles.mapping + +import com.futo.circles.model.RoomMemberListItem +import org.matrix.android.sdk.api.session.user.model.User + +fun User.toRoomMember() = RoomMemberListItem( + id = userId, + name = displayName ?: userId, + avatarUrl = avatarUrl ?: "" +) \ No newline at end of file diff --git a/app/src/main/res/layout/invite_members_dialog_fragment.xml b/app/src/main/res/layout/invite_members_dialog_fragment.xml index 6f4c00da1..cb3fc5824 100644 --- a/app/src/main/res/layout/invite_members_dialog_fragment.xml +++ b/app/src/main/res/layout/invite_members_dialog_fragment.xml @@ -30,6 +30,7 @@ android:layout_height="wrap_content" android:layout_margin="8dp" android:background="@drawable/bg_border" + app:iconifiedByDefault="false" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/toolbarDivider" -- GitLab