Skip to content

Commit 023588b

Browse files
rapterjet2004mahibi
authored andcommitted
- redoing the querying logic to use combine
converting message search functionality to a flow based approach - moving the activity logic to my viewModel, and observing the result properly - this adds the conversations to the combine flow, which simplifies the activity and filtering logic, resolving race conditions Signed-off-by: rapterjet2004 <juliuslinus1@gmail.com>
1 parent afc4c77 commit 023588b

File tree

8 files changed

+235
-164
lines changed

8 files changed

+235
-164
lines changed

app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ package com.nextcloud.talk.contacts
99

1010
import com.nextcloud.talk.data.user.model.User
1111
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
12+
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
1213
import com.nextcloud.talk.models.json.conversations.RoomOverall
14+
import kotlinx.coroutines.flow.Flow
1315

1416
interface ContactsRepository {
1517
suspend fun getContacts(user: User, searchQuery: String?, shareTypes: List<String>): AutocompleteOverall
@@ -23,4 +25,6 @@ interface ContactsRepository {
2325
): RoomOverall
2426

2527
fun getImageUri(user: User, avatarId: String, requestBigSize: Boolean): String
28+
29+
fun getContactsFlow(user: User, searchQuery: String?): Flow<List<AutocompleteUser>>
2630
}

app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ import com.nextcloud.talk.api.NcApiCoroutines
1111
import com.nextcloud.talk.data.user.model.User
1212
import com.nextcloud.talk.models.RetrofitBucket
1313
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
14+
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
1415
import com.nextcloud.talk.models.json.conversations.RoomOverall
1516
import com.nextcloud.talk.utils.ApiUtils
1617
import com.nextcloud.talk.utils.ContactUtils
18+
import kotlinx.coroutines.flow.Flow
19+
import kotlinx.coroutines.flow.flow
1720
import javax.inject.Inject
1821

1922
class ContactsRepositoryImpl @Inject constructor(private val ncApiCoroutines: NcApiCoroutines) : ContactsRepository {
@@ -71,6 +74,30 @@ class ContactsRepositoryImpl @Inject constructor(private val ncApiCoroutines: Nc
7174
requestBigSize
7275
)
7376

77+
override fun getContactsFlow(user: User, searchQuery: String?): Flow<List<AutocompleteUser>> =
78+
flow {
79+
val credentials = ApiUtils.getCredentials(user.username, user.token)
80+
81+
val retrofitBucket: RetrofitBucket = ApiUtils.getRetrofitBucketForContactsSearchFor14(
82+
user.baseUrl!!,
83+
searchQuery
84+
)
85+
86+
val shareTypes = mutableListOf(ShareType.User.shareType).toList()
87+
88+
val modifiedQueryMap: HashMap<String, Any> = HashMap(retrofitBucket.queryMap)
89+
modifiedQueryMap["limit"] = ContactUtils.MAX_CONTACT_LIMIT
90+
modifiedQueryMap["shareTypes[]"] = shareTypes
91+
val response = ncApiCoroutines.getContactsWithSearchParam(
92+
credentials,
93+
retrofitBucket.url,
94+
shareTypes,
95+
modifiedQueryMap
96+
)
97+
98+
emit(response.ocs?.data.orEmpty())
99+
}
100+
74101
companion object {
75102
private val TAG = ContactsRepositoryImpl::class.simpleName
76103
}

app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt

Lines changed: 12 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,7 @@ import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
8787
import com.nextcloud.talk.chat.ChatActivity
8888
import com.nextcloud.talk.chat.viewmodels.ChatViewModel
8989
import com.nextcloud.talk.contacts.ContactsActivity
90-
9190
import com.nextcloud.talk.contacts.ContactsViewModel
92-
9391
import com.nextcloud.talk.contextchat.ContextChatView
9492
import com.nextcloud.talk.contextchat.ContextChatViewModel
9593
import com.nextcloud.talk.conversationlist.viewmodels.ConversationsListViewModel
@@ -107,8 +105,6 @@ import com.nextcloud.talk.messagesearch.MessageSearchHelper
107105
import com.nextcloud.talk.messagesearch.MessageSearchHelper.MessageSearchResults
108106
import com.nextcloud.talk.models.domain.ConversationModel
109107
import com.nextcloud.talk.models.json.conversations.ConversationEnums
110-
import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter
111-
import com.nextcloud.talk.models.json.participants.Participant
112108
import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository
113109
import com.nextcloud.talk.settings.SettingsActivity
114110
import com.nextcloud.talk.threadsoverview.ThreadsOverviewActivity
@@ -154,15 +150,10 @@ import io.reactivex.android.schedulers.AndroidSchedulers
154150
import io.reactivex.disposables.Disposable
155151
import io.reactivex.schedulers.Schedulers
156152
import io.reactivex.subjects.BehaviorSubject
157-
import kotlinx.coroutines.Dispatchers
158-
import kotlinx.coroutines.async
159-
import kotlinx.coroutines.awaitAll
160153
import kotlinx.coroutines.flow.collect
161154
import kotlinx.coroutines.flow.onEach
162155
import kotlinx.coroutines.launch
163156
import kotlinx.coroutines.sync.Mutex
164-
import kotlinx.coroutines.sync.withLock
165-
import kotlinx.coroutines.withContext
166157
import org.apache.commons.lang3.builder.CompareToBuilder
167158
import org.greenrobot.eventbus.Subscribe
168159
import org.greenrobot.eventbus.ThreadMode
@@ -383,6 +374,14 @@ class ConversationsListActivity :
383374
}.collect()
384375
}
385376

377+
lifecycleScope.launch {
378+
conversationsListViewModel.searchResultFlow.collect { searchResults ->
379+
if (adapter?.hasFilter() == true) {
380+
adapter?.updateDataSet(searchResults)
381+
}
382+
}
383+
}
384+
386385
conversationsListViewModel.getFederationInvitationsViewState.observe(this) { state ->
387386
when (state) {
388387
is ConversationsListViewModel.GetFederationInvitationsStartState -> {
@@ -456,46 +455,6 @@ class ConversationsListActivity :
456455
}
457456
}
458457

459-
lifecycleScope.launch {
460-
conversationsListViewModel.openConversationsState.collect { state ->
461-
when (state) {
462-
is ConversationsListViewModel.OpenConversationsUiState.Success -> {
463-
val openConversationItems: MutableList<AbstractFlexibleItem<*>> = ArrayList()
464-
val headerTitle = resources!!.getString(R.string.openConversations)
465-
for (conversation in state.conversations) {
466-
var genericTextHeaderItem: GenericTextHeaderItem
467-
if (!callHeaderItems.containsKey(headerTitle)) {
468-
genericTextHeaderItem = GenericTextHeaderItem(headerTitle, viewThemeUtils)
469-
callHeaderItems[headerTitle] = genericTextHeaderItem
470-
}
471-
val conversationItem = ConversationItem(
472-
ConversationModel.mapToConversationModel(conversation, currentUser!!),
473-
currentUser!!,
474-
this@ConversationsListActivity,
475-
callHeaderItems[headerTitle],
476-
viewThemeUtils
477-
)
478-
openConversationItems.add(conversationItem)
479-
}
480-
481-
mutex.withLock {
482-
// Filters out all old open conversation items from the previous query
483-
searchableConversationItems = searchableConversationItems.filter {
484-
!(it is ConversationItem && it.header == callHeaderItems[headerTitle])
485-
}.toMutableList()
486-
487-
searchableConversationItems.addAll(openConversationItems)
488-
}
489-
}
490-
is ConversationsListViewModel.OpenConversationsUiState.Error -> {
491-
handleHttpExceptions(state.exception)
492-
}
493-
494-
else -> {}
495-
}
496-
}
497-
}
498-
499458
lifecycleScope.launch {
500459
conversationsListViewModel.getRoomsFlow
501460
.onEach { list ->
@@ -528,52 +487,6 @@ class ConversationsListActivity :
528487
}.collect()
529488
}
530489

531-
lifecycleScope.launch {
532-
contactsViewModel.contactsViewState.onEach { state ->
533-
when (state) {
534-
is ContactsViewModel.ContactsUiState.Success -> {
535-
if (state.contacts.isNullOrEmpty()) return@onEach
536-
537-
val userItems: MutableList<AbstractFlexibleItem<*>> = ArrayList()
538-
val actorTypeConverter = EnumActorTypeConverter()
539-
var genericTextHeaderItem: GenericTextHeaderItem
540-
for (autocompleteUser in state.contacts) {
541-
val headerTitle = resources!!.getString(R.string.nc_user)
542-
if (!callHeaderItems.containsKey(headerTitle)) {
543-
genericTextHeaderItem = GenericTextHeaderItem(headerTitle, viewThemeUtils)
544-
callHeaderItems[headerTitle] = genericTextHeaderItem
545-
}
546-
547-
val participant = Participant()
548-
participant.actorId = autocompleteUser.id
549-
participant.actorType = actorTypeConverter.getFromString(autocompleteUser.source)
550-
participant.displayName = autocompleteUser.label
551-
552-
val contactItem = ContactItem(
553-
participant,
554-
currentUser!!,
555-
callHeaderItems[headerTitle],
556-
viewThemeUtils
557-
)
558-
559-
userItems.add(contactItem)
560-
}
561-
562-
mutex.withLock {
563-
// Filters out all old user items from the previous query
564-
searchableConversationItems = searchableConversationItems.filter {
565-
it !is ContactItem
566-
}.toMutableList()
567-
568-
searchableConversationItems.addAll(userItems)
569-
}
570-
}
571-
572-
else -> {}
573-
}
574-
}.collect()
575-
}
576-
577490
lifecycleScope.launch {
578491
chatViewModel.backgroundPlayUIFlow.onEach { msg ->
579492
binding.composeViewForBackgroundPlay.apply {
@@ -1008,8 +921,8 @@ class ConversationsListActivity :
1008921
initSearchDisposable()
1009922
adapter?.setHeadersShown(true)
1010923
adapter!!.showAllHeaders()
924+
searchableConversationItems.addAll(conversationItemsWithHeader)
1011925
if (!hasFilterEnabled()) filterableConversationItems = searchableConversationItems
1012-
// adapter!!.updateDataSet(filterableConversationItems, false)
1013926
binding.swipeRefreshLayoutView.isEnabled = false
1014927
searchBehaviorSubject.onNext(true)
1015928
return true
@@ -1460,74 +1373,15 @@ class ConversationsListActivity :
14601373

14611374
private fun performFilterAndSearch(filter: String?) {
14621375
if (filter!!.length >= SEARCH_MIN_CHARS) {
1463-
clearMessageSearchResults()
14641376
binding.noArchivedConversationLayout.visibility = View.GONE
1465-
binding.swipeRefreshLayoutView.isRefreshing = true
1466-
1467-
lifecycleScope.launch {
1468-
// gets users, updates collector async, which adds them to searchableConversationItems
1469-
val deferred1 = async {
1470-
fetchUsers(filter)
1471-
}
1472-
1473-
// gets open conversations, updates collector async, which adds them to searchableConversationItems
1474-
val deferred2 = async {
1475-
fetchOpenConversations(filter)
1476-
}
1477-
1478-
awaitAll(deferred1, deferred2)
1479-
1480-
// Waits until both work in collectors is over, to avoid data races
1481-
mutex.withLock {
1482-
if (hasFilterEnabled()) {
1483-
val headerTitle = resources!!.getString(R.string.openConversations)
1484-
1485-
fun AbstractFlexibleItem<*>.isRegularConversationItem() =
1486-
this is ConversationItem && this.header != callHeaderItems[headerTitle]
1487-
1488-
// Only keeps the Open Conversations, Users
1489-
val list = searchableConversationItems.filter {
1490-
!it.isRegularConversationItem()
1491-
}.toMutableList()
1492-
1493-
// Only keeps the conversation items with the applied Nextcloud filter [mention/archive/unread]
1494-
filterableConversationItems = filterableConversationItems.filter {
1495-
it.isRegularConversationItem()
1496-
}.toMutableList()
1497-
1498-
filterableConversationItems.addAll(list)
1499-
adapter?.updateDataSet(filterableConversationItems)
1500-
1501-
adapter?.setFilter(filter)
1502-
adapter?.filterItems()
1503-
} else {
1504-
// Conversation Items without Nextcloud filter + Open conversations/users
1505-
adapter?.updateDataSet(searchableConversationItems)
1506-
adapter?.setFilter(filter)
1507-
adapter?.filterItems()
1508-
}
1509-
}
1510-
1511-
if (hasSpreedFeatureCapability(
1512-
currentUser?.capabilities?.spreedCapability,
1513-
SpreedFeatures.UNIFIED_SEARCH
1514-
)
1515-
) {
1516-
// gets messages async, adds them to the adapter, but NOT the searchableConversationItems
1517-
startMessageSearch(filter)
1518-
}
1519-
1520-
withContext(Dispatchers.Main) {
1521-
binding.swipeRefreshLayoutView.isRefreshing = false
1522-
}
1523-
}
1377+
adapter?.setFilter(filter)
1378+
conversationsListViewModel.getSearchQuery(context, filter)
15241379
} else {
15251380
resetSearchResults()
15261381
}
15271382
}
15281383

15291384
private fun resetSearchResults() {
1530-
clearMessageSearchResults()
15311385
adapter?.updateDataSet(conversationItems)
15321386
adapter?.setFilter("")
15331387
adapter?.filterItems()
@@ -1606,7 +1460,7 @@ class ConversationsListActivity :
16061460
}
16071461

16081462
is LoadMoreResultsItem -> {
1609-
loadMoreMessages()
1463+
conversationsListViewModel.loadMoreMessages(context)
16101464
}
16111465

16121466
is ConversationItem -> {

0 commit comments

Comments
 (0)