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 0000000000000000000000000000000000000000..a76978cbb59f59bf2124d69eee4945cc5b20d611 --- /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 22853086f350afbbfb8354cc1e0a4910c1adfce1..ecbb830d94cb106b5142b2d8544da016a98c944c 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 dc3a86c9f8d0705acdc06fac1706a88fc3bf0aaf..380096d8c8709ed691f95decc2903c51d453bbb1 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 2772decb8043f5dd2a5c2685012f00ac306b7036..258a426ea509cc34d01ddcc923ddb8902f33abdc 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 0000000000000000000000000000000000000000..a837f77804001e64997ffcd6735d4e0dd6369f9c --- /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 6f4c00da1b9a0bf44e754b8a1f42f655f3e86256..cb3fc58240255f7c106b51f81380dc6e4ae6f522 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"