Improved contacts display, fixed issue with LDAP results

This commit is contained in:
Sylvain Berfini 2024-04-08 16:17:22 +02:00
parent 9c1b9b2939
commit f5bdaf85fd
13 changed files with 141 additions and 100 deletions

View file

@ -274,7 +274,7 @@ class ContactsManager @UiThread constructor() {
return found
}
}
Log.d("$TAG No friend matching ref key [$id] has been found")
Log.w("$TAG No friend matching ref key [$id] has been found")
return null
}

View file

@ -98,7 +98,7 @@ class ContactFragment : SlidingPaneChildFragment() {
val refKey = args.contactRefKey
Log.i("$TAG Looking up for contact with ref key [$refKey]")
viewModel.findContactByRefKey(refKey)
viewModel.findContact(sharedViewModel.displayedFriend, refKey)
binding.setBackClickListener {
goBack()

View file

@ -206,6 +206,7 @@ class ContactsListFragment : AbstractTopBarFragment() {
it.consume { model ->
val modalBottomSheet = ContactsListMenuDialogFragment(
model.isFavourite.value == true,
model.isStored,
{ // onDismiss
adapter.resetSelection()
},
@ -244,7 +245,8 @@ class ContactsListFragment : AbstractTopBarFragment() {
adapter.contactClickedEvent.observe(viewLifecycleOwner) {
it.consume { model ->
sharedViewModel.showContactEvent.value = Event(model.id ?: "")
sharedViewModel.displayedFriend = model.friend
sharedViewModel.showContactEvent.value = Event(model.id)
}
}
}

View file

@ -34,6 +34,7 @@ import org.linphone.databinding.ContactsListLongPressMenuBinding
@UiThread
class ContactsListMenuDialogFragment(
private val isFavourite: Boolean,
private val isStored: Boolean,
private val onDismiss: (() -> Unit)? = null,
private val onFavourite: (() -> Unit)? = null,
private val onShare: (() -> Unit)? = null,
@ -68,6 +69,7 @@ class ContactsListMenuDialogFragment(
): View {
val view = ContactsListLongPressMenuBinding.inflate(layoutInflater)
view.isFavourite = isFavourite
view.isStored = isStored
view.setFavoriteClickListener {
onFavourite?.invoke()

View file

@ -40,10 +40,12 @@ class ContactAvatarModel @WorkerThread constructor(val friend: Friend, val addre
private const val TAG = "[Contact Avatar Model]"
}
val id = friend.refKey ?: friend.name
val id = friend.refKey ?: friend.name ?: ""
val contactName = friend.name
val isStored = friend.inList()
val isFavourite = MutableLiveData<Boolean>()
val lastPresenceInfo = MutableLiveData<String>()

View file

@ -84,6 +84,8 @@ class ContactViewModel @UiThread constructor() : ViewModel() {
val contactFoundEvent = MutableLiveData<Event<Boolean>>()
val isStored = MutableLiveData<Boolean>()
val chatDisabled = MutableLiveData<Boolean>()
val videoCallDisabled = MutableLiveData<Boolean>()
@ -229,6 +231,7 @@ class ContactViewModel @UiThread constructor() : ViewModel() {
private var refKey: String = ""
init {
isStored.value = false
expandNumbersAndAddresses.value = true
trustedDevicesPercentage.value = 0
@ -255,14 +258,33 @@ class ContactViewModel @UiThread constructor() : ViewModel() {
}
@UiThread
fun findContactByRefKey(refKey: String) {
fun findContact(displayedFriend: Friend?, refKey: String) {
this.refKey = refKey
coreContext.postOnCoreThread {
val friend = coreContext.contactsManager.findContactById(refKey)
if (friend != null) {
if (displayedFriend != null && ::friend.isInitialized && friend == displayedFriend) {
Log.i("$TAG Contact object already in memory, skipping")
refreshContactInfo()
contactFoundEvent.postValue(Event(true))
return@postOnCoreThread
}
if (displayedFriend != null && (!::friend.isInitialized || friend != displayedFriend)) {
if (displayedFriend.refKey == refKey) {
friend = displayedFriend
Log.i("$TAG Friend object available in sharedViewModel, using it")
refreshContactInfo()
contactFoundEvent.postValue(Event(true))
return@postOnCoreThread
}
}
val found = coreContext.contactsManager.findContactById(refKey)
if (found != null) {
friend = found
Log.i("$TAG Found contact [${friend.name}] matching ref key [$refKey]")
this.friend = friend
refreshContactInfo()
contactFoundEvent.postValue(Event(true))
@ -273,6 +295,7 @@ class ContactViewModel @UiThread constructor() : ViewModel() {
@WorkerThread
fun refreshContactInfo() {
isFavourite.postValue(friend.starred)
isStored.postValue(friend.inList())
contact.value?.destroy()
contact.postValue(ContactAvatarModel(friend))

View file

@ -237,6 +237,10 @@ class ContactsListViewModel @UiThread constructor() : AbstractTopBarViewModel()
for (result in results) {
val friend = result.friend
if (friend != null && result.sourceFlags == MagicSearch.Source.LdapServers.toInt()) {
// TODO FIXME: Fix issue in SDK, each LDAP friend should have a proper refKey
friend.refKey = friend.name
}
val model = if (friend != null) {
coreContext.contactsManager.getContactAvatarModelForFriend(friend)

View file

@ -79,6 +79,8 @@ class LdapViewModel : ViewModel() {
useTls.value = true
minCharacters.value = "3"
requestTimeout.value = "5"
requestDelay.value = "2000"
}
@UiThread

View file

@ -25,6 +25,7 @@ import androidx.annotation.UiThread
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import org.linphone.core.ChatRoom
import org.linphone.core.Friend
import org.linphone.ui.main.chat.model.MessageModel
import org.linphone.utils.Event
@ -75,6 +76,7 @@ class SharedMainViewModel @UiThread constructor() : ViewModel() {
/* Contacts related */
var displayedFriend: Friend? = null // Prevents the need to go look for the friend
val showContactEvent: MutableLiveData<Event<String>> by lazy {
MutableLiveData<Event<String>>()
}

View file

@ -64,6 +64,7 @@
android:padding="15dp"
android:adjustViewBounds="true"
android:src="@drawable/pencil_simple"
android:visibility="@{viewModel.isStored ? View.VISIBLE : View.GONE}"
app:tint="?attr/color_main1_500"
app:layout_constraintBottom_toBottomOf="@id/invisible_title"
app:layout_constraintEnd_toEndOf="parent"
@ -475,99 +476,97 @@
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_marginStart="16dp"
android:layout_marginBottom="@dimen/screen_bottom_margin"
android:layout_marginEnd="16dp"
android:src="@drawable/shape_squircle_white_background"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/actions"
app:layout_constraintBottom_toBottomOf="@id/action_delete" />
app:layout_constraintBottom_toBottomOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> viewModel.editContact()}"
style="@style/context_menu_action_label_style"
android:id="@+id/action_edit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="@string/contact_details_edit"
android:drawableStart="@drawable/pencil_simple"
android:background="@drawable/action_background"
app:layout_constraintTop_toTopOf="@id/actions_background"
app:layout_constraintStart_toStartOf="@id/actions_background"
app:layout_constraintEnd_toEndOf="@id/actions_background"/>
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:background="?attr/color_main2_200"
app:layout_constraintStart_toStartOf="@id/action_edit"
app:layout_constraintEnd_toEndOf="@id/action_edit"
app:layout_constraintTop_toBottomOf="@+id/action_edit"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> viewModel.toggleFavourite()}"
style="@style/context_menu_action_label_style"
android:id="@+id/action_favorite"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="@drawable/action_background"
android:text="@{viewModel.isFavourite ? @string/contact_details_remove_from_favourites : @string/contact_details_add_to_favourites, default=@string/contact_details_add_to_favourites}"
android:drawableStart="@{viewModel.isFavourite ? @drawable/heart_fill : @drawable/heart, default=@drawable/heart_fill}"
android:drawableTint="@{viewModel.isFavourite ? @color/danger_500 : @color/main2_500, default=@color/main2_500}"
app:layout_constraintTop_toBottomOf="@id/action_edit"
app:layout_constraintStart_toStartOf="@id/actions_background"
app:layout_constraintEnd_toEndOf="@id/actions_background"/>
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:background="?attr/color_main2_200"
app:layout_constraintStart_toStartOf="@id/action_favorite"
app:layout_constraintEnd_toEndOf="@id/action_favorite"
app:layout_constraintTop_toBottomOf="@+id/action_favorite"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{shareClickListener}"
style="@style/context_menu_action_label_style"
android:id="@+id/action_share"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="@drawable/action_background"
android:text="@string/contact_details_share"
android:drawableStart="@drawable/share_network"
app:layout_constraintTop_toBottomOf="@id/action_favorite"
app:layout_constraintStart_toStartOf="@id/actions_background"
app:layout_constraintEnd_toEndOf="@id/actions_background"/>
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:background="?attr/color_main2_200"
app:layout_constraintStart_toStartOf="@id/action_share"
app:layout_constraintEnd_toEndOf="@id/action_share"
app:layout_constraintTop_toBottomOf="@+id/action_share"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{deleteClickListener}"
style="@style/context_menu_danger_action_label_style"
android:id="@+id/action_delete"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="@dimen/screen_bottom_margin"
android:background="@drawable/action_background"
android:text="@string/contact_details_delete"
android:drawableStart="@drawable/trash_simple"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/action_share"
app:layout_constraintStart_toStartOf="@id/actions_background"
app:layout_constraintEnd_toEndOf="@id/actions_background"/>
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:background="@drawable/shape_squircle_white_background"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/actions"
app:layout_constraintBottom_toBottomOf="parent">
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> viewModel.editContact()}"
style="@style/context_menu_action_label_style"
android:id="@+id/action_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/contact_details_edit"
android:drawableStart="@drawable/pencil_simple"
android:background="@drawable/action_background"
android:visibility="@{viewModel.isStored ? View.VISIBLE : View.GONE}" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="?attr/color_main2_200"
android:visibility="@{viewModel.isStored ? View.VISIBLE : View.GONE}"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> viewModel.toggleFavourite()}"
style="@style/context_menu_action_label_style"
android:id="@+id/action_favorite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/action_background"
android:visibility="@{viewModel.isStored ? View.VISIBLE : View.GONE}"
android:text="@{viewModel.isFavourite ? @string/contact_details_remove_from_favourites : @string/contact_details_add_to_favourites, default=@string/contact_details_add_to_favourites}"
android:drawableStart="@{viewModel.isFavourite ? @drawable/heart_fill : @drawable/heart, default=@drawable/heart_fill}"
android:drawableTint="@{viewModel.isFavourite ? @color/danger_500 : @color/main2_500, default=@color/main2_500}" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="?attr/color_main2_200"
android:visibility="@{viewModel.isStored ? View.VISIBLE : View.GONE}"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{shareClickListener}"
style="@style/context_menu_action_label_style"
android:id="@+id/action_share"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/action_background"
android:text="@string/contact_details_share"
android:drawableStart="@drawable/share_network"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="?attr/color_main2_200"
android:visibility="@{viewModel.isStored ? View.VISIBLE : View.GONE}"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{deleteClickListener}"
style="@style/context_menu_danger_action_label_style"
android:id="@+id/action_delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/action_background"
android:text="@string/contact_details_delete"
android:drawableStart="@drawable/trash_simple"
android:visibility="@{viewModel.isStored ? View.VISIBLE : View.GONE}"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -19,6 +19,9 @@
<variable
name="isFavourite"
type="Boolean" />
<variable
name="isStored"
type="Boolean" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
@ -34,6 +37,7 @@
android:layout_height="wrap_content"
android:layout_marginBottom="1dp"
android:background="@drawable/menu_item_background"
android:visibility="@{isStored ? View.VISIBLE : View.GONE}"
android:text="@{isFavourite ? @string/contact_details_remove_from_favourites : @string/contact_details_add_to_favourites, default=@string/contact_details_add_to_favourites}"
android:drawableStart="@{isFavourite ? @drawable/heart_fill : @drawable/heart, default=@drawable/heart_fill}"
android:drawableTint="@{isFavourite ? @color/danger_500 : @color/main2_500, default=@color/main2_500}"
@ -42,12 +46,12 @@
app:layout_constraintEnd_toEndOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
style="@style/context_menu_action_label_style"
android:id="@+id/share"
android:onClick="@{shareClickListener}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/contact_details_share"
style="@style/context_menu_action_label_style"
android:background="@drawable/menu_item_background"
android:layout_marginBottom="1dp"
android:drawableStart="@drawable/share_network"
@ -56,12 +60,13 @@
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/context_menu_danger_action_label_style"
android:id="@+id/delete"
android:onClick="@{deleteClickListener}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/contact_details_delete"
style="@style/context_menu_danger_action_label_style"
android:visibility="@{isStored ? View.VISIBLE : View.GONE}"
android:background="@drawable/menu_item_background"
android:layout_marginBottom="1dp"
android:drawableStart="@drawable/trash_simple"

View file

@ -226,9 +226,9 @@
<string name="settings_contacts_ldap_search_base_title">Base de recherche (ne peut être vide)</string>
<string name="settings_contacts_ldap_search_filter_title">Filtre</string>
<string name="settings_contacts_ldap_max_results_title">Nombre de résultats maximum</string>
<string name="settings_contacts_ldap_request_timeout_title">Durée maximum</string>
<string name="settings_contacts_ldap_request_delay_title">Délai entre 2 requêtes (en secondes)</string>
<string name="settings_contacts_ldap_min_characters_title">Nombre minimum de caractères pour lancer la requête (en millisecondes)</string>
<string name="settings_contacts_ldap_request_timeout_title">Durée maximum (en secondes)</string>
<string name="settings_contacts_ldap_request_delay_title">Délai entre 2 requêtes (en millisecondes)</string>
<string name="settings_contacts_ldap_min_characters_title">Nombre minimum de caractères pour lancer la requête</string>
<string name="settings_contacts_ldap_name_attributes_title">Attributs de nom</string>
<string name="settings_contacts_ldap_sip_attributes_title">Attributs SIP</string>
<string name="settings_contacts_ldap_sip_domain_title">Domaine SIP</string>

View file

@ -269,10 +269,10 @@
<string name="settings_contacts_ldap_use_tls_title">Use TLS</string>
<string name="settings_contacts_ldap_search_base_title">Search</string>
<string name="settings_contacts_ldap_search_filter_title">Search base (can\'t be empty)</string>
<string name="settings_contacts_ldap_max_results_title">Filter</string>
<string name="settings_contacts_ldap_request_timeout_title">Max results</string>
<string name="settings_contacts_ldap_request_delay_title">Timeout (in seconds)</string>
<string name="settings_contacts_ldap_min_characters_title">Delay between two requests (in milliseconds)</string>
<string name="settings_contacts_ldap_max_results_title">Max results</string>
<string name="settings_contacts_ldap_request_timeout_title">Timeout (in seconds)</string>
<string name="settings_contacts_ldap_request_delay_title">Delay between two queries (in milliseconds)</string>
<string name="settings_contacts_ldap_min_characters_title">Min characters to start a query</string>
<string name="settings_contacts_ldap_name_attributes_title">Name attributes</string>
<string name="settings_contacts_ldap_sip_attributes_title">SIP attributes</string>
<string name="settings_contacts_ldap_sip_domain_title">SIP domain</string>