Contacts searching. Broken.

This commit is contained in:
ottoptj 2024-09-07 10:59:58 +03:00
commit 62f8cc679a
17 changed files with 444 additions and 66 deletions

View file

@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" /> <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" /> <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" /> tools:ignore="QueryAllPackagesPermission" />

View file

@ -136,7 +136,7 @@ class AppMenuAdapter(
uiUtils.setItemSpacing(holder.textView) uiUtils.setItemSpacing(holder.textView)
uiUtils.setTextFont(holder.textView) uiUtils.setTextFont(holder.listItem)
holder.textView.setTextColor(sharedPreferenceManager.getTextColor()) holder.textView.setTextColor(sharedPreferenceManager.getTextColor())
// Update the application information (allows updating apps to work) // Update the application information (allows updating apps to work)

View file

@ -0,0 +1,77 @@
package eu.ottop.yamlauncher
import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.TextView
import androidx.core.content.res.ResourcesCompat
import androidx.recyclerview.widget.RecyclerView
import eu.ottop.yamlauncher.settings.SharedPreferenceManager
import eu.ottop.yamlauncher.utils.UIUtils
class ContactsAdapter(
private val context: Context,
private var contacts: MutableList<Pair<String, Int>>,
private val contactClickListener: OnContactClickListener
) :
RecyclerView.Adapter<ContactsAdapter.AppViewHolder>() {
private val uiUtils = UIUtils(context)
private val sharedPreferenceManager = SharedPreferenceManager(context)
interface OnContactClickListener {
fun onContactClick(contactId: Int)
}
inner class AppViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val listItem: FrameLayout = itemView.findViewById(R.id.listItem)
val textView: TextView = listItem.findViewById(R.id.appName)
init {
textView.setOnClickListener {
val position = bindingAdapterPosition
val contact = contacts[position]
contactClickListener.onContactClick(contact.second)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.app_item_layout, parent, false)
return AppViewHolder(view)
}
override fun onBindViewHolder(holder: AppViewHolder, position: Int) {
val contact = contacts[position]
holder.textView.setCompoundDrawablesWithIntrinsicBounds(
ResourcesCompat.getDrawable(context.resources, R.drawable.ic_empty, null),null, ResourcesCompat.getDrawable(context.resources, R.drawable.ic_empty, null),null)
uiUtils.setAppAlignment(holder.textView)
uiUtils.setAppSize(holder.textView)
uiUtils.setItemSpacing(holder.textView)
uiUtils.setTextFont(holder.listItem)
holder.textView.setTextColor(sharedPreferenceManager.getTextColor())
holder.textView.text = contact.first
holder.textView.visibility = View.VISIBLE
}
override fun getItemCount(): Int {
return contacts.size
}
@SuppressLint("NotifyDataSetChanged")
fun updateContacts(newContacts: List<Pair<String, Int>>) {
contacts = newContacts.toMutableList()
notifyDataSetChanged()
}
}

View file

@ -1,33 +1,44 @@
package eu.ottop.yamlauncher package eu.ottop.yamlauncher
import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.ContentResolver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps import android.content.pm.LauncherApps
import android.content.pm.PackageManager
import android.database.Cursor
import android.graphics.BlendMode import android.graphics.BlendMode
import android.graphics.BlendModeColorFilter import android.graphics.BlendModeColorFilter
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.UserHandle import android.os.UserHandle
import android.provider.AlarmClock import android.provider.AlarmClock
import android.provider.ContactsContract
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.GestureDetector import android.view.GestureDetector
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextClock import android.widget.TextClock
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import android.widget.ViewSwitcher
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.database.getStringOrNull
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.marginLeft import androidx.core.view.marginLeft
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
@ -49,6 +60,7 @@ import eu.ottop.yamlauncher.utils.GestureUtils
import eu.ottop.yamlauncher.utils.StringUtils import eu.ottop.yamlauncher.utils.StringUtils
import eu.ottop.yamlauncher.utils.UIUtils import eu.ottop.yamlauncher.utils.UIUtils
import eu.ottop.yamlauncher.utils.WeatherSystem import eu.ottop.yamlauncher.utils.WeatherSystem
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -57,7 +69,7 @@ import java.lang.reflect.Method
import kotlin.math.abs import kotlin.math.abs
class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener, AppMenuAdapter.OnItemClickListener, AppMenuAdapter.OnShortcutListener, AppMenuAdapter.OnItemLongClickListener { class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener, AppMenuAdapter.OnItemClickListener, AppMenuAdapter.OnShortcutListener, AppMenuAdapter.OnItemLongClickListener, ContactsAdapter.OnContactClickListener {
private lateinit var weatherSystem: WeatherSystem private lateinit var weatherSystem: WeatherSystem
private lateinit var appUtils: AppUtils private lateinit var appUtils: AppUtils
@ -66,6 +78,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private lateinit var gestureUtils: GestureUtils private lateinit var gestureUtils: GestureUtils
private val appMenuLinearLayoutManager = AppMenuLinearLayoutManager(this@MainActivity) private val appMenuLinearLayoutManager = AppMenuLinearLayoutManager(this@MainActivity)
private val contactMenuLinearLayoutManager = AppMenuLinearLayoutManager(this@MainActivity)
private val appMenuEdgeFactory = AppMenuEdgeFactory(this@MainActivity) private val appMenuEdgeFactory = AppMenuEdgeFactory(this@MainActivity)
private lateinit var sharedPreferenceManager: SharedPreferenceManager private lateinit var sharedPreferenceManager: SharedPreferenceManager
@ -77,9 +90,13 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private lateinit var dateText: TextClock private lateinit var dateText: TextClock
private var dateElements = mutableListOf<String>() private var dateElements = mutableListOf<String>()
private lateinit var recyclerView: RecyclerView private lateinit var menuView: ViewSwitcher
private lateinit var appRecycler: RecyclerView
private lateinit var contactRecycler: RecyclerView
private lateinit var searchSwitcher: ImageView
private lateinit var searchView: TextInputEditText private lateinit var searchView: TextInputEditText
private var adapter: AppMenuAdapter? = null private var appAdapter: AppMenuAdapter? = null
private var contactAdapter: ContactsAdapter? = null
private var batteryReceiver: BatteryReceiver? = null private var batteryReceiver: BatteryReceiver? = null
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
@ -105,6 +122,8 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
var returnAllowed = true var returnAllowed = true
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater) binding = ActivityMainBinding.inflate(layoutInflater)
@ -154,15 +173,19 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
gestureDetector = GestureDetector(this, GestureListener()) gestureDetector = GestureDetector(this, GestureListener())
shortcutGestureDetector = GestureDetector(this, TextGestureListener()) shortcutGestureDetector = GestureDetector(this, TextGestureListener())
clock = findViewById(R.id.textClock) clock = binding.textClock
clockMargin = clock.marginLeft clockMargin = clock.marginLeft
dateText = findViewById(R.id.textDate) dateText = binding.textDate
dateElements = mutableListOf(dateText.format12Hour.toString(), dateText.format24Hour.toString(), "", "") dateElements = mutableListOf(dateText.format12Hour.toString(), dateText.format24Hour.toString(), "", "")
searchView = findViewById(R.id.searchView) menuView = binding.menuView
searchSwitcher = binding.searchSwitcher
searchView = binding.searchView
preferences = PreferenceManager.getDefaultSharedPreferences(this) preferences = PreferenceManager.getDefaultSharedPreferences(this)
} }
@ -183,8 +206,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
else { else {
textView.visibility = View.VISIBLE textView.visibility = View.VISIBLE
val savedView = sharedPreferenceManager.getShortcut(textView) val savedView = sharedPreferenceManager.getShortcut(textView)
// Set the non-work profile drawable by default // Set the non-work profile drawable by default
@ -217,7 +238,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
uiUtils.setMenuTitleAlignment(binding.menuTitle) uiUtils.setMenuTitleAlignment(binding.menuTitle)
binding.menuTitle.visibility = View.VISIBLE binding.menuTitle.visibility = View.VISIBLE
adapter?.shortcutTextView = textView appAdapter?.shortcutTextView = textView
toAppMenu() toAppMenu()
true true
} }
@ -236,7 +257,8 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
uiUtils.setMenuTitleAlignment(binding.menuTitle) uiUtils.setMenuTitleAlignment(binding.menuTitle)
binding.menuTitle.visibility = View.VISIBLE binding.menuTitle.visibility = View.VISIBLE
adapter?.shortcutTextView = textView appAdapter?.shortcutTextView = textView
searchSwitcher.visibility = View.GONE
toAppMenu() toAppMenu()
return@setOnLongClickListener true return@setOnLongClickListener true
@ -246,11 +268,12 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private fun toAppMenu() { private fun toAppMenu() {
try { try {
// The menu opens from the top // The menu opens from the top
recyclerView.scrollToPosition(0) appRecycler.scrollToPosition(0)
} contactRecycler.scrollToPosition(0)
catch (_: UninitializedPropertyAccessException) { menuView.displayedChild = 0
searchSwitcher.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.contacts_24px, null))
} }
catch (_: UninitializedPropertyAccessException) {}
animations.showApps(binding.homeView, binding.appView) animations.showApps(binding.homeView, binding.appView)
animations.backgroundIn(this@MainActivity) animations.backgroundIn(this@MainActivity)
if (sharedPreferenceManager.isAutoKeyboardEnabled()) { if (sharedPreferenceManager.isAutoKeyboardEnabled()) {
@ -293,7 +316,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private fun setPreferences() { private fun setPreferences() {
uiUtils.setBackground(window) uiUtils.setBackground(window)
uiUtils.setTextFont(binding.homeView) uiUtils.setTextFont(binding.homeView)
uiUtils.setFont(searchView) uiUtils.setFont(searchView)
uiUtils.setFont(binding.menuTitle) uiUtils.setFont(binding.menuTitle)
@ -302,9 +324,11 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
uiUtils.setMenuItemColors(binding.menuTitle, "A9") uiUtils.setMenuItemColors(binding.menuTitle, "A9")
uiUtils.setImageColor(searchSwitcher)
uiUtils.setClockVisibility(clock) uiUtils.setClockVisibility(clock)
uiUtils.setDateVisibility(dateText) uiUtils.setDateVisibility(dateText)
uiUtils.setSearchVisibility(searchView, binding.searchReplacement) uiUtils.setSearchVisibility(searchView, binding.searchLayout, binding.searchReplacement)
uiUtils.setClockAlignment(clock, dateText) uiUtils.setClockAlignment(clock, dateText)
uiUtils.setSearchAlignment(searchView) uiUtils.setSearchAlignment(searchView)
@ -317,11 +341,10 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
uiUtils.setShortcutsSpacing(binding.homeView) uiUtils.setShortcutsSpacing(binding.homeView)
// This didn't work and somehow delaying it by 0 makes it work // This didn't work and somehow delaying it by 0 makes it work
val handler = Handler(Looper.getMainLooper())
handler.postDelayed({ handler.postDelayed({
uiUtils.setStatusBar(window) uiUtils.setStatusBar(window)
uiUtils.setMenuItemColors(searchView) uiUtils.setMenuItemColors(searchView)
}, 0) }, 100)
clockApp = gestureUtils.getSwipeInfo(launcherApps, "clock") clockApp = gestureUtils.getSwipeInfo(launcherApps, "clock")
dateApp = gestureUtils.getSwipeInfo(launcherApps, "date") dateApp = gestureUtils.getSwipeInfo(launcherApps, "date")
@ -420,8 +443,9 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
} }
private fun openAppMenu() { private fun openAppMenu() {
adapter?.shortcutTextView = null appAdapter?.shortcutTextView = null
binding.menuTitle.visibility = View.GONE binding.menuTitle.visibility = View.GONE
uiUtils.setContactsVisibility(searchSwitcher, binding.searchLayout, binding.searchReplacement)
toAppMenu() toAppMenu()
} }
@ -437,6 +461,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
uiUtils.setTextColors(binding.homeView) uiUtils.setTextColors(binding.homeView)
uiUtils.setMenuItemColors(searchView) uiUtils.setMenuItemColors(searchView)
uiUtils.setMenuItemColors(binding.menuTitle, "A9") uiUtils.setMenuItemColors(binding.menuTitle, "A9")
uiUtils.setImageColor(searchSwitcher)
} }
"textFont" -> { "textFont" -> {
@ -460,7 +485,14 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
} }
"searchEnabled" -> { "searchEnabled" -> {
uiUtils.setSearchVisibility(searchView, binding.searchReplacement) uiUtils.setSearchVisibility(searchView, binding.searchLayout, binding.searchReplacement)
}
"contactsEnabled" -> {
if (sharedPreferenceManager.areContactsEnabled()) {
checkContactsPermission()
}
uiUtils.setContactsVisibility(searchSwitcher, binding.searchLayout, binding.searchReplacement)
} }
"clockAlignment" -> { "clockAlignment" -> {
@ -569,7 +601,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
// Delay app menu changes so that the user doesn't see them // Delay app menu changes so that the user doesn't see them
val handler = Handler(Looper.getMainLooper())
handler.postDelayed({ handler.postDelayed({
try { try {
searchView.setText(R.string.empty) searchView.setText(R.string.empty)
@ -583,8 +614,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
handler.postDelayed({ handler.postDelayed({
lifecycleScope.launch { lifecycleScope.launch {
refreshAppMenu() refreshAppMenu()
}}, animSpeed + 50) }}, animSpeed + 50)
} }
@ -627,7 +656,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private suspend fun updateMenu(updatedApps: List<Triple<LauncherActivityInfo, UserHandle, Int>>) { private suspend fun updateMenu(updatedApps: List<Triple<LauncherActivityInfo, UserHandle, Int>>) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
adapter?.updateApps(updatedApps) appAdapter?.updateApps(updatedApps)
} }
} }
@ -660,39 +689,120 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
installedApps = appUtils.getInstalledApps() installedApps = appUtils.getInstalledApps()
val newApps = installedApps.toMutableList() val newApps = installedApps.toMutableList()
setupRecyclerView(newApps) setupAppRecycler(newApps)
setupSearch() setupSearch()
if (sharedPreferenceManager.areContactsEnabled()) {
setupContactRecycler()
}
} }
} }
private suspend fun setupRecyclerView(newApps: MutableList<Triple<LauncherActivityInfo, UserHandle, Int>>) { private suspend fun setupAppRecycler(newApps: MutableList<Triple<LauncherActivityInfo, UserHandle, Int>>) {
adapter = AppMenuAdapter(this@MainActivity, binding, newApps, this@MainActivity, this@MainActivity, this@MainActivity, launcherApps) appAdapter = AppMenuAdapter(this@MainActivity, binding, newApps, this@MainActivity, this@MainActivity, this@MainActivity, launcherApps)
appMenuLinearLayoutManager.stackFromEnd = true appMenuLinearLayoutManager.stackFromEnd = true
recyclerView = findViewById(R.id.recyclerView) appRecycler = binding.appRecycler
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
recyclerView.layoutManager = appMenuLinearLayoutManager appRecycler.layoutManager = appMenuLinearLayoutManager
recyclerView.edgeEffectFactory = appMenuEdgeFactory appRecycler.edgeEffectFactory = appMenuEdgeFactory
recyclerView.adapter = adapter appRecycler.adapter = appAdapter
} }
setupRecyclerListener() setupRecyclerListener(appRecycler, appMenuLinearLayoutManager)
} }
// Inform the layout manager of scroll states to calculate whether the menu is on the top // Inform the layout manager of scroll states to calculate whether the menu is on the top
private fun setupRecyclerListener() { private fun setupRecyclerListener(recycler:RecyclerView, layoutManager: AppMenuLinearLayoutManager) {
recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() { recycler.addOnScrollListener(object: RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState) super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
appMenuLinearLayoutManager.setScrollInfo() layoutManager.setScrollInfo()
} }
} }
}) })
} }
private suspend fun setupContactRecycler() {
contactAdapter = ContactsAdapter(this, mutableListOf(), this)
contactRecycler = binding.contactRecycler
withContext(Dispatchers.Main) {
contactRecycler.layoutManager = contactMenuLinearLayoutManager
contactRecycler.edgeEffectFactory = appMenuEdgeFactory
contactRecycler.adapter = contactAdapter
}
setupRecyclerListener(contactRecycler, contactMenuLinearLayoutManager)
}
private fun getContacts(filterString: String): MutableList<Pair<String, Int>> {
if (!checkContactsPermission()) {
return mutableListOf()
}
val contacts = mutableListOf<Pair<String, Int>>()
val contentResolver: ContentResolver = contentResolver
val projection = arrayOf(
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME
)
val selection = "${ContactsContract.Contacts.DISPLAY_NAME} LIKE ?"
val selectionArgs = arrayOf("%$filterString%")
val cursor: Cursor? = contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
projection,
selection,
selectionArgs,
"${ContactsContract.Contacts.DISPLAY_NAME} ASC"
)
cursor?.use {
val nameIndex = it.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)
val idIndex = it.getColumnIndex(ContactsContract.Contacts._ID)
while (it.moveToNext()) {
val name = it.getStringOrNull(nameIndex)
val id = it.getStringOrNull(idIndex)?.toInt()
if (name != null && id != null) {
contacts.add(Pair(name, id))
}
}
}
return contacts
}
private fun checkContactsPermission(): Boolean {
try {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_CONTACTS
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.READ_CONTACTS),
1
)
return false
}
return true
} catch(_: Exception) {
return false
}
}
private suspend fun updateContacts(filterString: String) {
val contacts = getContacts(filterString)
withContext(Dispatchers.Main) {
contactAdapter?.updateContacts(contacts)
}
}
private suspend fun setupSearch() { private suspend fun setupSearch() {
binding.appView.addOnLayoutChangeListener { _, _, top, _, bottom, _, oldTop, _, oldBottom -> binding.appView.addOnLayoutChangeListener { _, _, top, _, bottom, _, oldTop, _, oldBottom ->
@ -718,6 +828,19 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
} }
} }
}) })
searchSwitcher.setOnClickListener {
menuView.showNext()
when (menuView.displayedChild) {
0 -> searchSwitcher.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.contacts_24px, null))
1 -> {
lifecycleScope.launch(Dispatchers.Default) {
updateContacts("")
}
searchSwitcher.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.apps_24px, null))}
}
}
} }
private suspend fun filterItems(query: String?) { private suspend fun filterItems(query: String?) {
@ -727,6 +850,9 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
val updatedApps = appUtils.getInstalledApps() val updatedApps = appUtils.getInstalledApps()
getFilteredApps(cleanQuery, newFilteredApps, updatedApps) getFilteredApps(cleanQuery, newFilteredApps, updatedApps)
if (sharedPreferenceManager.areContactsEnabled() && cleanQuery != null) {
updateContacts(cleanQuery)
}
} }
private suspend fun getFilteredApps(cleanQuery: String?, newFilteredApps: MutableList<Triple<LauncherActivityInfo, UserHandle, Int>>, updatedApps: List<Triple<LauncherActivityInfo, UserHandle, Int>>) { private suspend fun getFilteredApps(cleanQuery: String?, newFilteredApps: MutableList<Triple<LauncherActivityInfo, UserHandle, Int>>, updatedApps: List<Triple<LauncherActivityInfo, UserHandle, Int>>) {
@ -767,12 +893,12 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
fun disableAppMenuScroll() { fun disableAppMenuScroll() {
appMenuLinearLayoutManager.setScrollEnabled(false) appMenuLinearLayoutManager.setScrollEnabled(false)
recyclerView.layoutManager = appMenuLinearLayoutManager appRecycler.layoutManager = appMenuLinearLayoutManager
} }
fun enableAppMenuScroll() { fun enableAppMenuScroll() {
appMenuLinearLayoutManager.setScrollEnabled(true) appMenuLinearLayoutManager.setScrollEnabled(true)
recyclerView.layoutManager = appMenuLinearLayoutManager appRecycler.layoutManager = appMenuLinearLayoutManager
} }
// On home key or swipe, return to home screen // On home key or swipe, return to home screen
@ -801,7 +927,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
backToHome(0) backToHome(0)
} }
returnAllowed = true returnAllowed = true
adapter?.notifyDataSetChanged() appAdapter?.notifyDataSetChanged()
} }
override fun onItemClick(appInfo: LauncherActivityInfo, userHandle: UserHandle) { override fun onItemClick(appInfo: LauncherActivityInfo, userHandle: UserHandle) {
@ -932,4 +1058,15 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
} }
} }
override fun onContactClick(contactId: Int) {
val contactUri: Uri = Uri.withAppendedPath(
ContactsContract.Contacts.CONTENT_URI,
contactId.toString()
)
val intent = Intent(Intent.ACTION_VIEW, contactUri)
startActivity(intent)
returnAllowed = false
}
} }

View file

@ -204,6 +204,10 @@ class SharedPreferenceManager (private val context: Context) {
return preferences.getBoolean("autoKeyboard", false) return preferences.getBoolean("autoKeyboard", false)
} }
fun areContactsEnabled(): Boolean {
return preferences.getBoolean("contactsEnabled", false)
}
// Hidden Apps // Hidden Apps
fun setAppHidden(packageName: String, profile: Int, hidden: Boolean) { fun setAppHidden(packageName: String, profile: Int, hidden: Boolean) {
val editor = preferences.edit() val editor = preferences.edit()

View file

@ -13,6 +13,7 @@ import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.Window import android.view.Window
import android.view.WindowInsets import android.view.WindowInsets
import android.view.WindowInsetsController import android.view.WindowInsetsController
import android.widget.ImageView
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.Space import android.widget.Space
import android.widget.TextClock import android.widget.TextClock
@ -36,6 +37,10 @@ class UIUtils(private val context: Context) {
) )
} }
fun setImageColor(view: ImageView) {
view.setColorFilter(sharedPreferenceManager.getTextColor())
}
fun setTextColors(view: View) { fun setTextColors(view: View) {
val color = sharedPreferenceManager.getTextColor() val color = sharedPreferenceManager.getTextColor()
when { when {
@ -148,13 +153,31 @@ class UIUtils(private val context: Context) {
} }
} }
fun setSearchVisibility(searchView: TextInputEditText, replacementView: View) { fun setSearchVisibility(searchView: View, searchLayout: View, replacementView: View) {
setSearchLayoutVisibility(searchLayout, replacementView)
if (sharedPreferenceManager.isSearchEnabled()) { if (sharedPreferenceManager.isSearchEnabled()) {
searchView.visibility = View.VISIBLE searchView.visibility = View.VISIBLE
replacementView.visibility = View.GONE
} else { } else {
searchView.visibility = View.GONE searchView.visibility = View.GONE
}
}
fun setContactsVisibility(contactsView: View, searchLayout: View, replacementView: View) {
setSearchLayoutVisibility(searchLayout, replacementView)
if (sharedPreferenceManager.areContactsEnabled()) {
contactsView.visibility = View.VISIBLE
} else {
contactsView.visibility = View.GONE
}
}
private fun setSearchLayoutVisibility(searchLayout: View, replacementView: View) {
if (!sharedPreferenceManager.isSearchEnabled() && !sharedPreferenceManager.areContactsEnabled()) {
searchLayout.visibility = View.GONE
replacementView.visibility = View.VISIBLE replacementView.visibility = View.VISIBLE
} else {
replacementView.visibility = View.GONE
searchLayout.visibility = View.VISIBLE
} }
} }

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M240,800Q207,800 183.5,776.5Q160,753 160,720Q160,687 183.5,663.5Q207,640 240,640Q273,640 296.5,663.5Q320,687 320,720Q320,753 296.5,776.5Q273,800 240,800ZM480,800Q447,800 423.5,776.5Q400,753 400,720Q400,687 423.5,663.5Q447,640 480,640Q513,640 536.5,663.5Q560,687 560,720Q560,753 536.5,776.5Q513,800 480,800ZM720,800Q687,800 663.5,776.5Q640,753 640,720Q640,687 663.5,663.5Q687,640 720,640Q753,640 776.5,663.5Q800,687 800,720Q800,753 776.5,776.5Q753,800 720,800ZM240,560Q207,560 183.5,536.5Q160,513 160,480Q160,447 183.5,423.5Q207,400 240,400Q273,400 296.5,423.5Q320,447 320,480Q320,513 296.5,536.5Q273,560 240,560ZM480,560Q447,560 423.5,536.5Q400,513 400,480Q400,447 423.5,423.5Q447,400 480,400Q513,400 536.5,423.5Q560,447 560,480Q560,513 536.5,536.5Q513,560 480,560ZM720,560Q687,560 663.5,536.5Q640,513 640,480Q640,447 663.5,423.5Q687,400 720,400Q753,400 776.5,423.5Q800,447 800,480Q800,513 776.5,536.5Q753,560 720,560ZM240,320Q207,320 183.5,296.5Q160,273 160,240Q160,207 183.5,183.5Q207,160 240,160Q273,160 296.5,183.5Q320,207 320,240Q320,273 296.5,296.5Q273,320 240,320ZM480,320Q447,320 423.5,296.5Q400,273 400,240Q400,207 423.5,183.5Q447,160 480,160Q513,160 536.5,183.5Q560,207 560,240Q560,273 536.5,296.5Q513,320 480,320ZM720,320Q687,320 663.5,296.5Q640,273 640,240Q640,207 663.5,183.5Q687,160 720,160Q753,160 776.5,183.5Q800,207 800,240Q800,273 776.5,296.5Q753,320 720,320Z"/>
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M256,760L200,704L424,480L200,256L256,200L480,424L704,200L760,256L536,480L760,704L704,760L480,536L256,760Z"/>
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M160,920L160,840L800,840L800,920L160,920ZM160,120L160,40L800,40L800,120L160,120ZM480,520Q530,520 565,485Q600,450 600,400Q600,350 565,315Q530,280 480,280Q430,280 395,315Q360,350 360,400Q360,450 395,485Q430,520 480,520ZM160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L800,160Q833,160 856.5,183.5Q880,207 880,240L880,720Q880,753 856.5,776.5Q833,800 800,800L160,800ZM230,720Q275,664 339,632Q403,600 480,600Q557,600 621,632Q685,664 730,720L800,720Q800,720 800,720Q800,720 800,720L800,240Q800,240 800,240Q800,240 800,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720L230,720ZM348,720L612,720Q583,700 549.5,690Q516,680 480,680Q444,680 410.5,690Q377,700 348,720ZM480,440Q463,440 451.5,428.5Q440,417 440,400Q440,383 451.5,371.5Q463,360 480,360Q497,360 508.5,371.5Q520,383 520,400Q520,417 508.5,428.5Q497,440 480,440ZM480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M280,840Q247,840 223.5,816.5Q200,793 200,760L200,240L160,240L160,160L360,160L360,120L600,120L600,160L800,160L800,240L760,240L760,760Q760,793 736.5,816.5Q713,840 680,840L280,840ZM680,240L280,240L280,760Q280,760 280,760Q280,760 280,760L680,760Q680,760 680,760Q680,760 680,760L680,240ZM360,680L440,680L440,320L360,320L360,680ZM520,680L600,680L600,320L520,320L520,680ZM280,240L280,240L280,760Q280,760 280,760Q280,760 280,760L280,760Q280,760 280,760Q280,760 280,760L280,240Z"/>
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M200,760L257,760L648,369L591,312L200,703L200,760ZM120,840L120,670L648,143Q660,132 674.5,126Q689,120 705,120Q721,120 736,126Q751,132 762,144L817,200Q829,211 834.5,226Q840,241 840,256Q840,272 834.5,286.5Q829,301 817,313L290,840L120,840ZM760,256L760,256L704,200L704,200L760,256ZM619,341L591,312L591,312L648,369L648,369L619,341Z"/>
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M440,680L520,680L520,440L440,440L440,680ZM480,360Q497,360 508.5,348.5Q520,337 520,320Q520,303 508.5,291.5Q497,280 480,280Q463,280 451.5,291.5Q440,303 440,320Q440,337 451.5,348.5Q463,360 480,360ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M784,840L532,588Q502,612 463,626Q424,640 380,640Q271,640 195.5,564.5Q120,489 120,380Q120,271 195.5,195.5Q271,120 380,120Q489,120 564.5,195.5Q640,271 640,380Q640,424 626,463Q612,502 588,532L840,784L784,840ZM380,560Q455,560 507.5,507.5Q560,455 560,380Q560,305 507.5,252.5Q455,200 380,200Q305,200 252.5,252.5Q200,305 200,380Q200,455 252.5,507.5Q305,560 380,560Z"/>
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M644,532L586,474Q595,427 559,386Q523,345 466,354L408,296Q425,288 442.5,284Q460,280 480,280Q555,280 607.5,332.5Q660,385 660,460Q660,480 656,497.5Q652,515 644,532ZM772,658L714,602Q752,573 781.5,538.5Q811,504 832,460Q782,359 688.5,299.5Q595,240 480,240Q451,240 423,244Q395,248 368,256L306,194Q347,177 390,168.5Q433,160 480,160Q631,160 749,243.5Q867,327 920,460Q897,519 859.5,569.5Q822,620 772,658ZM792,904L624,738Q589,749 553.5,754.5Q518,760 480,760Q329,760 211,676.5Q93,593 40,460Q61,407 93,361.5Q125,316 166,280L56,168L112,112L848,848L792,904ZM222,336Q193,362 169,393Q145,424 128,460Q178,561 271.5,620.5Q365,680 480,680Q500,680 519,677.5Q538,675 558,672L522,634Q511,637 501,638.5Q491,640 480,640Q405,640 352.5,587.5Q300,535 300,460Q300,449 301.5,439Q303,429 306,418L222,336ZM541,429L541,429Q541,429 541,429Q541,429 541,429Q541,429 541,429Q541,429 541,429Q541,429 541,429Q541,429 541,429ZM390,504Q390,504 390,504Q390,504 390,504L390,504Q390,504 390,504Q390,504 390,504Q390,504 390,504Q390,504 390,504Z"/>
</vector>

View file

@ -36,38 +36,90 @@
android:textColor="#C1F3F3F3" android:textColor="#C1F3F3F3"
android:textSize="36sp" /> android:textSize="36sp" />
<androidx.recyclerview.widget.RecyclerView <ViewSwitcher
android:id="@+id/recyclerView" android:id="@+id/menuView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1.1"
android:clipToPadding="false" android:clipToPadding="false">
android:fadingEdgeLength="20dp"
android:padding="0dp"
android:requiresFadingEdge="vertical"
android:scrollbars="none">
</androidx.recyclerview.widget.RecyclerView> <androidx.recyclerview.widget.RecyclerView
android:id="@+id/appRecycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:fadingEdgeLength="20dp"
android:padding="0dp"
android:requiresFadingEdge="vertical"
android:scrollbars="none">
<com.google.android.material.textfield.TextInputEditText </androidx.recyclerview.widget.RecyclerView>
android:id="@+id/searchView"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/contactRecycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:fadingEdgeLength="20dp"
android:padding="0dp"
android:requiresFadingEdge="vertical"
android:scrollbars="none">
</androidx.recyclerview.widget.RecyclerView>
</ViewSwitcher>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/searchLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp" android:layout_marginHorizontal="32dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:layout_weight="0.1" android:layout_weight="0.1"
android:background="@android:color/transparent" android:orientation="horizontal"
android:cursorVisible="true" app:layout_constraintEnd_toStartOf="@+id/searchSwitcher"
android:drawableStart="@drawable/search_24px" app:layout_constraintStart_toStartOf="@+id/searchSwitcher">
android:drawablePadding="8dp"
android:editTextColor="#f3f3f3" <com.google.android.material.textfield.TextInputEditText
android:hint="@string/search" android:id="@+id/searchView"
android:singleLine="true" android:layout_width="0dp"
android:textAlignment="viewStart" android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.DeviceDefault" android:background="@android:color/transparent"
android:textColorHighlight="#5F33B5E5" android:cursorVisible="true"
android:textSize="25sp" /> android:drawableStart="@drawable/search_24px"
android:drawablePadding="8dp"
android:editTextColor="#f3f3f3"
android:hint="@string/search"
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
android:textColorHighlight="#5F33B5E5"
android:textSize="25sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/searchSwitcher"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_conversion_absoluteHeight="0dp"
tools:layout_conversion_absoluteWidth="0dp" />
<ImageView
android:id="@+id/searchSwitcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:padding="6dp"
android:scaleType="fitCenter"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/searchView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/searchView"
app:layout_constraintTop_toTopOf="@+id/searchView"
app:srcCompat="@drawable/apps_24px"
tools:layout_conversion_absoluteHeight="0dp"
tools:layout_conversion_absoluteWidth="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
<Space <Space
android:id="@+id/searchReplacement" android:id="@+id/searchReplacement"

View file

@ -69,8 +69,7 @@
android:textAppearance="@android:style/TextAppearance.DeviceDefault" android:textAppearance="@android:style/TextAppearance.DeviceDefault"
android:textColor="#F3F3F3" android:textColor="#F3F3F3"
android:textSize="28sp" android:textSize="28sp"
android:visibility="visible" android:visibility="visible" />
app:drawableLeftCompat="@drawable/ic_work_app" />
<LinearLayout <LinearLayout
android:id="@+id/actionMenu" android:id="@+id/actionMenu"

View file

@ -32,6 +32,12 @@
app:key="appSpacing" app:key="appSpacing"
app:title="App Spacing" app:title="App Spacing"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<SwitchPreference
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:defaultValue="false"
android:title="Contacts Menu"
app:key="contactsEnabled" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory