diff --git a/app/build.gradle b/app/build.gradle index 44f2954f..046184c9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -36,7 +36,7 @@ ext { } dependencies { - implementation 'com.simplemobiletools:commons:3.4.14' + implementation 'com.simplemobiletools:commons:3.4.15' implementation 'joda-time:joda-time:2.9.9' debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion" diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt index 80f93efe..845ce89e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt @@ -1,45 +1,43 @@ package com.simplemobiletools.contacts.activities import android.content.Intent -import android.graphics.Paint +import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Menu import android.view.MenuItem import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* -import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener import com.simplemobiletools.contacts.BuildConfig import com.simplemobiletools.contacts.R -import com.simplemobiletools.contacts.adapters.ContactsAdapter +import com.simplemobiletools.contacts.adapters.ViewPagerAdapter import com.simplemobiletools.contacts.dialogs.ChangeSortingDialog import com.simplemobiletools.contacts.dialogs.FilterContactSourcesDialog import com.simplemobiletools.contacts.extensions.config -import com.simplemobiletools.contacts.extensions.openContact -import com.simplemobiletools.contacts.extensions.tryStartCall -import com.simplemobiletools.contacts.helpers.ContactsHelper -import com.simplemobiletools.contacts.models.Contact +import com.simplemobiletools.contacts.extensions.onPageChanged +import com.simplemobiletools.contacts.extensions.onTabSelectionChanged import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.android.synthetic.main.fragment_contacts.* +import kotlinx.android.synthetic.main.fragment_favorites.* + +class MainActivity : SimpleActivity() { + private var isFirstResume = true -class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { private var storedUseEnglish = false private var storedTextColor = 0 private var storedBackgroundColor = 0 private var storedPrimaryColor = 0 private var storedStartNameWithSurname = false - private var isFirstResume = true - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) appLaunched() - contacts_fab.setOnClickListener { addNewContact() } handlePermission(PERMISSION_READ_CONTACTS) { if (it) { handlePermission(PERMISSION_WRITE_CONTACTS) { if (it) { - initContacts() + initFragments() } else { toast(R.string.no_contacts_permission) finish() @@ -50,7 +48,6 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { finish() } } - storeStateVariables() } @@ -61,37 +58,37 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { return } - if (storedTextColor != config.textColor) { - (contacts_list.adapter as ContactsAdapter).apply { - updateTextColor(config.textColor) - initDrawables() - } + val configTextColor = config.textColor + if (storedTextColor != configTextColor) { + val inactiveTabIndex = if (viewpager.currentItem == 0) 1 else 0 + main_tabs_holder.getTabAt(inactiveTabIndex)?.icon?.applyColorFilter(configTextColor) + contacts_fragment.textColorChanged(configTextColor) + favorites_fragment.textColorChanged(configTextColor) } - if (storedPrimaryColor != config.primaryColor) { - contacts_fastscroller.updatePrimaryColor() + val configBackgroundColor = config.backgroundColor + if (storedBackgroundColor != configBackgroundColor) { + main_tabs_holder.background = ColorDrawable(configBackgroundColor) } - if (storedStartNameWithSurname != config.startNameWithSurname) { - (contacts_list.adapter as ContactsAdapter).apply { - startNameWithSurname = config.startNameWithSurname - config.sorting = if (config.startNameWithSurname) SORT_BY_SURNAME else SORT_BY_FIRST_NAME - initContacts() - } + val configPrimaryColor = config.primaryColor + if (storedPrimaryColor != configPrimaryColor) { + main_tabs_holder.setSelectedTabIndicatorColor(getAdjustedPrimaryColor()) + main_tabs_holder.getTabAt(viewpager.currentItem)?.icon?.applyColorFilter(getAdjustedPrimaryColor()) + contacts_fragment.primaryColorChanged(configPrimaryColor) + favorites_fragment.primaryColorChanged(configPrimaryColor) } - contacts_fastscroller.updateBubbleColors() - contacts_fastscroller.allowBubbleDisplay = config.showInfoBubble - updateTextColors(contacts_holder) - - contacts_placeholder_2.paintFlags = contacts_placeholder_2.paintFlags or Paint.UNDERLINE_TEXT_FLAG - contacts_placeholder_2.setTextColor(config.primaryColor) - contacts_placeholder_2.setOnClickListener { - showFilterDialog() + val configStartNameWithSurname = config.startNameWithSurname + if (storedStartNameWithSurname != configStartNameWithSurname) { + contacts_fragment.startNameWithSurnameChanged(configStartNameWithSurname) + favorites_fragment.startNameWithSurnameChanged(configStartNameWithSurname) } if (!isFirstResume) { - initContacts() + contacts_fragment.initContacts() + contacts_fragment.onActivityResume() + favorites_fragment.onActivityResume() } isFirstResume = false } @@ -117,22 +114,6 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { return true } - private fun showSortingDialog() { - ChangeSortingDialog(this) { - initContacts() - } - } - - private fun showFilterDialog() { - FilterContactSourcesDialog(this) { - initContacts() - } - } - - private fun launchAbout() { - startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_MULTISELECT or LICENSE_JODA or LICENSE_GLIDE, BuildConfig.VERSION_NAME) - } - private fun storeStateVariables() { config.apply { storedUseEnglish = useEnglish @@ -143,63 +124,44 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { } } - private fun initContacts() { - ContactsHelper(this).getContacts { - if (config.lastUsedContactSource.isEmpty()) { - val grouped = it.groupBy { it.source }.maxWith(compareBy { it.value.size }) - config.lastUsedContactSource = grouped?.key ?: "" - } + private fun initFragments() { + viewpager.adapter = ViewPagerAdapter(this) + viewpager.onPageChanged { + main_tabs_holder.getTabAt(it)?.select() + invalidateOptionsMenu() + } - Contact.sorting = config.sorting - it.sort() + main_tabs_holder.apply { + background = ColorDrawable(config.backgroundColor) + setSelectedTabIndicatorColor(getAdjustedPrimaryColor()) + getTabAt(0)?.icon?.applyColorFilter(getAdjustedPrimaryColor()) + getTabAt(1)?.icon?.applyColorFilter(config.textColor) + } - if (it.hashCode() != (contacts_list.adapter as? ContactsAdapter)?.contactItems?.hashCode()) { - runOnUiThread { - setupContacts(it) + main_tabs_holder.onTabSelectionChanged( + tabUnselectedAction = { + it.icon?.applyColorFilter(config.textColor) + }, + tabSelectedAction = { + viewpager.currentItem = it.position + it.icon?.applyColorFilter(getAdjustedPrimaryColor()) } - } + ) + } + + private fun showSortingDialog() { + ChangeSortingDialog(this) { + contacts_fragment.initContacts() } } - private fun setupContacts(contacts: ArrayList) { - contacts_placeholder_2.beVisibleIf(contacts.isEmpty()) - contacts_placeholder.beVisibleIf(contacts.isEmpty()) - - val currAdapter = contacts_list.adapter - if (currAdapter == null) { - ContactsAdapter(this, contacts, this, contacts_list) { - if (config.callContact) { - val contact = it as Contact - if (contact.phoneNumbers.isNotEmpty()) { - tryStartCall(it) - } else { - toast(R.string.no_phone_number_found) - } - } else { - openContact(it as Contact) - } - }.apply { - setupDragListener(true) - addVerticalDividers(true) - contacts_list.adapter = this - } - - contacts_fastscroller.setViews(contacts_list) { - val item = (contacts_list.adapter as ContactsAdapter).contactItems.getOrNull(it) - contacts_fastscroller.updateBubbleText(item?.getBubbleText() ?: "") - } - } else { - (currAdapter as ContactsAdapter).updateItems(contacts) + fun showFilterDialog() { + FilterContactSourcesDialog(this) { + contacts_fragment.initContacts() } } - private fun addNewContact() { - Intent(applicationContext, ContactActivity::class.java).apply { - startActivity(this) - } - } - - override fun refreshItems() { - initContacts() + private fun launchAbout() { + startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_MULTISELECT or LICENSE_JODA or LICENSE_GLIDE, BuildConfig.VERSION_NAME) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ViewPagerAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ViewPagerAdapter.kt new file mode 100644 index 00000000..bed555b9 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ViewPagerAdapter.kt @@ -0,0 +1,26 @@ +package com.simplemobiletools.contacts.adapters + +import android.support.v4.view.PagerAdapter +import android.view.View +import android.view.ViewGroup +import com.simplemobiletools.contacts.R +import com.simplemobiletools.contacts.activities.MainActivity +import com.simplemobiletools.contacts.fragments.MyViewPagerFragment + +class ViewPagerAdapter(val activity: MainActivity) : PagerAdapter() { + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val layout = if (position == 0) R.layout.fragment_contacts else R.layout.fragment_favorites + val view = activity.layoutInflater.inflate(layout, container, false) + container.addView(view) + (view as MyViewPagerFragment).setupFragment(activity) + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, item: Any) { + container.removeView(item as View) + } + + override fun getCount() = 2 + override fun isViewFromObject(view: View, item: Any) = view == item +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/TabLayout.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/TabLayout.kt new file mode 100644 index 00000000..f31bef05 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/TabLayout.kt @@ -0,0 +1,17 @@ +package com.simplemobiletools.contacts.extensions + +import android.support.design.widget.TabLayout + +fun TabLayout.onTabSelectionChanged(tabUnselectedAction: (inactiveTab: TabLayout.Tab) -> Unit, tabSelectedAction: (activeTab: TabLayout.Tab) -> Unit) = + setOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab) { + tabSelectedAction(tab) + } + + override fun onTabUnselected(tab: TabLayout.Tab) { + tabUnselectedAction(tab) + } + + override fun onTabReselected(tab: TabLayout.Tab) { + } + }) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/ViewPager.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/ViewPager.kt new file mode 100644 index 00000000..6ef7ba95 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/ViewPager.kt @@ -0,0 +1,16 @@ +package com.simplemobiletools.contacts.extensions + +import android.support.v4.view.ViewPager + +fun ViewPager.onPageChanged(pageChangedAction: (activePage: Int) -> Unit) = + addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageSelected(position: Int) { + pageChangedAction(position) + } + + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + } + + override fun onPageScrollStateChanged(state: Int) { + } + }) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/ContactsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/ContactsFragment.kt new file mode 100644 index 00000000..a3843f02 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/ContactsFragment.kt @@ -0,0 +1,147 @@ +package com.simplemobiletools.contacts.fragments + +import android.content.Context +import android.content.Intent +import android.graphics.Paint +import android.util.AttributeSet +import com.simplemobiletools.commons.extensions.beVisibleIf +import com.simplemobiletools.commons.extensions.isActivityDestroyed +import com.simplemobiletools.commons.extensions.toast +import com.simplemobiletools.commons.extensions.updateTextColors +import com.simplemobiletools.commons.helpers.SORT_BY_FIRST_NAME +import com.simplemobiletools.commons.helpers.SORT_BY_SURNAME +import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener +import com.simplemobiletools.contacts.R +import com.simplemobiletools.contacts.activities.ContactActivity +import com.simplemobiletools.contacts.activities.MainActivity +import com.simplemobiletools.contacts.activities.SimpleActivity +import com.simplemobiletools.contacts.adapters.ContactsAdapter +import com.simplemobiletools.contacts.extensions.openContact +import com.simplemobiletools.contacts.extensions.tryStartCall +import com.simplemobiletools.contacts.helpers.ContactsHelper +import com.simplemobiletools.contacts.models.Contact +import kotlinx.android.synthetic.main.fragment_contacts.view.* + +class ContactsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet), RefreshRecyclerViewListener { + var activity: MainActivity? = null + + override fun initFragment(activity: MainActivity) { + if (this.activity == null) { + this.activity = activity + contacts_fab.setOnClickListener { + addNewContact() + } + + contacts_placeholder_2.setOnClickListener { + activity.showFilterDialog() + } + + contacts_placeholder_2.paintFlags = contacts_placeholder_2.paintFlags or Paint.UNDERLINE_TEXT_FLAG + updateViewStuff() + } + + initContacts() + } + + override fun textColorChanged(color: Int) { + (contacts_list.adapter as ContactsAdapter).apply { + updateTextColor(color) + initDrawables() + } + } + + override fun primaryColorChanged(color: Int) { + contacts_fastscroller.updatePrimaryColor() + contacts_fab.setColors(config.textColor, color, config.backgroundColor) + contacts_fastscroller.updateBubblePrimaryColor() + } + + override fun startNameWithSurnameChanged(startNameWithSurname: Boolean) { + (contacts_list.adapter as ContactsAdapter).apply { + config.sorting = if (startNameWithSurname) SORT_BY_SURNAME else SORT_BY_FIRST_NAME + initContacts() + } + } + + override fun onActivityResume() { + updateViewStuff() + } + + private fun updateViewStuff() { + context.updateTextColors(contacts_fragment) + contacts_fastscroller.updateBubbleColors() + contacts_fastscroller.allowBubbleDisplay = config.showInfoBubble + contacts_placeholder_2.setTextColor(config.primaryColor) + } + + fun initContacts() { + if (activity == null || activity!!.isActivityDestroyed()) { + return + } + + ContactsHelper(activity!!).getContacts { + if (activity == null || activity!!.isActivityDestroyed()) { + return@getContacts + } + + if (config.lastUsedContactSource.isEmpty()) { + val grouped = it.groupBy { it.source }.maxWith(compareBy { it.value.size }) + config.lastUsedContactSource = grouped?.key ?: "" + } + + Contact.sorting = config.sorting + it.sort() + + if (it.hashCode() != (contacts_list.adapter as? ContactsAdapter)?.contactItems?.hashCode()) { + activity!!.runOnUiThread { + setupContacts(it) + } + } + } + } + + private fun setupContacts(contacts: ArrayList) { + contacts_placeholder_2.beVisibleIf(contacts.isEmpty()) + contacts_placeholder.beVisibleIf(contacts.isEmpty()) + + val currAdapter = contacts_list.adapter + if (currAdapter == null) { + ContactsAdapter(activity as SimpleActivity, contacts, this, contacts_list) { + if (config.callContact) { + val contact = it as Contact + if (contact.phoneNumbers.isNotEmpty()) { + (activity as SimpleActivity).tryStartCall(it) + } else { + activity!!.toast(R.string.no_phone_number_found) + } + } else { + context!!.openContact(it as Contact) + } + }.apply { + setupDragListener(true) + addVerticalDividers(true) + contacts_list.adapter = this + } + + contacts_fastscroller.setViews(contacts_list) { + val item = (contacts_list.adapter as ContactsAdapter).contactItems.getOrNull(it) + contacts_fastscroller.updateBubbleText(item?.getBubbleText() ?: "") + } + } else { + (currAdapter as ContactsAdapter).apply { + startNameWithSurname = config.startNameWithSurname + updateItems(contacts) + } + } + } + + private fun addNewContact() { + Intent(context, ContactActivity::class.java).apply { + context.startActivity(this) + } + } + + override fun refreshItems() { + initContacts() + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/FavoritesFragment.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/FavoritesFragment.kt new file mode 100644 index 00000000..f96d89d7 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/FavoritesFragment.kt @@ -0,0 +1,22 @@ +package com.simplemobiletools.contacts.fragments + +import android.content.Context +import android.util.AttributeSet +import com.simplemobiletools.contacts.activities.MainActivity + +class FavoritesFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet) { + override fun initFragment(activity: MainActivity) { + } + + override fun textColorChanged(color: Int) { + } + + override fun primaryColorChanged(color: Int) { + } + + override fun startNameWithSurnameChanged(startNameWithSurname: Boolean) { + } + + override fun onActivityResume() { + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt new file mode 100644 index 00000000..c19f3b9c --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt @@ -0,0 +1,27 @@ +package com.simplemobiletools.contacts.fragments + +import android.content.Context +import android.support.design.widget.CoordinatorLayout +import android.util.AttributeSet +import com.simplemobiletools.contacts.activities.MainActivity +import com.simplemobiletools.contacts.extensions.config +import com.simplemobiletools.contacts.helpers.Config + +abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet) : CoordinatorLayout(context, attributeSet) { + lateinit var config: Config + + fun setupFragment(activity: MainActivity) { + config = activity.config + initFragment(activity) + } + + abstract fun initFragment(activity: MainActivity) + + abstract fun textColorChanged(color: Int) + + abstract fun primaryColorChanged(color: Int) + + abstract fun startNameWithSurnameChanged(startNameWithSurname: Boolean) + + abstract fun onActivityResume() +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index eac2d7cc..23457c44 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,68 +1,41 @@ - + android:layout_height="match_parent" + tooLs:ignore="MissingPrefix"> - + android:layout_height="48dp" + app:elevation="6dp" + app:tabIndicatorColor="@android:color/white" + app:tabIndicatorHeight="2dp" + app:tabMinWidth="150dp" + app:tabSelectedTextColor="@android:color/white"> - - - - - - - + android:layout_height="wrap_content" + android:icon="@drawable/ic_person"/> - + - - + - + - + diff --git a/app/src/main/res/layout/fragment_contacts.xml b/app/src/main/res/layout/fragment_contacts.xml new file mode 100644 index 00000000..bf9f8cf6 --- /dev/null +++ b/app/src/main/res/layout/fragment_contacts.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_favorites.xml b/app/src/main/res/layout/fragment_favorites.xml new file mode 100644 index 00000000..2f0e4177 --- /dev/null +++ b/app/src/main/res/layout/fragment_favorites.xml @@ -0,0 +1,8 @@ + + + +