Prevent favourites contacts from missing due to magic search limit

This commit is contained in:
Sylvain Berfini 2025-07-22 15:13:11 +02:00
parent c5550bc78d
commit 7dcaf15e68
4 changed files with 44 additions and 22 deletions

View file

@ -148,7 +148,7 @@ class ContactsListFragment : AbstractMainFragment() {
listViewModel.fetchInProgress.value = false
}
listViewModel.favourites.observe(
listViewModel.favouritesList.observe(
viewLifecycleOwner
) {
favouritesAdapter.submitList(it)

View file

@ -51,7 +51,7 @@ class ContactsListViewModel
val contactsList = MutableLiveData<ArrayList<ContactAvatarModel>>()
val favourites = MutableLiveData<ArrayList<ContactAvatarModel>>()
val favouritesList = MutableLiveData<ArrayList<ContactAvatarModel>>()
val fetchInProgress = MutableLiveData<Boolean>()
@ -76,13 +76,23 @@ class ContactsListViewModel
private lateinit var magicSearch: MagicSearch
private lateinit var favouritesMagicSearch: MagicSearch
private var firstLoad = true
private val magicSearchListener = object : MagicSearchListenerStub() {
@WorkerThread
override fun onSearchResultsReceived(magicSearch: MagicSearch) {
Log.i("$TAG Magic search contacts available")
processMagicSearchResults(magicSearch.lastSearch)
processMagicSearchResults(magicSearch.lastSearch, favourites = false)
}
}
private val favouritesMagicSearchListener = object : MagicSearchListenerStub() {
@WorkerThread
override fun onSearchResultsReceived(magicSearch: MagicSearch) {
Log.i("$TAG Magic search favourites contacts available")
processMagicSearchResults(magicSearch.lastSearch, favourites = true)
}
}
@ -91,6 +101,7 @@ class ContactsListViewModel
override fun onContactsLoaded() {
Log.i("$TAG Contacts have been (re)loaded, updating list")
magicSearch.resetSearchCache()
favouritesMagicSearch.resetSearchCache()
applyFilter(
currentFilter,
@ -118,6 +129,10 @@ class ContactsListViewModel
magicSearch.searchLimit = corePreferences.magicSearchResultsLimit
magicSearch.addListener(magicSearchListener)
favouritesMagicSearch = core.createMagicSearch()
favouritesMagicSearch.limitedSearch = false
favouritesMagicSearch.addListener(favouritesMagicSearchListener)
coreContext.postOnMainThread {
applyFilter(currentFilter)
}
@ -128,6 +143,7 @@ class ContactsListViewModel
override fun onCleared() {
coreContext.postOnCoreThread {
magicSearch.removeListener(magicSearchListener)
favouritesMagicSearch.removeListener(favouritesMagicSearchListener)
coreContext.contactsManager.removeListener(contactsListener)
}
super.onCleared()
@ -259,6 +275,16 @@ class ContactsListViewModel
"$TAG Asking Magic search for contacts matching filter [$filter], domain [$domain] and in sources Friends/LDAP/CardDAV"
)
searchInProgress.postValue(filter.isNotEmpty())
if (filter.isEmpty()) {
favouritesMagicSearch.getContactsListAsync(
filter,
domain,
MagicSearch.Source.FavoriteFriends.toInt(),
MagicSearch.Aggregation.Friend
)
}
magicSearch.getContactsListAsync(
filter,
domain,
@ -268,12 +294,11 @@ class ContactsListViewModel
}
@WorkerThread
private fun processMagicSearchResults(results: Array<SearchResult>) {
private fun processMagicSearchResults(results: Array<SearchResult>, favourites: Boolean) {
// Do not call destroy() on previous list items as they are cached and will be re-used
Log.i("$TAG Processing [${results.size}] results")
Log.i("$TAG Processing [${results.size}] results, favourites is [$favourites]")
val list = arrayListOf<ContactAvatarModel>()
val favouritesList = arrayListOf<ContactAvatarModel>()
var count = 0
for (result in results) {
@ -303,29 +328,26 @@ class ContactsListViewModel
val starred = friend?.starred == true
model.isFavourite.postValue(starred)
if (starred) {
favouritesList.add(model)
}
if (firstLoad && count == 20) {
if (!favourites && firstLoad && count == 20) {
contactsList.postValue(list)
}
}
val collator = Collator.getInstance(Locale.getDefault())
favouritesList.sortWith { model1, model2 ->
collator.compare(model1.friend.name, model2.friend.name)
}
list.sortWith { model1, model2 ->
collator.compare(model1.friend.name, model2.friend.name)
}
searchInProgress.postValue(false)
favourites.postValue(favouritesList)
contactsList.postValue(list)
if (favourites) {
favouritesList.postValue(list)
} else {
contactsList.postValue(list)
firstLoad = false
}
Log.i("$TAG Processed [${results.size}] results into [${list.size} contacts]")
firstLoad = false
}
@WorkerThread

View file

@ -74,7 +74,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/section_header_style"
android:id="@+id/favourites_label"
android:visibility="@{!viewModel.isListFiltered &amp;&amp; viewModel.favourites.size() > 0 ? View.VISIBLE : View.GONE}"
android:visibility="@{!viewModel.isListFiltered &amp;&amp; viewModel.favouritesList.size() > 0 ? View.VISIBLE : View.GONE}"
onClickListener="@{() -> viewModel.toggleFavouritesVisibility()}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -87,7 +87,7 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/favourites_contacts_list"
android:visibility="@{viewModel.showFavourites &amp;&amp; !viewModel.isListFiltered &amp;&amp; viewModel.favourites.size() > 0 ? View.VISIBLE : View.GONE}"
android:visibility="@{viewModel.showFavourites &amp;&amp; !viewModel.isListFiltered &amp;&amp; viewModel.favouritesList.size() > 0 ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp" />
@ -95,7 +95,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/section_header_style"
android:id="@+id/all_contacts_label"
android:visibility="@{!viewModel.isListFiltered &amp;&amp; viewModel.favourites.size() > 0 ? View.VISIBLE : View.GONE}"
android:visibility="@{!viewModel.isListFiltered &amp;&amp; viewModel.favouritesList.size() > 0 ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"

View file

@ -73,7 +73,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/section_header_style"
android:id="@+id/favourites_label"
android:visibility="@{!viewModel.isListFiltered &amp;&amp; viewModel.favourites.size() > 0 ? View.VISIBLE : View.GONE}"
android:visibility="@{!viewModel.isListFiltered &amp;&amp; viewModel.favouritesList.size() > 0 ? View.VISIBLE : View.GONE}"
onClickListener="@{() -> viewModel.toggleFavouritesVisibility()}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -87,7 +87,7 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/favourites_contacts_list"
android:visibility="@{viewModel.showFavourites &amp;&amp; !viewModel.isListFiltered &amp;&amp; viewModel.favourites.size() > 0 ? View.VISIBLE : View.GONE}"
android:visibility="@{viewModel.showFavourites &amp;&amp; !viewModel.isListFiltered &amp;&amp; viewModel.favouritesList.size() > 0 ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp" />
@ -95,7 +95,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/section_header_style"
android:id="@+id/all_contacts_label"
android:visibility="@{!viewModel.isListFiltered &amp;&amp; viewModel.favourites.size() > 0 ? View.VISIBLE : View.GONE}"
android:visibility="@{!viewModel.isListFiltered &amp;&amp; viewModel.favouritesList.size() > 0 ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"