Improved contacts list search field
This commit is contained in:
parent
7e81f775c3
commit
339e30a75e
10 changed files with 86 additions and 108 deletions
|
@ -23,7 +23,6 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.SearchView
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
@ -122,6 +121,10 @@ class ChatRoomCreationFragment : Fragment() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
viewModel.filter.observe(viewLifecycleOwner, Observer {
|
||||||
|
viewModel.applyFilter()
|
||||||
|
})
|
||||||
|
|
||||||
adapter.selectedContact.observe(viewLifecycleOwner, Observer {
|
adapter.selectedContact.observe(viewLifecycleOwner, Observer {
|
||||||
it.consume { searchResult ->
|
it.consume { searchResult ->
|
||||||
if (createGroup) {
|
if (createGroup) {
|
||||||
|
@ -145,17 +148,6 @@ class ChatRoomCreationFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
|
||||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQueryTextChange(newText: String?): Boolean {
|
|
||||||
viewModel.filter(newText ?: "")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.onErrorEvent.observe(viewLifecycleOwner, Observer {
|
viewModel.onErrorEvent.observe(viewLifecycleOwner, Observer {
|
||||||
it.consume { messageResourceId ->
|
it.consume { messageResourceId ->
|
||||||
(activity as MainActivity).showSnackBar(messageResourceId)
|
(activity as MainActivity).showSnackBar(messageResourceId)
|
||||||
|
|
|
@ -47,9 +47,10 @@ class ChatRoomCreationViewModel : ErrorReportingViewModel() {
|
||||||
|
|
||||||
val selectedAddresses = MutableLiveData<ArrayList<Address>>()
|
val selectedAddresses = MutableLiveData<ArrayList<Address>>()
|
||||||
|
|
||||||
val limeAvailable: Boolean = LinphoneUtils.isLimeAvailable()
|
val filter = MutableLiveData<String>()
|
||||||
|
var previousFilter = ""
|
||||||
|
|
||||||
private var filter: String = ""
|
val limeAvailable: Boolean = LinphoneUtils.isLimeAvailable()
|
||||||
|
|
||||||
private val contactsUpdatedListener = object : ContactsUpdatedListenerStub() {
|
private val contactsUpdatedListener = object : ContactsUpdatedListenerStub() {
|
||||||
override fun onContactsUpdated() {
|
override fun onContactsUpdated() {
|
||||||
|
@ -95,18 +96,19 @@ class ChatRoomCreationViewModel : ErrorReportingViewModel() {
|
||||||
isEncrypted.value = encrypted
|
isEncrypted.value = encrypted
|
||||||
}
|
}
|
||||||
|
|
||||||
fun filter(search: String) {
|
fun applyFilter() {
|
||||||
if (filter.isNotEmpty() && filter.length > search.length) {
|
val filterValue = filter.value.orEmpty()
|
||||||
|
if (previousFilter.isNotEmpty() && previousFilter.length > filterValue.length) {
|
||||||
coreContext.contactsManager.magicSearch.resetSearchCache()
|
coreContext.contactsManager.magicSearch.resetSearchCache()
|
||||||
}
|
}
|
||||||
filter = search
|
previousFilter = filterValue
|
||||||
|
|
||||||
updateContactsList()
|
updateContactsList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateContactsList() {
|
fun updateContactsList() {
|
||||||
val domain = if (sipContactsSelected.value == true) coreContext.core.defaultProxyConfig?.domain ?: "" else ""
|
val domain = if (sipContactsSelected.value == true) coreContext.core.defaultProxyConfig?.domain ?: "" else ""
|
||||||
val results = coreContext.contactsManager.magicSearch.getContactListFromFilter(filter, domain)
|
val results = coreContext.contactsManager.magicSearch.getContactListFromFilter(filter.value.orEmpty(), domain)
|
||||||
|
|
||||||
val list = arrayListOf<SearchResult>()
|
val list = arrayListOf<SearchResult>()
|
||||||
for (result in results) {
|
for (result in results) {
|
||||||
|
|
|
@ -24,7 +24,6 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.SearchView
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
@ -104,6 +103,7 @@ class MasterContactsFragment : MasterFragment() {
|
||||||
it.consume { contact ->
|
it.consume { contact ->
|
||||||
Log.i("[Contacts] Selected item in list changed: $contact")
|
Log.i("[Contacts] Selected item in list changed: $contact")
|
||||||
sharedViewModel.selectedContact.value = contact
|
sharedViewModel.selectedContact.value = contact
|
||||||
|
listViewModel.filter.value = ""
|
||||||
|
|
||||||
if (editOnClick) {
|
if (editOnClick) {
|
||||||
goToContactEditor()
|
goToContactEditor()
|
||||||
|
@ -130,23 +130,16 @@ class MasterContactsFragment : MasterFragment() {
|
||||||
listViewModel.updateContactsList()
|
listViewModel.updateContactsList()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
listViewModel.filter.observe(viewLifecycleOwner, Observer {
|
||||||
|
listViewModel.updateContactsList()
|
||||||
|
})
|
||||||
|
|
||||||
binding.setNewContactClickListener {
|
binding.setNewContactClickListener {
|
||||||
// Remove any previously selected contact
|
// Remove any previously selected contact
|
||||||
sharedViewModel.selectedContact.value = null
|
sharedViewModel.selectedContact.value = null
|
||||||
goToContactEditor()
|
goToContactEditor()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
|
||||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQueryTextChange(newText: String?): Boolean {
|
|
||||||
listViewModel.filter(newText ?: "")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
val id = arguments?.getString("id")
|
val id = arguments?.getString("id")
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
Log.i("[Contacts] Found contact id parameter in arguments: $id")
|
Log.i("[Contacts] Found contact id parameter in arguments: $id")
|
||||||
|
|
|
@ -35,7 +35,7 @@ class ContactsListViewModel : ViewModel() {
|
||||||
|
|
||||||
val contactsList = MutableLiveData<ArrayList<Contact>>()
|
val contactsList = MutableLiveData<ArrayList<Contact>>()
|
||||||
|
|
||||||
private var filter: String = ""
|
val filter = MutableLiveData<String>()
|
||||||
|
|
||||||
private val contactsUpdatedListener = object : ContactsUpdatedListenerStub() {
|
private val contactsUpdatedListener = object : ContactsUpdatedListenerStub() {
|
||||||
override fun onContactsUpdated() {
|
override fun onContactsUpdated() {
|
||||||
|
@ -46,7 +46,6 @@ class ContactsListViewModel : ViewModel() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
sipContactsSelected.value = true
|
sipContactsSelected.value = true
|
||||||
filter = ""
|
|
||||||
|
|
||||||
coreContext.contactsManager.addListener(contactsUpdatedListener)
|
coreContext.contactsManager.addListener(contactsUpdatedListener)
|
||||||
}
|
}
|
||||||
|
@ -61,10 +60,10 @@ class ContactsListViewModel : ViewModel() {
|
||||||
var list = arrayListOf<Contact>()
|
var list = arrayListOf<Contact>()
|
||||||
list.addAll(if (sipContactsSelected.value == true) coreContext.contactsManager.sipContacts else coreContext.contactsManager.contacts)
|
list.addAll(if (sipContactsSelected.value == true) coreContext.contactsManager.sipContacts else coreContext.contactsManager.contacts)
|
||||||
|
|
||||||
if (filter.isNotEmpty()) {
|
val filterValue = filter.value.orEmpty().toLowerCase(Locale.getDefault())
|
||||||
val filter = filter.toLowerCase(Locale.getDefault())
|
if (filterValue.isNotEmpty()) {
|
||||||
list = list.filter { contact ->
|
list = list.filter { contact ->
|
||||||
contact.fullName?.toLowerCase(Locale.getDefault())?.contains(filter) ?: false
|
contact.fullName?.toLowerCase(Locale.getDefault())?.contains(filterValue) ?: false
|
||||||
} as ArrayList<Contact>
|
} as ArrayList<Contact>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,11 +73,6 @@ class ContactsListViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun filter(search: String) {
|
|
||||||
filter = search
|
|
||||||
updateContactsList()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun deleteContacts(list: ArrayList<Contact>) {
|
fun deleteContacts(list: ArrayList<Contact>) {
|
||||||
val select = ContactsContract.Data.CONTACT_ID + " = ?"
|
val select = ContactsContract.Data.CONTACT_ID + " = ?"
|
||||||
val ops = ArrayList<ContentProviderOperation>()
|
val ops = ArrayList<ContentProviderOperation>()
|
||||||
|
|
|
@ -92,6 +92,7 @@ class DialerViewModel : ViewModel() {
|
||||||
val addressToCall = enteredUri.value.orEmpty()
|
val addressToCall = enteredUri.value.orEmpty()
|
||||||
if (addressToCall.isNotEmpty()) {
|
if (addressToCall.isNotEmpty()) {
|
||||||
coreContext.startCall(addressToCall)
|
coreContext.startCall(addressToCall)
|
||||||
|
eraseAll()
|
||||||
} else {
|
} else {
|
||||||
setLastOutgoingCallAddress()
|
setLastOutgoingCallAddress()
|
||||||
}
|
}
|
||||||
|
@ -101,6 +102,7 @@ class DialerViewModel : ViewModel() {
|
||||||
val addressToCall = enteredUri.value.orEmpty()
|
val addressToCall = enteredUri.value.orEmpty()
|
||||||
if (addressToCall.isNotEmpty()) {
|
if (addressToCall.isNotEmpty()) {
|
||||||
coreContext.transferCallTo(addressToCall)
|
coreContext.transferCallTo(addressToCall)
|
||||||
|
eraseAll()
|
||||||
} else {
|
} else {
|
||||||
setLastOutgoingCallAddress()
|
setLastOutgoingCallAddress()
|
||||||
}
|
}
|
||||||
|
|
|
@ -440,3 +440,29 @@ fun setEditTextErrorListener(editText: EditText, attrChange: InverseBindingListe
|
||||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { }
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("queryValue")
|
||||||
|
fun setSearchViewQuery(view: SearchView, query: String?) {
|
||||||
|
if (query != view.query) {
|
||||||
|
view.setQuery(query, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@InverseBindingAdapter(attribute = "queryValue")
|
||||||
|
fun getSearchViewQuery(view: SearchView): String? {
|
||||||
|
return view.query?.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("queryValueAttrChanged")
|
||||||
|
fun setSearchViewQueryListener(view: SearchView, attrChange: InverseBindingListener) {
|
||||||
|
view.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||||
|
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQueryTextChange(newText: String?): Boolean {
|
||||||
|
attrChange.onChange()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -127,27 +127,19 @@
|
||||||
android:layout_alignTop="@id/top_bar"
|
android:layout_alignTop="@id/top_bar"
|
||||||
tools:layout="@layout/list_edit_top_bar_fragment" />
|
tools:layout="@layout/list_edit_top_bar_fragment" />
|
||||||
|
|
||||||
<RelativeLayout
|
<SearchView
|
||||||
android:id="@+id/searchBar"
|
android:id="@+id/searchBar"
|
||||||
|
queryValue="@={viewModel.filter}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="40dp"
|
||||||
android:focusableInTouchMode="true"
|
android:gravity="center"
|
||||||
|
android:iconifiedByDefault="false"
|
||||||
|
android:inputType="textPersonName"
|
||||||
android:layout_below="@id/top_bar"
|
android:layout_below="@id/top_bar"
|
||||||
android:layout_toRightOf="@id/tabs_fragment"
|
android:layout_toRightOf="@id/tabs_fragment"
|
||||||
android:layout_margin="10dp">
|
android:layout_margin="10dp"
|
||||||
|
android:queryBackground="@color/transparent_color"
|
||||||
<SearchView
|
android:queryHint="@string/contact_filter_hint"/>
|
||||||
android:id="@+id/searchView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:iconifiedByDefault="false"
|
|
||||||
android:inputType="textPersonName"
|
|
||||||
android:paddingRight="5dp"
|
|
||||||
android:queryBackground="@color/transparent_color"
|
|
||||||
android:queryHint="@string/contact_filter_hint"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/contactsList"
|
android:id="@+id/contactsList"
|
||||||
|
|
|
@ -137,26 +137,18 @@
|
||||||
android:layout_alignTop="@id/top_bar"
|
android:layout_alignTop="@id/top_bar"
|
||||||
tools:layout="@layout/list_edit_top_bar_fragment" />
|
tools:layout="@layout/list_edit_top_bar_fragment" />
|
||||||
|
|
||||||
<RelativeLayout
|
<SearchView
|
||||||
android:id="@+id/searchBar"
|
android:id="@+id/searchBar"
|
||||||
|
queryValue="@={viewModel.filter}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="40dp"
|
||||||
android:focusableInTouchMode="true"
|
android:gravity="center"
|
||||||
|
android:iconifiedByDefault="false"
|
||||||
|
android:inputType="textPersonName"
|
||||||
android:layout_below="@id/top_bar"
|
android:layout_below="@id/top_bar"
|
||||||
android:layout_margin="10dp">
|
android:layout_margin="10dp"
|
||||||
|
android:queryBackground="@color/transparent_color"
|
||||||
<SearchView
|
android:queryHint="@string/contact_filter_hint"/>
|
||||||
android:id="@+id/searchView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:iconifiedByDefault="false"
|
|
||||||
android:inputType="textPersonName"
|
|
||||||
android:paddingRight="5dp"
|
|
||||||
android:queryBackground="@color/transparent_color"
|
|
||||||
android:queryHint="@string/contact_filter_hint"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/contactsList"
|
android:id="@+id/contactsList"
|
||||||
|
|
|
@ -148,26 +148,19 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
<SearchView
|
||||||
android:id="@+id/searchBar"
|
android:id="@+id/searchBar"
|
||||||
|
queryValue="@={viewModel.filter}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="40dp"
|
||||||
android:focusableInTouchMode="true"
|
android:gravity="center"
|
||||||
|
android:iconifiedByDefault="false"
|
||||||
|
android:inputType="textPersonName"
|
||||||
android:layout_below="@id/top_bar"
|
android:layout_below="@id/top_bar"
|
||||||
android:layout_margin="10dp">
|
android:layout_margin="10dp"
|
||||||
|
android:paddingRight="5dp"
|
||||||
<SearchView
|
android:queryBackground="@color/transparent_color"
|
||||||
android:id="@+id/searchView"
|
android:queryHint="@string/contact_filter_hint"/>
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:iconifiedByDefault="false"
|
|
||||||
android:inputType="textPersonName"
|
|
||||||
android:paddingRight="5dp"
|
|
||||||
android:queryBackground="@color/transparent_color"
|
|
||||||
android:queryHint="@string/contact_filter_hint"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
android:visibility="@{viewModel.createGroupChat ? View.VISIBLE : View.GONE}"
|
android:visibility="@{viewModel.createGroupChat ? View.VISIBLE : View.GONE}"
|
||||||
|
|
|
@ -126,26 +126,18 @@
|
||||||
android:layout_alignTop="@id/top_bar"
|
android:layout_alignTop="@id/top_bar"
|
||||||
tools:layout="@layout/list_edit_top_bar_fragment" />
|
tools:layout="@layout/list_edit_top_bar_fragment" />
|
||||||
|
|
||||||
<RelativeLayout
|
<SearchView
|
||||||
android:id="@+id/searchBar"
|
android:id="@+id/searchBar"
|
||||||
|
queryValue="@={viewModel.filter}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="40dp"
|
||||||
android:focusableInTouchMode="true"
|
|
||||||
android:layout_below="@id/top_bar"
|
android:layout_below="@id/top_bar"
|
||||||
android:layout_margin="10dp">
|
android:layout_margin="10dp"
|
||||||
|
android:gravity="center"
|
||||||
<SearchView
|
android:iconifiedByDefault="false"
|
||||||
android:id="@+id/searchView"
|
android:inputType="textPersonName"
|
||||||
android:layout_width="match_parent"
|
android:queryBackground="@color/transparent_color"
|
||||||
android:layout_height="40dp"
|
android:queryHint="@string/contact_filter_hint"/>
|
||||||
android:gravity="center"
|
|
||||||
android:iconifiedByDefault="false"
|
|
||||||
android:inputType="textPersonName"
|
|
||||||
android:paddingRight="5dp"
|
|
||||||
android:queryBackground="@color/transparent_color"
|
|
||||||
android:queryHint="@string/contact_filter_hint"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/contactsList"
|
android:id="@+id/contactsList"
|
||||||
|
|
Loading…
Reference in a new issue