Merge pull request #999 from Merkost/contacts_grid

Contacts favourites grid view
This commit is contained in:
Tibor Kaputa 2023-07-24 11:02:49 +02:00 committed by GitHub
commit baa11dfab2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 328 additions and 122 deletions

View File

@ -1,7 +1,9 @@
apply plugin: 'com.android.application' plugins {
apply plugin: 'kotlin-android' id 'com.android.application'
apply plugin: 'kotlin-android-extensions' id 'kotlin-android'
apply plugin: 'kotlin-kapt' id 'kotlin-android-extensions'
id 'kotlin-kapt'
}
def keystorePropertiesFile = rootProject.file("keystore.properties") def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties() def keystoreProperties = new Properties()
@ -63,7 +65,7 @@ android {
} }
dependencies { dependencies {
implementation 'com.github.SimpleMobileTools:Simple-Commons:35d685c042' implementation 'com.github.SimpleMobileTools:Simple-Commons:91763fe00f'
implementation 'com.googlecode.ez-vcard:ez-vcard:0.11.3' implementation 'com.googlecode.ez-vcard:ez-vcard:0.11.3'
implementation 'com.github.tibbi:IndicatorFastScroll:4524cd0b61' implementation 'com.github.tibbi:IndicatorFastScroll:4524cd0b61'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

View File

@ -10,16 +10,18 @@ import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.ContactsHelper import com.simplemobiletools.commons.helpers.ContactsHelper
import com.simplemobiletools.commons.helpers.NavigationIcon import com.simplemobiletools.commons.helpers.NavigationIcon
import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.commons.models.contacts.Contact
import com.simplemobiletools.commons.models.contacts.Group
import com.simplemobiletools.contacts.pro.R import com.simplemobiletools.contacts.pro.R
import com.simplemobiletools.contacts.pro.adapters.ContactsAdapter import com.simplemobiletools.contacts.pro.adapters.ContactsAdapter
import com.simplemobiletools.contacts.pro.dialogs.SelectContactsDialog import com.simplemobiletools.contacts.pro.dialogs.SelectContactsDialog
import com.simplemobiletools.contacts.pro.extensions.* import com.simplemobiletools.contacts.pro.extensions.handleGenericContactClick
import com.simplemobiletools.contacts.pro.helpers.GROUP import com.simplemobiletools.contacts.pro.helpers.GROUP
import com.simplemobiletools.contacts.pro.helpers.LOCATION_GROUP_CONTACTS import com.simplemobiletools.contacts.pro.helpers.LOCATION_GROUP_CONTACTS
import com.simplemobiletools.contacts.pro.interfaces.RefreshContactsListener import com.simplemobiletools.contacts.pro.interfaces.RefreshContactsListener
import com.simplemobiletools.contacts.pro.interfaces.RemoveFromGroupListener import com.simplemobiletools.contacts.pro.interfaces.RemoveFromGroupListener
import com.simplemobiletools.commons.models.contacts.*
import kotlinx.android.synthetic.main.activity_group_contacts.* import kotlinx.android.synthetic.main.activity_group_contacts.*
import kotlinx.android.synthetic.main.fragment_layout.fragment_list
class GroupContactsActivity : SimpleActivity(), RemoveFromGroupListener, RefreshContactsListener { class GroupContactsActivity : SimpleActivity(), RemoveFromGroupListener, RefreshContactsListener {
private var allContacts = ArrayList<Contact>() private var allContacts = ArrayList<Contact>()
@ -146,7 +148,14 @@ class GroupContactsActivity : SimpleActivity(), RemoveFromGroupListener, Refresh
private fun updateContacts(contacts: ArrayList<Contact>) { private fun updateContacts(contacts: ArrayList<Contact>) {
val currAdapter = group_contacts_list.adapter val currAdapter = group_contacts_list.adapter
if (currAdapter == null) { if (currAdapter == null) {
ContactsAdapter(this, contacts, this, LOCATION_GROUP_CONTACTS, this, group_contacts_list) { ContactsAdapter(
this,
contactItems = contacts,
recyclerView = fragment_list,
location = LOCATION_GROUP_CONTACTS,
removeListener = this,
refreshListener = this
) {
contactClicked(it as Contact) contactClicked(it as Contact)
}.apply { }.apply {
group_contacts_list.adapter = this group_contacts_list.adapter = this

View File

@ -15,11 +15,14 @@ import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
import com.simplemobiletools.commons.databases.ContactsDatabase import com.simplemobiletools.commons.databases.ContactsDatabase
import com.simplemobiletools.commons.dialogs.ChangeViewTypeDialog
import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.dialogs.FilePickerDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.models.FAQItem import com.simplemobiletools.commons.models.FAQItem
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.commons.models.Release import com.simplemobiletools.commons.models.Release
import com.simplemobiletools.commons.models.contacts.Contact import com.simplemobiletools.commons.models.contacts.Contact
import com.simplemobiletools.contacts.pro.BuildConfig import com.simplemobiletools.contacts.pro.BuildConfig
@ -172,9 +175,9 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData) super.onActivityResult(requestCode, resultCode, resultData)
if (requestCode == PICK_IMPORT_SOURCE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { if (requestCode == PICK_IMPORT_SOURCE_INTENT && resultCode == Activity.RESULT_OK && resultData?.data != null) {
tryImportContactsFromFile(resultData.data!!) tryImportContactsFromFile(resultData.data!!)
} else if (requestCode == PICK_EXPORT_FILE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { } else if (requestCode == PICK_EXPORT_FILE_INTENT && resultCode == Activity.RESULT_OK && resultData?.data != null) {
try { try {
val outputStream = contentResolver.openOutputStream(resultData.data!!) val outputStream = contentResolver.openOutputStream(resultData.data!!)
exportContactsTo(ignoredExportContactSources, outputStream) exportContactsTo(ignoredExportContactSources, outputStream)
@ -198,6 +201,8 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
findItem(R.id.sort).isVisible = currentFragment != groups_fragment findItem(R.id.sort).isVisible = currentFragment != groups_fragment
findItem(R.id.filter).isVisible = currentFragment != groups_fragment findItem(R.id.filter).isVisible = currentFragment != groups_fragment
findItem(R.id.dialpad).isVisible = !config.showDialpadButton findItem(R.id.dialpad).isVisible = !config.showDialpadButton
findItem(R.id.change_view_type).isVisible = currentFragment == favorites_fragment
findItem(R.id.column_count).isVisible = currentFragment == favorites_fragment && config.viewType == VIEW_TYPE_GRID
findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(R.bool.hide_google_relations) findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(R.bool.hide_google_relations)
} }
} }
@ -225,6 +230,8 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
R.id.import_contacts -> tryImportContacts() R.id.import_contacts -> tryImportContacts()
R.id.export_contacts -> tryExportContacts() R.id.export_contacts -> tryExportContacts()
R.id.more_apps_from_us -> launchMoreAppsFromUsIntent() R.id.more_apps_from_us -> launchMoreAppsFromUsIntent()
R.id.change_view_type -> changeViewType()
R.id.column_count -> changeColumnCount()
R.id.settings -> launchSettings() R.id.settings -> launchSettings()
R.id.about -> launchAbout() R.id.about -> launchAbout()
else -> return@setOnMenuItemClickListener false else -> return@setOnMenuItemClickListener false
@ -233,6 +240,29 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
} }
} }
private fun changeViewType() {
ChangeViewTypeDialog(this) {
refreshMenuItems()
favorites_fragment?.updateFavouritesAdapter()
}
}
private fun changeColumnCount() {
val items = ArrayList<RadioItem>()
for (i in 1..CONTACTS_GRID_MAX_COLUMNS_COUNT) {
items.add(RadioItem(i, resources.getQuantityString(R.plurals.column_counts, i, i)))
}
val currentColumnCount = config.contactsGridColumnCount
RadioGroupDialog(this, items, currentColumnCount) {
val newColumnCount = it as Int
if (currentColumnCount != newColumnCount) {
config.contactsGridColumnCount = newColumnCount
favorites_fragment?.columnCountChanged()
}
}
}
private fun updateMenuColors() { private fun updateMenuColors() {
updateStatusbarColor(getProperBackgroundColor()) updateStatusbarColor(getProperBackgroundColor())
main_menu.updateColors() main_menu.updateColors()

View File

@ -46,12 +46,13 @@ import java.util.*
class ContactsAdapter( class ContactsAdapter(
activity: SimpleActivity, activity: SimpleActivity,
var contactItems: ArrayList<Contact>, var contactItems: MutableList<Contact>,
recyclerView: MyRecyclerView,
highlightText: String = "",
var viewType: Int = VIEW_TYPE_LIST,
private val refreshListener: RefreshContactsListener?, private val refreshListener: RefreshContactsListener?,
private val location: Int, private val location: Int,
private val removeListener: RemoveFromGroupListener?, private val removeListener: RemoveFromGroupListener?,
recyclerView: MyRecyclerView,
highlightText: String = "",
private val enableDrag: Boolean = false, private val enableDrag: Boolean = false,
itemClick: (Any) -> Unit itemClick: (Any) -> Unit
) : MyRecyclerViewAdapter(activity, recyclerView, itemClick), RecyclerViewFastScroller.OnPopupTextUpdate, ItemTouchHelperContract { ) : MyRecyclerViewAdapter(activity, recyclerView, itemClick), RecyclerViewFastScroller.OnPopupTextUpdate, ItemTouchHelperContract {
@ -67,7 +68,6 @@ class ContactsAdapter(
var fontSize = activity.getTextSize() var fontSize = activity.getTextSize()
var onDragEndListener: (() -> Unit)? = null var onDragEndListener: (() -> Unit)? = null
private val itemLayout = if (showPhoneNumbers) R.layout.item_contact_with_number else R.layout.item_contact_without_number
private var touchHelper: ItemTouchHelper? = null private var touchHelper: ItemTouchHelper? = null
private var startReorderDragListener: StartReorderDragListener? = null private var startReorderDragListener: StartReorderDragListener? = null
@ -75,7 +75,7 @@ class ContactsAdapter(
setupDragListener(true) setupDragListener(true)
if (enableDrag) { if (enableDrag) {
touchHelper = ItemTouchHelper(ItemMoveCallback(this)) touchHelper = ItemTouchHelper(ItemMoveCallback(this, viewType == VIEW_TYPE_GRID))
touchHelper!!.attachToRecyclerView(recyclerView) touchHelper!!.attachToRecyclerView(recyclerView)
startReorderDragListener = object : StartReorderDragListener { startReorderDragListener = object : StartReorderDragListener {
@ -143,7 +143,21 @@ class ContactsAdapter(
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(itemLayout, parent) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layout = when (viewType) {
VIEW_TYPE_GRID -> {
if (showPhoneNumbers) R.layout.item_contact_with_number_grid else R.layout.item_contact_without_number_grid
}
else -> {
if (showPhoneNumbers) R.layout.item_contact_with_number else R.layout.item_contact_without_number
}
}
return createViewHolder(layout, parent)
}
override fun getItemViewType(position: Int): Int {
return viewType
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val contact = contactItems[position] val contact = contactItems[position]
@ -158,9 +172,9 @@ class ContactsAdapter(
private fun getItemWithKey(key: Int): Contact? = contactItems.firstOrNull { it.id == key } private fun getItemWithKey(key: Int): Contact? = contactItems.firstOrNull { it.id == key }
fun updateItems(newItems: ArrayList<Contact>, highlightText: String = "") { fun updateItems(newItems: List<Contact>, highlightText: String = "") {
if (newItems.hashCode() != contactItems.hashCode()) { if (newItems.hashCode() != contactItems.hashCode()) {
contactItems = newItems.clone() as ArrayList<Contact> contactItems = newItems.toMutableList()
textToHighlight = highlightText textToHighlight = highlightText
notifyDataSetChanged() notifyDataSetChanged()
finishActMode() finishActMode()

View File

@ -3,10 +3,18 @@ package com.simplemobiletools.contacts.pro.fragments
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.AttributeSet import android.util.AttributeSet
import com.simplemobiletools.commons.extensions.areSystemAnimationsEnabled
import com.simplemobiletools.commons.extensions.hideKeyboard import com.simplemobiletools.commons.extensions.hideKeyboard
import com.simplemobiletools.commons.models.contacts.Contact
import com.simplemobiletools.contacts.pro.activities.EditContactActivity import com.simplemobiletools.contacts.pro.activities.EditContactActivity
import com.simplemobiletools.contacts.pro.activities.InsertOrEditContactActivity import com.simplemobiletools.contacts.pro.activities.InsertOrEditContactActivity
import com.simplemobiletools.contacts.pro.activities.MainActivity import com.simplemobiletools.contacts.pro.activities.MainActivity
import com.simplemobiletools.contacts.pro.activities.SimpleActivity
import com.simplemobiletools.contacts.pro.adapters.ContactsAdapter
import com.simplemobiletools.contacts.pro.extensions.config
import com.simplemobiletools.contacts.pro.helpers.LOCATION_CONTACTS_TAB
import com.simplemobiletools.contacts.pro.interfaces.RefreshContactsListener
import kotlinx.android.synthetic.main.fragment_layout.view.fragment_list
class ContactsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet) { class ContactsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet) {
override fun fabClicked() { override fun fabClicked() {
@ -23,4 +31,39 @@ class ContactsFragment(context: Context, attributeSet: AttributeSet) : MyViewPag
(activity as InsertOrEditContactActivity).showFilterDialog() (activity as InsertOrEditContactActivity).showFilterDialog()
} }
} }
fun setupContactsAdapter(contacts: List<Contact>) {
setupViewVisibility(contacts.isNotEmpty())
val currAdapter = fragment_list.adapter
if (currAdapter == null || forceListRedraw) {
forceListRedraw = false
val location = LOCATION_CONTACTS_TAB
ContactsAdapter(
activity = activity as SimpleActivity,
contactItems = contacts.toMutableList(),
refreshListener = activity as RefreshContactsListener,
location = location,
removeListener = null,
recyclerView = fragment_list,
enableDrag = false,
) {
(activity as RefreshContactsListener).contactClicked(it as Contact)
}.apply {
fragment_list.adapter = this
}
if (context.areSystemAnimationsEnabled) {
fragment_list.scheduleLayoutAnimation()
}
} else {
(currAdapter as ContactsAdapter).apply {
startNameWithSurname = context.config.startNameWithSurname
showPhoneNumbers = context.config.showPhoneNumbers
showContactThumbnails = context.config.showContactThumbnails
updateItems(contacts)
}
}
}
} }

View File

@ -2,13 +2,33 @@ package com.simplemobiletools.contacts.pro.fragments
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import com.google.gson.Gson
import com.simplemobiletools.commons.extensions.areSystemAnimationsEnabled
import com.simplemobiletools.commons.extensions.beGone
import com.simplemobiletools.commons.extensions.beVisible
import com.simplemobiletools.commons.helpers.CONTACTS_GRID_MAX_COLUMNS_COUNT
import com.simplemobiletools.commons.helpers.ContactsHelper import com.simplemobiletools.commons.helpers.ContactsHelper
import com.simplemobiletools.commons.helpers.TAB_FAVORITES import com.simplemobiletools.commons.helpers.TAB_FAVORITES
import com.simplemobiletools.commons.helpers.VIEW_TYPE_GRID
import com.simplemobiletools.commons.models.contacts.Contact
import com.simplemobiletools.commons.views.MyGridLayoutManager
import com.simplemobiletools.commons.views.MyLinearLayoutManager
import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.contacts.pro.activities.MainActivity import com.simplemobiletools.contacts.pro.activities.MainActivity
import com.simplemobiletools.contacts.pro.activities.SimpleActivity import com.simplemobiletools.contacts.pro.activities.SimpleActivity
import com.simplemobiletools.contacts.pro.adapters.ContactsAdapter
import com.simplemobiletools.contacts.pro.dialogs.SelectContactsDialog import com.simplemobiletools.contacts.pro.dialogs.SelectContactsDialog
import com.simplemobiletools.contacts.pro.extensions.config
import com.simplemobiletools.contacts.pro.helpers.LOCATION_FAVORITES_TAB
import com.simplemobiletools.contacts.pro.interfaces.RefreshContactsListener
import kotlinx.android.synthetic.main.dialog_select_contact.view.letter_fastscroller
import kotlinx.android.synthetic.main.fragment_favorites.view.favorites_fragment
import kotlinx.android.synthetic.main.fragment_layout.view.fragment_list
class FavoritesFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet) { class FavoritesFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet) {
private var favouriteContacts = listOf<Contact>()
private var zoomListener: MyRecyclerView.MyZoomListener? = null
override fun fabClicked() { override fun fabClicked() {
finishActMode() finishActMode()
showAddFavoritesDialog() showAddFavoritesDialog()
@ -18,6 +38,8 @@ class FavoritesFragment(context: Context, attributeSet: AttributeSet) : MyViewPa
showAddFavoritesDialog() showAddFavoritesDialog()
} }
private fun getRecyclerAdapter() = fragment_list.adapter as? ContactsAdapter
private fun showAddFavoritesDialog() { private fun showAddFavoritesDialog() {
SelectContactsDialog(activity!!, allContacts, true, false) { addedContacts, removedContacts -> SelectContactsDialog(activity!!, allContacts, true, false) { addedContacts, removedContacts ->
ContactsHelper(activity as SimpleActivity).apply { ContactsHelper(activity as SimpleActivity).apply {
@ -28,4 +50,124 @@ class FavoritesFragment(context: Context, attributeSet: AttributeSet) : MyViewPa
(activity as? MainActivity)?.refreshContacts(TAB_FAVORITES) (activity as? MainActivity)?.refreshContacts(TAB_FAVORITES)
} }
} }
fun setupContactsFavoritesAdapter(contacts: List<Contact>) {
favouriteContacts = contacts
setupViewVisibility(favouriteContacts.isNotEmpty())
val currAdapter = getRecyclerAdapter()
val viewType = context.config.viewType
setFavoritesViewType(viewType)
initZoomListener(viewType)
if (currAdapter == null || forceListRedraw) {
forceListRedraw = false
val location = LOCATION_FAVORITES_TAB
ContactsAdapter(
activity = activity as SimpleActivity,
contactItems = favouriteContacts.toMutableList(),
refreshListener = activity as RefreshContactsListener,
location = location,
viewType = viewType,
removeListener = null,
recyclerView = fragment_list,
enableDrag = true,
) {
(activity as RefreshContactsListener).contactClicked(it as Contact)
}.apply {
fragment_list.adapter = this
setupZoomListener(zoomListener)
onDragEndListener = {
val adapter = fragment_list?.adapter
if (adapter is ContactsAdapter) {
val items = adapter.contactItems
saveCustomOrderToPrefs(items)
setupLetterFastscroller(items)
}
}
}
if (context.areSystemAnimationsEnabled) {
fragment_list.scheduleLayoutAnimation()
}
} else {
currAdapter.apply {
startNameWithSurname = context.config.startNameWithSurname
showPhoneNumbers = context.config.showPhoneNumbers
showContactThumbnails = context.config.showContactThumbnails
this.viewType = viewType
updateItems(favouriteContacts)
}
}
}
fun updateFavouritesAdapter() {
setupContactsFavoritesAdapter(favouriteContacts)
}
private fun setFavoritesViewType(viewType: Int) {
val spanCount = context.config.contactsGridColumnCount
if (viewType == VIEW_TYPE_GRID) {
favorites_fragment.letter_fastscroller.beGone()
fragment_list.layoutManager = MyGridLayoutManager(context, spanCount)
} else {
favorites_fragment.letter_fastscroller.beVisible()
fragment_list.layoutManager = MyLinearLayoutManager(context)
}
}
private fun initZoomListener(viewType: Int) {
if (viewType == VIEW_TYPE_GRID) {
val layoutManager = fragment_list.layoutManager as MyGridLayoutManager
zoomListener = object : MyRecyclerView.MyZoomListener {
override fun zoomIn() {
if (layoutManager.spanCount > 1) {
reduceColumnCount()
getRecyclerAdapter()?.finishActMode()
}
}
override fun zoomOut() {
if (layoutManager.spanCount < CONTACTS_GRID_MAX_COLUMNS_COUNT) {
increaseColumnCount()
getRecyclerAdapter()?.finishActMode()
}
}
}
} else {
zoomListener = null
}
}
private fun increaseColumnCount() {
if (context.config.viewType == VIEW_TYPE_GRID) {
context!!.config.contactsGridColumnCount += 1
columnCountChanged()
}
}
private fun reduceColumnCount() {
if (context.config.viewType == VIEW_TYPE_GRID) {
context!!.config.contactsGridColumnCount -= 1
columnCountChanged()
}
}
fun columnCountChanged() {
(fragment_list.layoutManager as? MyGridLayoutManager)?.spanCount = context!!.config.contactsGridColumnCount
getRecyclerAdapter()?.apply {
notifyItemRangeChanged(0, favouriteContacts.size)
}
}
private fun saveCustomOrderToPrefs(items: List<Contact>) {
activity?.apply {
val orderIds = items.map { it.id }
val orderGsonString = Gson().toJson(orderIds)
config.favoritesContactsOrder = orderGsonString
}
}
} }

View File

@ -5,11 +5,12 @@ import android.content.Intent
import android.util.AttributeSet import android.util.AttributeSet
import android.view.ViewGroup import android.view.ViewGroup
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.gson.Gson
import com.reddit.indicatorfastscroll.FastScrollItemIndicator import com.reddit.indicatorfastscroll.FastScrollItemIndicator
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.models.contacts.Contact
import com.simplemobiletools.commons.models.contacts.Group
import com.simplemobiletools.contacts.pro.R import com.simplemobiletools.contacts.pro.R
import com.simplemobiletools.contacts.pro.activities.GroupContactsActivity import com.simplemobiletools.contacts.pro.activities.GroupContactsActivity
import com.simplemobiletools.contacts.pro.activities.InsertOrEditContactActivity import com.simplemobiletools.contacts.pro.activities.InsertOrEditContactActivity
@ -17,27 +18,26 @@ import com.simplemobiletools.contacts.pro.activities.MainActivity
import com.simplemobiletools.contacts.pro.activities.SimpleActivity import com.simplemobiletools.contacts.pro.activities.SimpleActivity
import com.simplemobiletools.contacts.pro.adapters.ContactsAdapter import com.simplemobiletools.contacts.pro.adapters.ContactsAdapter
import com.simplemobiletools.contacts.pro.adapters.GroupsAdapter import com.simplemobiletools.contacts.pro.adapters.GroupsAdapter
import com.simplemobiletools.commons.helpers.Converters
import com.simplemobiletools.contacts.pro.helpers.*
import com.simplemobiletools.contacts.pro.interfaces.RefreshContactsListener
import com.simplemobiletools.commons.models.contacts.*
import com.simplemobiletools.contacts.pro.extensions.config import com.simplemobiletools.contacts.pro.extensions.config
import com.simplemobiletools.contacts.pro.helpers.AVOID_CHANGING_TEXT_TAG
import com.simplemobiletools.contacts.pro.helpers.AVOID_CHANGING_VISIBILITY_TAG
import com.simplemobiletools.contacts.pro.helpers.Config
import com.simplemobiletools.contacts.pro.helpers.GROUP
import com.simplemobiletools.contacts.pro.interfaces.RefreshContactsListener
import kotlinx.android.synthetic.main.dialog_select_contact.view.letter_fastscroller
import kotlinx.android.synthetic.main.fragment_contacts.view.contacts_fragment
import kotlinx.android.synthetic.main.fragment_favorites.view.favorites_fragment
import kotlinx.android.synthetic.main.fragment_layout.view.* import kotlinx.android.synthetic.main.fragment_layout.view.*
import kotlinx.android.synthetic.main.fragment_layout.view.fragment_fab import kotlinx.android.synthetic.main.fragment_letters_layout.view.letter_fastscroller_thumb
import kotlinx.android.synthetic.main.fragment_layout.view.fragment_list import java.util.Locale
import kotlinx.android.synthetic.main.fragment_layout.view.fragment_placeholder
import kotlinx.android.synthetic.main.fragment_layout.view.fragment_placeholder_2
import kotlinx.android.synthetic.main.fragment_layout.view.fragment_wrapper
import kotlinx.android.synthetic.main.fragment_letters_layout.view.*
import java.util.*
abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet) : CoordinatorLayout(context, attributeSet) { abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet) : CoordinatorLayout(context, attributeSet) {
protected var activity: SimpleActivity? = null protected var activity: SimpleActivity? = null
protected var allContacts = ArrayList<Contact>() protected var allContacts = ArrayList<Contact>()
private var lastHashCode = 0 private var lastHashCode = 0
private var contactsIgnoringSearch = ArrayList<Contact>() private var contactsIgnoringSearch = listOf<Contact>()
private var groupsIgnoringSearch = ArrayList<Group>() private var groupsIgnoringSearch = listOf<Group>()
private lateinit var config: Config private lateinit var config: Config
var skipHashComparing = false var skipHashComparing = false
@ -62,11 +62,13 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
this is ContactsFragment -> { this is ContactsFragment -> {
fragment_fab.contentDescription = activity.getString(R.string.create_new_contact) fragment_fab.contentDescription = activity.getString(R.string.create_new_contact)
} }
this is FavoritesFragment -> { this is FavoritesFragment -> {
fragment_placeholder.text = activity.getString(R.string.no_favorites) fragment_placeholder.text = activity.getString(R.string.no_favorites)
fragment_placeholder_2.text = activity.getString(R.string.add_favorites) fragment_placeholder_2.text = activity.getString(R.string.add_favorites)
fragment_fab.contentDescription = activity.getString(R.string.add_favorites) fragment_fab.contentDescription = activity.getString(R.string.add_favorites)
} }
this is GroupsFragment -> { this is GroupsFragment -> {
fragment_placeholder.text = activity.getString(R.string.no_group_created) fragment_placeholder.text = activity.getString(R.string.no_group_created)
fragment_placeholder_2.text = activity.getString(R.string.create_group) fragment_placeholder_2.text = activity.getString(R.string.create_group)
@ -113,26 +115,26 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
} }
if (config.lastUsedContactSource.isEmpty()) { if (config.lastUsedContactSource.isEmpty()) {
val grouped = contacts.asSequence().groupBy { it.source }.maxWithOrNull(compareBy { it.value.size }) val grouped = contacts.groupBy { it.source }.maxWithOrNull(compareBy { it.value.size })
config.lastUsedContactSource = grouped?.key ?: "" config.lastUsedContactSource = grouped?.key ?: ""
} }
allContacts = contacts allContacts = contacts
val filtered = when (this) {
val filtered = when { is GroupsFragment -> contacts
this is GroupsFragment -> contacts is FavoritesFragment -> {
this is FavoritesFragment -> { val favouriteContacts = contacts.filter { it.starred == 1 }
val favorites = contacts.filter { it.starred == 1 } as ArrayList<Contact>
if (activity!!.config.isCustomOrderSelected) { if (activity!!.config.isCustomOrderSelected) {
sortByCustomOrder(favorites) sortFavourites(favouriteContacts)
} else { } else {
favorites favouriteContacts
} }
} }
else -> { else -> {
val contactSources = activity!!.getVisibleContactSources() val contactSources = activity!!.getVisibleContactSources()
contacts.filter { contactSources.contains(it.source) } as ArrayList<Contact> contacts.filter { contactSources.contains(it.source) }
} }
} }
@ -141,7 +143,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
currentHash += it.getHashWithoutPrivatePhoto() currentHash += it.getHashWithoutPrivatePhoto()
} }
if (currentHash != lastHashCode || skipHashComparing || filtered.size == 0) { if (currentHash != lastHashCode || skipHashComparing || filtered.isEmpty()) {
skipHashComparing = false skipHashComparing = false
lastHashCode = currentHash lastHashCode = currentHash
activity?.runOnUiThread { activity?.runOnUiThread {
@ -157,34 +159,45 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
} }
} }
private fun sortByCustomOrder(starred: List<Contact>): ArrayList<Contact> { private fun sortFavourites(contacts: List<Contact>): List<Contact> {
val favoritesOrder = activity!!.config.favoritesContactsOrder val favoritesOrder = activity?.config?.favoritesContactsOrder
if (favoritesOrder.isNullOrEmpty()) {
if (favoritesOrder.isEmpty()) { return contacts
return ArrayList(starred)
} }
val orderList = Converters().jsonToStringList(favoritesOrder) val orderList = Converters().jsonToStringList(favoritesOrder)
val map = orderList.withIndex().associate { it.value to it.index } val map = orderList.withIndex().associate { it.value to it.index }
val sorted = starred.sortedBy { map[it.id.toString()] }
return ArrayList(sorted) return contacts.sortedBy { contact ->
} map[contact.id.toString()]
private fun setupContacts(contacts: ArrayList<Contact>) {
if (this is GroupsFragment) {
setupGroupsAdapter(contacts) {
groupsIgnoringSearch = (fragment_list?.adapter as? GroupsAdapter)?.groups ?: ArrayList()
}
} else {
setupContactsFavoritesAdapter(contacts)
contactsIgnoringSearch = (fragment_list?.adapter as? ContactsAdapter)?.contactItems ?: ArrayList()
setupLetterFastscroller(contacts)
letter_fastscroller_thumb.setupWithFastScroller(letter_fastscroller)
} }
} }
private fun setupGroupsAdapter(contacts: ArrayList<Contact>, callback: () -> Unit) { private fun setupContacts(contacts: List<Contact>) {
when (this) {
is GroupsFragment -> {
setupGroupsAdapter(contacts) {
groupsIgnoringSearch = (fragment_list?.adapter as? GroupsAdapter)?.groups ?: ArrayList()
}
}
is FavoritesFragment -> {
favorites_fragment.setupContactsFavoritesAdapter(contacts)
contactsIgnoringSearch = (fragment_list?.adapter as? ContactsAdapter)?.contactItems ?: listOf()
setupLetterFastscroller(contacts)
letter_fastscroller_thumb.setupWithFastScroller(letter_fastscroller)
}
else -> {
contacts_fragment.setupContactsAdapter(contacts)
contactsIgnoringSearch = (fragment_list?.adapter as? ContactsAdapter)?.contactItems ?: ArrayList()
setupLetterFastscroller(contacts)
letter_fastscroller_thumb.setupWithFastScroller(letter_fastscroller)
}
}
}
private fun setupGroupsAdapter(contacts: List<Contact>, callback: () -> Unit) {
ContactsHelper(activity!!).getStoredGroups { ContactsHelper(activity!!).getStoredGroups {
var storedGroups = it var storedGroups = it
contacts.forEach { contacts.forEach {
@ -227,63 +240,6 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
} }
} }
private fun setupContactsFavoritesAdapter(contacts: ArrayList<Contact>) {
setupViewVisibility(contacts.isNotEmpty())
val currAdapter = fragment_list.adapter
if (currAdapter == null || forceListRedraw) {
forceListRedraw = false
val location = when {
activity is InsertOrEditContactActivity -> LOCATION_INSERT_OR_EDIT
this is FavoritesFragment -> LOCATION_FAVORITES_TAB
else -> LOCATION_CONTACTS_TAB
}
val enableDragReorder = this is FavoritesFragment
ContactsAdapter(
activity = activity as SimpleActivity,
contactItems = contacts,
refreshListener = activity as RefreshContactsListener,
location = location,
removeListener = null,
recyclerView = fragment_list,
enableDrag = enableDragReorder,
) {
(activity as RefreshContactsListener).contactClicked(it as Contact)
}.apply {
fragment_list.adapter = this
if (enableDragReorder) {
onDragEndListener = {
val adapter = fragment_list?.adapter
if (adapter is ContactsAdapter) {
val items = adapter.contactItems
saveCustomOrderToPrefs(items)
setupLetterFastscroller(items)
}
}
}
}
if (context.areSystemAnimationsEnabled) {
fragment_list.scheduleLayoutAnimation()
}
} else {
(currAdapter as ContactsAdapter).apply {
startNameWithSurname = config.startNameWithSurname
showPhoneNumbers = config.showPhoneNumbers
showContactThumbnails = config.showContactThumbnails
updateItems(contacts)
}
}
}
private fun saveCustomOrderToPrefs(items: ArrayList<Contact>) {
activity?.apply {
val orderIds = items.map { it.id }
val orderGsonString = Gson().toJson(orderIds)
config.favoritesContactsOrder = orderGsonString
}
}
fun showContactThumbnailsChanged(showThumbnails: Boolean) { fun showContactThumbnailsChanged(showThumbnails: Boolean) {
if (this is GroupsFragment) { if (this is GroupsFragment) {
(fragment_list.adapter as? GroupsAdapter)?.apply { (fragment_list.adapter as? GroupsAdapter)?.apply {
@ -298,7 +254,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
} }
} }
private fun setupLetterFastscroller(contacts: ArrayList<Contact>) { fun setupLetterFastscroller(contacts: List<Contact>) {
val sorting = context.config.sorting val sorting = context.config.sorting
letter_fastscroller.setupWithRecyclerView(fragment_list, { position -> letter_fastscroller.setupWithRecyclerView(fragment_list, { position ->
try { try {
@ -396,7 +352,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
setupLetterFastscroller(contactsIgnoringSearch) setupLetterFastscroller(contactsIgnoringSearch)
setupViewVisibility(contactsIgnoringSearch.isNotEmpty()) setupViewVisibility(contactsIgnoringSearch.isNotEmpty())
} else if (fragment_list.adapter is GroupsAdapter) { } else if (fragment_list.adapter is GroupsAdapter) {
(fragment_list.adapter as? GroupsAdapter)?.updateItems(groupsIgnoringSearch) (fragment_list.adapter as? GroupsAdapter)?.updateItems(ArrayList(groupsIgnoringSearch))
setupViewVisibility(groupsIgnoringSearch.isNotEmpty()) setupViewVisibility(groupsIgnoringSearch.isNotEmpty())
} }
@ -405,7 +361,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
} }
} }
private fun setupViewVisibility(hasItemsToShow: Boolean) { fun setupViewVisibility(hasItemsToShow: Boolean) {
if (fragment_placeholder_2.tag != AVOID_CHANGING_VISIBILITY_TAG) { if (fragment_placeholder_2.tag != AVOID_CHANGING_VISIBILITY_TAG) {
fragment_placeholder_2?.beVisibleIf(!hasItemsToShow) fragment_placeholder_2?.beVisibleIf(!hasItemsToShow)
} }

View File

@ -18,6 +18,16 @@
android:icon="@drawable/ic_dialpad_vector" android:icon="@drawable/ic_dialpad_vector"
android:title="@string/dialpad" android:title="@string/dialpad"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item
android:id="@+id/change_view_type"
android:icon="@drawable/ic_change_view_vector"
android:title="@string/change_view_type"
app:showAsAction="ifRoom" />
<item
android:id="@+id/column_count"
android:icon="@drawable/ic_column_count_vector"
android:title="@string/column_count"
app:showAsAction="ifRoom" />
<item <item
android:id="@+id/import_contacts" android:id="@+id/import_contacts"
android:showAsAction="never" android:showAsAction="never"