Added search for Contacts/Allowlist tab

This commit is contained in:
partisan 2025-05-18 09:24:05 +02:00
parent 6d9024a580
commit 6af51d8fc8
7 changed files with 72 additions and 5 deletions

View file

@ -8,9 +8,11 @@ import androidx.recyclerview.widget.RecyclerView
class ContactAdapter( class ContactAdapter(
private val prefs: Preferences, private val prefs: Preferences,
private val contacts: List<ContactEntry> private val fullList: List<ContactEntry>
) : RecyclerView.Adapter<ContactAdapter.ViewHolder>() { ) : RecyclerView.Adapter<ContactAdapter.ViewHolder>() {
private var filteredList = fullList.toMutableList()
inner class ViewHolder(inflater: LayoutInflater, parent: ViewGroup) : inner class ViewHolder(inflater: LayoutInflater, parent: ViewGroup) :
RecyclerView.ViewHolder(inflater.inflate(R.layout.item_contact, parent, false)) { RecyclerView.ViewHolder(inflater.inflate(R.layout.item_contact, parent, false)) {
val contactName: TextView = itemView.findViewById(R.id.contactName) val contactName: TextView = itemView.findViewById(R.id.contactName)
@ -22,8 +24,9 @@ class ContactAdapter(
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val contact = contacts[position] val contact = filteredList[position]
holder.contactName.text = contact.name holder.contactName.text = contact.name
holder.contactAllowed.setOnCheckedChangeListener(null)
holder.contactAllowed.isChecked = prefs.isContactWhitelisted(contact.phoneNumber) holder.contactAllowed.isChecked = prefs.isContactWhitelisted(contact.phoneNumber)
holder.contactAllowed.setOnCheckedChangeListener { _, isChecked -> holder.contactAllowed.setOnCheckedChangeListener { _, isChecked ->
@ -31,5 +34,16 @@ class ContactAdapter(
} }
} }
override fun getItemCount(): Int = contacts.size override fun getItemCount(): Int = filteredList.size
fun filter(query: String) {
filteredList = if (query.isBlank()) {
fullList.toMutableList()
} else {
fullList.filter {
it.name.contains(query, ignoreCase = true)
}.toMutableList()
}
notifyDataSetChanged()
}
} }

View file

@ -6,6 +6,7 @@ import android.provider.ContactsContract
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.graphics.Color
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import partisan.weforge.xyz.pulse.databinding.FragmentContactsBinding import partisan.weforge.xyz.pulse.databinding.FragmentContactsBinding
@ -47,15 +48,44 @@ class ContactsFragment : Fragment() {
(requireActivity() as? MainActivity)?.setupPopupToggle(false) (requireActivity() as? MainActivity)?.setupPopupToggle(false)
} }
private lateinit var adapter: ContactAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
prefs = Preferences(requireContext()) prefs = Preferences(requireContext())
val contacts = getContacts() val contacts = getContacts()
val adapter = ContactAdapter(prefs, contacts) adapter = ContactAdapter(prefs, contacts)
binding.contactRecycler.layoutManager = LinearLayoutManager(requireContext()) binding.contactRecycler.layoutManager = LinearLayoutManager(requireContext())
binding.contactRecycler.adapter = adapter binding.contactRecycler.adapter = adapter
binding.contactSearch.setOnQueryTextListener(object : androidx.appcompat.widget.SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean = false
override fun onQueryTextChange(newText: String?): Boolean {
adapter.filter(newText ?: "")
return true
}
})
val searchView = binding.contactSearch
searchView.setIconifiedByDefault(false)
searchView.isIconified = false
searchView.isSubmitButtonEnabled = false
searchView.clearFocus()
val editText = searchView.findViewById<androidx.appcompat.widget.SearchView.SearchAutoComplete>(
androidx.appcompat.R.id.search_src_text
)
editText.isFocusable = true
editText.isFocusableInTouchMode = true
editText.setTextColor(Color.WHITE)
editText.setHintTextColor(Color.LTGRAY)
val searchPlate = searchView.findViewById<View>(androidx.appcompat.R.id.search_plate)
searchPlate.setBackgroundColor(Color.TRANSPARENT)
searchPlate.setPadding(0, 0, 0, 0)
} }
private fun getContacts(): List<ContactEntry> { private fun getContacts(): List<ContactEntry> {

View file

@ -0,0 +1,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/colorSurfaceVariant" />
<corners android:radius="50dp" />
</shape>

View file

@ -6,11 +6,25 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="16dp"> android:padding="16dp">
<androidx.appcompat.widget.SearchView
android:id="@+id/contactSearch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:background="@drawable/search_background"
android:iconifiedByDefault="false"
android:queryHint="@string/contact_search"
android:layout_marginTop="8dp"
android:layout_marginHorizontal="4dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/contactRecycler" android:id="@+id/contactRecycler"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toBottomOf="@id/contactSearch"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View file

@ -14,4 +14,6 @@
<color name="colorOnSecondary">#000000</color> <color name="colorOnSecondary">#000000</color>
<color name="launcher_background">@color/colorPrimary</color> <color name="launcher_background">@color/colorPrimary</color>
<color name="colorSurfaceVariant">#2B3542</color>
</resources> </resources>

View file

@ -16,6 +16,7 @@
<string name="destination_whatsapp">WhatsApp</string> <string name="destination_whatsapp">WhatsApp</string>
<string name="redirection_delay_description">The delay before a call will be redirected.</string> <string name="redirection_delay_description">The delay before a call will be redirected.</string>
<string name="services_desc">Here you can enable or disable redirection to individual services and change their priority by dragging them. Redirection will be handled in order from top to bottom.</string> <string name="services_desc">Here you can enable or disable redirection to individual services and change their priority by dragging them. Redirection will be handled in order from top to bottom.</string>
<string name="contact_search">Filter contacts</string>
<string name="popup_position">Popup position</string> <string name="popup_position">Popup position</string>
<string name="activate_description">To start, grant the required permissions by tapping the Activate button.</string> <string name="activate_description">To start, grant the required permissions by tapping the Activate button.</string>
<string name="activate">Activate</string> <string name="activate">Activate</string>

View file

@ -12,5 +12,6 @@
<item name="colorOnSurface">@color/black</item> <item name="colorOnSurface">@color/black</item>
<item name="textAppearanceBodyMedium">@style/TextAppearance.Material3.BodyMedium</item> <item name="textAppearanceBodyMedium">@style/TextAppearance.Material3.BodyMedium</item>
<item name="colorSurfaceContainerLowest">?attr/colorSurfaceContainerLowest</item> <item name="colorSurfaceContainerLowest">?attr/colorSurfaceContainerLowest</item>
<item name="colorSurfaceVariant">@color/colorSurfaceVariant</item>
</style> </style>
</resources> </resources>