diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4f8ea65c..f9854e29 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,21 @@
Changelog
==========
+Version 4.0.1 *(2018-05-09)*
+----------------------------
+
+ * Fixed a glitch happening at updating from old app version to 4.x
+
+Version 4.0.0 *(2018-05-09)*
+----------------------------
+
+ * Allow changing app icon color
+ * Add a toggle for trying to filter out duplicate contacts, enabled by default
+ * Fix some contacts not being visible
+ * Allow opening contacts with third party apps
+ * Couple misc fixes related to contacts syncing via CardDAV
+ * Allow moving contacts in a different contact source at the Edit screen
+
Version 3.5.3 *(2018-04-18)*
----------------------------
diff --git a/app/build.gradle b/app/build.gradle
index bdd914c4..ca15f081 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -10,8 +10,8 @@ android {
applicationId "com.simplemobiletools.contacts"
minSdkVersion 16
targetSdkVersion 27
- versionCode 19
- versionName "3.5.3"
+ versionCode 21
+ versionName "4.0.1"
setProperty("archivesBaseName", "contacts")
}
@@ -45,7 +45,7 @@ ext {
}
dependencies {
- implementation 'com.simplemobiletools:commons:3.20.6'
+ implementation 'com.simplemobiletools:commons:4.0.0'
implementation 'joda-time:joda-time:2.9.9'
implementation 'com.facebook.stetho:stetho:1.5.0'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f8b1cd21..6d7fec68 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -210,6 +210,228 @@
android:icon="@mipmap/ic_launcher_red"
android:roundIcon="@mipmap/ic_launcher_red"
android:targetActivity=".activities.SplashActivity">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt
index 8b57dafd..a1c655a3 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt
@@ -52,6 +52,7 @@ class EditContactActivity : ContactActivity() {
private var lastPhotoIntentUri: Uri? = null
private var isSaving = false
private var isThirdPartyIntent = false
+ private var originalContactSource = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -212,6 +213,7 @@ class EditContactActivity : ContactActivity() {
contact_events_add_new.setOnClickListener { addNewEventField() }
contact_websites_add_new.setOnClickListener { addNewWebsiteField() }
contact_groups_add_new.setOnClickListener { showSelectGroupsDialog() }
+ contact_source.setOnClickListener { showSelectContactSourceDialog() }
setupFieldVisibility()
@@ -504,21 +506,16 @@ class EditContactActivity : ContactActivity() {
private fun setupContactSource() {
contact_source.text = getPublicContactSource(contact!!.source)
+ originalContactSource = contact!!.source
}
private fun setupNewContact() {
supportActionBar?.title = resources.getString(R.string.new_contact)
- val contactSource = if (hasContactPermissions()) config.lastUsedContactSource else SMT_PRIVATE
+ originalContactSource = if (hasContactPermissions()) config.lastUsedContactSource else SMT_PRIVATE
val organization = Organization("", "")
- contact = Contact(0, "", "", "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), contactSource, 0, 0, "", null, "",
+ contact = Contact(0, "", "", "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), originalContactSource, 0, 0, "", null, "",
ArrayList(), organization, ArrayList())
contact_source.text = getPublicContactSource(contact!!.source)
- contact_source.setOnClickListener {
- showContactSourcePicker(contact!!.source) {
- contact!!.source = if (it == getString(R.string.phone_storage_hidden)) SMT_PRIVATE else it
- contact_source.text = getPublicContactSource(it)
- }
- }
}
private fun setupTypePickers() {
@@ -708,6 +705,13 @@ class EditContactActivity : ContactActivity() {
}
}
+ private fun showSelectContactSourceDialog() {
+ showContactSourcePicker(contact!!.source) {
+ contact!!.source = if (it == getString(R.string.phone_storage_hidden)) SMT_PRIVATE else it
+ contact_source.text = getPublicContactSource(it)
+ }
+ }
+
private fun saveContact() {
if (isSaving || contact == null) {
return
@@ -726,7 +730,6 @@ class EditContactActivity : ContactActivity() {
emails = getFilledEmails()
addresses = getFilledAddresses()
events = getFilledEvents()
- source = contact!!.source
starred = if (isContactStarred()) 1 else 0
notes = contact_notes.value
websites = getFilledWebsites()
@@ -737,11 +740,13 @@ class EditContactActivity : ContactActivity() {
Thread {
config.lastUsedContactSource = source
- if (id == 0) {
- insertNewContact()
- } else {
- val photoUpdateStatus = getPhotoUpdateStatus(oldPhotoUri, photoUri)
- updateContact(photoUpdateStatus)
+ when {
+ id == 0 -> insertNewContact(false)
+ originalContactSource != source -> insertNewContact(true)
+ else -> {
+ val photoUpdateStatus = getPhotoUpdateStatus(oldPhotoUri, photoUri)
+ updateContact(photoUpdateStatus)
+ }
}
}.start()
}
@@ -821,10 +826,17 @@ class EditContactActivity : ContactActivity() {
return websites
}
- private fun insertNewContact() {
+ private fun insertNewContact(deleteCurrentContact: Boolean) {
isSaving = true
- toast(R.string.inserting)
+ if (!deleteCurrentContact) {
+ toast(R.string.inserting)
+ }
+
if (ContactsHelper(this@EditContactActivity).insertContact(contact!!)) {
+ if (deleteCurrentContact) {
+ contact!!.source = originalContactSource
+ ContactsHelper(this).deleteContact(contact!!)
+ }
finish()
} else {
toast(R.string.unknown_error_occurred)
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 03a277aa..90f0f9e4 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt
@@ -1,11 +1,15 @@
package com.simplemobiletools.contacts.activities
+import android.Manifest
import android.app.SearchManager
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Bundle
+import android.support.v4.app.ActivityCompat
+import android.support.v4.content.ContextCompat
import android.support.v4.view.MenuItemCompat
import android.support.v4.view.ViewPager
import android.support.v7.widget.SearchView
@@ -48,11 +52,12 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
private var storedShowContactThumbnails = false
private var storedShowPhoneNumbers = false
private var storedStartNameWithSurname = false
+ private var storedFilterDuplicates = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
- appLaunched()
+ appLaunched(BuildConfig.APPLICATION_ID)
setupTabColors()
// just get a reference to the database to make sure it is created properly
@@ -62,6 +67,12 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
werePermissionsHandled = true
if (it) {
handlePermission(PERMISSION_WRITE_CONTACTS) {
+ // workaround for upgrading from version 3.x to 4.x as we added a new permission from an already granted permissions group
+ val hasGetAccountsPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.GET_ACCOUNTS) == PackageManager.PERMISSION_GRANTED
+ if (!hasGetAccountsPermission) {
+ ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.GET_ACCOUNTS), 34)
+ }
+
storeLocalAccountData()
initFragments()
}
@@ -118,6 +129,10 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
favorites_fragment?.startNameWithSurnameChanged(configStartNameWithSurname)
}
+ if (storedFilterDuplicates != config.filterDuplicates) {
+ refreshContacts(ALL_TABS_MASK)
+ }
+
if (werePermissionsHandled && !isFirstResume) {
if (viewpager.adapter == null) {
initFragments()
@@ -175,6 +190,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
storedShowContactThumbnails = showContactThumbnails
storedShowPhoneNumbers = showPhoneNumbers
storedStartNameWithSurname = startNameWithSurname
+ storedFilterDuplicates = filterDuplicates
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SelectContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SelectContactActivity.kt
index bab426b8..0d592bd1 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SelectContactActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SelectContactActivity.kt
@@ -6,7 +6,6 @@ import android.os.Bundle
import android.provider.ContactsContract
import android.view.Menu
import android.view.MenuItem
-import com.simplemobiletools.commons.extensions.appLaunched
import com.simplemobiletools.commons.extensions.baseConfig
import com.simplemobiletools.commons.extensions.isActivityDestroyed
import com.simplemobiletools.commons.extensions.toast
@@ -18,6 +17,7 @@ import com.simplemobiletools.contacts.dialogs.ChangeSortingDialog
import com.simplemobiletools.contacts.dialogs.FilterContactSourcesDialog
import com.simplemobiletools.contacts.extensions.config
import com.simplemobiletools.contacts.extensions.getContactPublicUri
+import com.simplemobiletools.contacts.extensions.getVisibleContactSources
import com.simplemobiletools.contacts.helpers.ContactsHelper
import com.simplemobiletools.contacts.helpers.SMT_PRIVATE
import com.simplemobiletools.contacts.models.Contact
@@ -29,7 +29,6 @@ class SelectContactActivity : SimpleActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.layout_select_contact)
- appLaunched()
handlePermission(PERMISSION_READ_CONTACTS) {
if (it) {
@@ -98,7 +97,7 @@ class SelectContactActivity : SimpleActivity() {
}
} as ArrayList
- val contactSources = config.displayContactSources
+ val contactSources = getVisibleContactSources()
contacts = contacts.filter { contactSources.contains(it.source) } as ArrayList
Contact.sorting = config.sorting
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SettingsActivity.kt
index 9b76f9eb..1cf3bb24 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SettingsActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SettingsActivity.kt
@@ -31,6 +31,7 @@ class SettingsActivity : SimpleActivity() {
setupShowContactThumbnails()
setupShowPhoneNumbers()
setupStartNameWithSurname()
+ setupFilterDuplicates()
setupOnContactClick()
updateTextColors(settings_holder)
}
@@ -97,6 +98,14 @@ class SettingsActivity : SimpleActivity() {
}
}
+ private fun setupFilterDuplicates() {
+ settings_filter_duplicates.isChecked = config.filterDuplicates
+ settings_filter_duplicates_holder.setOnClickListener {
+ settings_filter_duplicates.toggle()
+ config.filterDuplicates = settings_filter_duplicates.isChecked
+ }
+ }
+
private fun setupOnContactClick() {
settings_on_contact_click.text = getOnContactClickText()
settings_on_contact_click_holder.setOnClickListener {
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SimpleActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SimpleActivity.kt
index 94e97fce..7ef01301 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SimpleActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SimpleActivity.kt
@@ -6,7 +6,24 @@ import com.simplemobiletools.contacts.R
open class SimpleActivity : BaseSimpleActivity() {
override fun getAppIconIDs() = arrayListOf(
R.mipmap.ic_launcher_red,
- R.mipmap.ic_launcher
+ R.mipmap.ic_launcher_pink,
+ R.mipmap.ic_launcher_purple,
+ R.mipmap.ic_launcher_deep_purple,
+ R.mipmap.ic_launcher_indigo,
+ R.mipmap.ic_launcher_blue,
+ R.mipmap.ic_launcher_light_blue,
+ R.mipmap.ic_launcher_cyan,
+ R.mipmap.ic_launcher_teal,
+ R.mipmap.ic_launcher_green,
+ R.mipmap.ic_launcher_light_green,
+ R.mipmap.ic_launcher_lime,
+ R.mipmap.ic_launcher_yellow,
+ R.mipmap.ic_launcher_amber,
+ R.mipmap.ic_launcher,
+ R.mipmap.ic_launcher_deep_orange,
+ R.mipmap.ic_launcher_brown,
+ R.mipmap.ic_launcher_blue_grey,
+ R.mipmap.ic_launcher_grey_black
)
override fun getAppLauncherName() = getString(R.string.app_launcher_name)
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt
index ca85d078..fd9db502 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt
@@ -125,6 +125,7 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList, private val displayContactSources: Set) :
+class FilterContactSourcesAdapter(val activity: SimpleActivity, private val contactSources: List, private val displayContactSources: ArrayList) :
RecyclerView.Adapter() {
private val itemViews = SparseArray()
private val selectedPositions = HashSet()
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/GroupsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/GroupsAdapter.kt
index 9869eca8..a556b00d 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/GroupsAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/GroupsAdapter.kt
@@ -77,6 +77,7 @@ class GroupsAdapter(activity: SimpleActivity, var groups: ArrayList, val
groups = newItems
notifyDataSetChanged()
finishActMode()
+ fastScroller?.measureRecyclerView()
}
private fun editGroup() {
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/SelectContactsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/SelectContactsAdapter.kt
index 59471c1b..df9d5fe8 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/SelectContactsAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/SelectContactsAdapter.kt
@@ -119,7 +119,9 @@ class SelectContactsAdapter(val activity: SimpleActivity, val contacts: List confirmEventTypes() })
.setNegativeButton(R.string.cancel, null)
.create().apply {
- activity.setupDialogStuff(view, this)
- }
+ activity.setupDialogStuff(view, this)
+ }
}
}
}
private fun confirmEventTypes() {
val selectedIndexes = (view.filter_contact_sources_list.adapter as FilterContactSourcesAdapter).getSelectedItemsSet()
- val selectedContactSources = HashSet()
- selectedIndexes.forEach {
- selectedContactSources.add(if (contactSources[it].type == SMT_PRIVATE) SMT_PRIVATE else contactSources[it].name)
+ val ignoredIndexes = ArrayList()
+ for (i in 0 until contactSources.size) {
+ if (!selectedIndexes.contains(i)) {
+ ignoredIndexes.add(i)
+ }
}
- if (activity.config.displayContactSources != selectedContactSources) {
- activity.config.displayContactSources = selectedContactSources
+ val ignoredContactSources = HashSet()
+ ignoredIndexes.forEach {
+ ignoredContactSources.add(if (contactSources[it].type == SMT_PRIVATE) SMT_PRIVATE else contactSources[it].name)
+ }
+
+ if (activity.getVisibleContactSources() != ignoredContactSources) {
+ activity.config.ignoredContactSources = ignoredContactSources
callback()
}
dialog?.dismiss()
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/SelectContactsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/SelectContactsDialog.kt
index eed613d0..76660338 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/SelectContactsDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/SelectContactsDialog.kt
@@ -7,6 +7,7 @@ import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.activities.SimpleActivity
import com.simplemobiletools.contacts.adapters.SelectContactsAdapter
import com.simplemobiletools.contacts.extensions.config
+import com.simplemobiletools.contacts.extensions.getVisibleContactSources
import com.simplemobiletools.contacts.models.Contact
import kotlinx.android.synthetic.main.layout_select_contact.view.*
@@ -18,7 +19,7 @@ class SelectContactsDialog(val activity: SimpleActivity, initialContacts: ArrayL
init {
var allContacts = initialContacts
if (selectContacts == null) {
- val contactSources = activity.config.displayContactSources
+ val contactSources = activity.getVisibleContactSources()
allContacts = allContacts.filter { contactSources.contains(it.source) } as ArrayList
initiallySelectedContacts = allContacts.filter { it.starred == 1 } as ArrayList
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Activity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Activity.kt
index e7b4eabb..7044edc6 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Activity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Activity.kt
@@ -1,5 +1,6 @@
package com.simplemobiletools.contacts.extensions
+import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.provider.ContactsContract
@@ -17,6 +18,7 @@ import com.simplemobiletools.contacts.helpers.ContactsHelper
import com.simplemobiletools.contacts.helpers.SMT_PRIVATE
import com.simplemobiletools.contacts.helpers.VcfExporter
import com.simplemobiletools.contacts.models.Contact
+import com.simplemobiletools.contacts.models.ContactSource
import java.io.File
fun SimpleActivity.startCallIntent(recipient: String) {
@@ -181,3 +183,11 @@ fun BaseSimpleActivity.getContactPublicUri(contact: Contact): Uri {
val lookupKey = ContactsHelper(this).getContactLookupKey(contact.id.toString())
return Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
}
+
+fun Activity.getVisibleContactSources(): ArrayList {
+ val sources = ContactsHelper(this).getDeviceContactSources()
+ sources.add(ContactSource(getString(R.string.phone_storage_hidden), SMT_PRIVATE))
+ val sourceNames = ArrayList(sources).map { if (it.type == SMT_PRIVATE) SMT_PRIVATE else it.name }.toMutableList() as ArrayList
+ sourceNames.removeAll(config.ignoredContactSources)
+ return sourceNames
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt
index ac4fbfcb..853b1292 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt
@@ -15,10 +15,7 @@ import com.simplemobiletools.contacts.activities.MainActivity
import com.simplemobiletools.contacts.activities.SimpleActivity
import com.simplemobiletools.contacts.adapters.ContactsAdapter
import com.simplemobiletools.contacts.adapters.GroupsAdapter
-import com.simplemobiletools.contacts.extensions.config
-import com.simplemobiletools.contacts.extensions.editContact
-import com.simplemobiletools.contacts.extensions.tryStartCall
-import com.simplemobiletools.contacts.extensions.viewContact
+import com.simplemobiletools.contacts.extensions.*
import com.simplemobiletools.contacts.helpers.*
import com.simplemobiletools.contacts.models.Contact
import com.simplemobiletools.contacts.models.Group
@@ -103,7 +100,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
this is GroupsFragment -> contacts
this is FavoritesFragment -> contacts.filter { it.starred == 1 } as ArrayList
else -> {
- val contactSources = config.displayContactSources
+ val contactSources = activity!!.getVisibleContactSources()
contacts.filter { contactSources.contains(it.source) } as ArrayList
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Config.kt
index 444a814c..de1bb860 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Config.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Config.kt
@@ -8,9 +8,9 @@ class Config(context: Context) : BaseConfig(context) {
fun newInstance(context: Context) = Config(context)
}
- var displayContactSources: Set
- get() = prefs.getStringSet(DISPLAY_CONTACT_SOURCES, hashSetOf("-1"))
- set(displayContactSources) = prefs.edit().remove(DISPLAY_CONTACT_SOURCES).putStringSet(DISPLAY_CONTACT_SOURCES, displayContactSources).apply()
+ var ignoredContactSources: HashSet
+ get() = prefs.getStringSet(IGNORED_CONTACT_SOURCES, hashSetOf(".")) as HashSet
+ set(ignoreContactSources) = prefs.edit().remove(IGNORED_CONTACT_SOURCES).putStringSet(IGNORED_CONTACT_SOURCES, ignoreContactSources).apply()
var showContactThumbnails: Boolean
get() = prefs.getBoolean(SHOW_CONTACT_THUMBNAILS, true)
@@ -44,4 +44,8 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(SHOW_CONTACT_FIELDS, SHOW_FIRST_NAME_FIELD or SHOW_SURNAME_FIELD or SHOW_PHONE_NUMBERS_FIELD or SHOW_EMAILS_FIELD or
SHOW_ADDRESSES_FIELD or SHOW_EVENTS_FIELD or SHOW_NOTES_FIELD or SHOW_GROUPS_FIELD or SHOW_CONTACT_SOURCE_FIELD)
set(showContactFields) = prefs.edit().putInt(SHOW_CONTACT_FIELDS, showContactFields).apply()
+
+ var filterDuplicates: Boolean
+ get() = prefs.getBoolean(FILTER_DUPLICATES, true)
+ set(filterDuplicates) = prefs.edit().putBoolean(FILTER_DUPLICATES, filterDuplicates).apply()
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt
index 0b2e1b25..5409d2dd 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt
@@ -5,13 +5,14 @@ import android.provider.ContactsContract.CommonDataKinds
// shared prefs
const val SHOW_CONTACT_THUMBNAILS = "show_contact_thumbnails"
const val SHOW_PHONE_NUMBERS = "show_phone_numbers"
-const val DISPLAY_CONTACT_SOURCES = "display_contact_sources"
+const val IGNORED_CONTACT_SOURCES = "ignored_contact_sources"
const val START_NAME_WITH_SURNAME = "start_name_with_surname"
const val LAST_USED_CONTACT_SOURCE = "last_used_contact_source"
const val LOCAL_ACCOUNT_NAME = "local_account_name"
const val LOCAL_ACCOUNT_TYPE = "local_account_type"
const val ON_CONTACT_CLICK = "on_contact_click"
const val SHOW_CONTACT_FIELDS = "show_contact_fields"
+const val FILTER_DUPLICATES = "filter_duplicates"
const val CONTACT_ID = "contact_id"
const val SMT_PRIVATE = "smt_private" // used at the contact source of local contacts hidden from other apps
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt
index c100807c..e52181fa 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt
@@ -1,6 +1,7 @@
package com.simplemobiletools.contacts.helpers
import android.accounts.AccountManager
+import android.app.Activity
import android.content.*
import android.database.Cursor
import android.graphics.Bitmap
@@ -11,7 +12,6 @@ import android.provider.ContactsContract.CommonDataKinds.Note
import android.provider.MediaStore
import android.text.TextUtils
import android.util.SparseArray
-import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.SORT_BY_FIRST_NAME
import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME
@@ -20,24 +20,32 @@ import com.simplemobiletools.commons.helpers.SORT_DESCENDING
import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.extensions.*
import com.simplemobiletools.contacts.models.*
+import com.simplemobiletools.contacts.overloads.times
-class ContactsHelper(val activity: BaseSimpleActivity) {
+class ContactsHelper(val activity: Activity) {
private val BATCH_SIZE = 100
+ private var displayContactSources = ArrayList()
+
fun getContacts(callback: (ArrayList) -> Unit) {
Thread {
val contacts = SparseArray()
+ displayContactSources = activity.getVisibleContactSources()
getDeviceContacts(contacts)
- activity.dbHelper.getContacts(activity).forEach {
- contacts.put(it.id, it)
+ if (displayContactSources.contains(SMT_PRIVATE)) {
+ activity.dbHelper.getContacts(activity).forEach {
+ contacts.put(it.id, it)
+ }
}
val contactsSize = contacts.size()
var resultContacts = ArrayList(contactsSize)
(0 until contactsSize).mapTo(resultContacts) { contacts.valueAt(it) }
- resultContacts = resultContacts.distinctBy {
- it.getHashToCompare()
- } as ArrayList
+ if (activity.config.filterDuplicates) {
+ resultContacts = resultContacts.distinctBy {
+ it.getHashToCompare()
+ } as ArrayList
+ }
// groups are obtained with contactID, not rawID, so assign them to proper contacts like this
val groups = getContactGroups(getStoredGroups())
@@ -60,8 +68,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
val uri = ContactsContract.Data.CONTENT_URI
val projection = getContactProjection()
- val selection = "${ContactsContract.Data.MIMETYPE} = ?"
- val selectionArgs = arrayOf(CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+ val selection = getSourcesSelection(true)
+ val selectionArgs = getSourcesSelectionArgs(CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
val sortOrder = getSortString()
var cursor: Cursor? = null
@@ -100,7 +108,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
cursor?.close()
}
- val phoneNumbers = getPhoneNumbers()
+ val phoneNumbers = getPhoneNumbers(null)
var size = phoneNumbers.size()
for (i in 0 until size) {
val key = phoneNumbers.keyAt(i)
@@ -159,8 +167,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
CommonDataKinds.Phone.TYPE
)
- val selection = if (contactId == null) null else "${ContactsContract.Data.RAW_CONTACT_ID} = ?"
- val selectionArgs = if (contactId == null) null else arrayOf(contactId.toString())
+ val selection = if (contactId == null) getSourcesSelection() else "${ContactsContract.Data.RAW_CONTACT_ID} = ?"
+ val selectionArgs = if (contactId == null) getSourcesSelectionArgs() else arrayOf(contactId.toString())
var cursor: Cursor? = null
try {
@@ -184,6 +192,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
} finally {
cursor?.close()
}
+
return phoneNumbers
}
@@ -196,8 +205,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
CommonDataKinds.Email.TYPE
)
- val selection = if (contactId == null) null else "${ContactsContract.Data.RAW_CONTACT_ID} = ?"
- val selectionArgs = if (contactId == null) null else arrayOf(contactId.toString())
+ val selection = if (contactId == null) getSourcesSelection() else "${ContactsContract.Data.RAW_CONTACT_ID} = ?"
+ val selectionArgs = if (contactId == null) getSourcesSelectionArgs() else arrayOf(contactId.toString())
var cursor: Cursor? = null
try {
@@ -215,7 +224,6 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
emails[id]!!.add(Email(email, type))
} while (cursor.moveToNext())
}
-
} catch (e: Exception) {
activity.showErrorToast(e)
} finally {
@@ -234,8 +242,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
CommonDataKinds.StructuredPostal.TYPE
)
- val selection = if (contactId == null) null else "${ContactsContract.Data.RAW_CONTACT_ID} = ?"
- val selectionArgs = if (contactId == null) null else arrayOf(contactId.toString())
+ val selection = if (contactId == null) getSourcesSelection() else "${ContactsContract.Data.RAW_CONTACT_ID} = ?"
+ val selectionArgs = if (contactId == null) getSourcesSelectionArgs() else arrayOf(contactId.toString())
var cursor: Cursor? = null
try {
@@ -253,7 +261,6 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
addresses[id]!!.add(Address(address, type))
} while (cursor.moveToNext())
}
-
} catch (e: Exception) {
activity.showErrorToast(e)
} finally {
@@ -272,13 +279,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
CommonDataKinds.Event.TYPE
)
- var selection = "${ContactsContract.Data.MIMETYPE} = ?"
- var selectionArgs = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE)
-
- if (contactId != null) {
- selection += " AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
- selectionArgs = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE, contactId.toString())
- }
+ val selection = getSourcesSelection(true, contactId != null)
+ val selectionArgs = getSourcesSelectionArgs(CommonDataKinds.Event.CONTENT_ITEM_TYPE, contactId)
var cursor: Cursor? = null
try {
@@ -313,13 +315,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
Note.NOTE
)
- var selection = "${ContactsContract.Data.MIMETYPE} = ?"
- var selectionArgs = arrayOf(Note.CONTENT_ITEM_TYPE)
-
- if (contactId != null) {
- selection += " AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
- selectionArgs = arrayOf(Note.CONTENT_ITEM_TYPE, contactId.toString())
- }
+ val selection = getSourcesSelection(true, contactId != null)
+ val selectionArgs = getSourcesSelectionArgs(Note.CONTENT_ITEM_TYPE, contactId)
var cursor: Cursor? = null
try {
@@ -349,13 +346,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
CommonDataKinds.Organization.TITLE
)
- var selection = "${ContactsContract.Data.MIMETYPE} = ?"
- var selectionArgs = arrayOf(CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
-
- if (contactId != null) {
- selection += " AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
- selectionArgs = arrayOf(CommonDataKinds.Organization.CONTENT_ITEM_TYPE, contactId.toString())
- }
+ val selection = getSourcesSelection(true, contactId != null)
+ val selectionArgs = getSourcesSelectionArgs(CommonDataKinds.Organization.CONTENT_ITEM_TYPE, contactId)
var cursor: Cursor? = null
try {
@@ -386,13 +378,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
CommonDataKinds.Website.URL
)
- var selection = "${ContactsContract.Data.MIMETYPE} = ?"
- var selectionArgs = arrayOf(CommonDataKinds.Website.CONTENT_ITEM_TYPE)
-
- if (contactId != null) {
- selection += " AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
- selectionArgs = arrayOf(CommonDataKinds.Website.CONTENT_ITEM_TYPE, contactId.toString())
- }
+ val selection = getSourcesSelection(true, contactId != null)
+ val selectionArgs = getSourcesSelectionArgs(CommonDataKinds.Website.CONTENT_ITEM_TYPE, contactId)
var cursor: Cursor? = null
try {
@@ -430,13 +417,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
ContactsContract.Data.DATA1
)
- var selection = "${ContactsContract.Data.MIMETYPE} = ?"
- var selectionArgs = arrayOf(CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE)
-
- if (contactId != null) {
- selection += " AND ${ContactsContract.Data.CONTACT_ID} = ?"
- selectionArgs = arrayOf(CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE, contactId.toString())
- }
+ val selection = getSourcesSelection(true, contactId != null, false)
+ val selectionArgs = getSourcesSelectionArgs(CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE, contactId)
var cursor: Cursor? = null
try {
@@ -463,6 +445,48 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
return groups
}
+ private fun getQuestionMarks() = "?,".times(displayContactSources.filter { it.isNotEmpty() }.size).trimEnd(',')
+
+ private fun getSourcesSelection(addMimeType: Boolean = false, addContactId: Boolean = false, useRawContactId: Boolean = true): String {
+ val strings = ArrayList()
+ if (addMimeType) {
+ strings.add("${ContactsContract.Data.MIMETYPE} = ?")
+ }
+
+ if (addContactId) {
+ strings.add("${if (useRawContactId) ContactsContract.Data.RAW_CONTACT_ID else ContactsContract.Data.CONTACT_ID} = ?")
+ } else {
+ // sometimes local device storage has null account_name, handle it properly
+ val accountnameString = StringBuilder()
+ if (displayContactSources.contains("")) {
+ accountnameString.append("(")
+ }
+ accountnameString.append("${ContactsContract.RawContacts.ACCOUNT_NAME} IN (${getQuestionMarks()})")
+ if (displayContactSources.contains("")) {
+ accountnameString.append(" OR ${ContactsContract.RawContacts.ACCOUNT_NAME} IS NULL)")
+ }
+ strings.add(accountnameString.toString())
+ }
+
+ return TextUtils.join(" AND ", strings)
+ }
+
+ private fun getSourcesSelectionArgs(mimetype: String? = null, contactId: Int? = null): Array {
+ val args = ArrayList()
+
+ if (mimetype != null) {
+ args.add(mimetype)
+ }
+
+ if (contactId != null) {
+ args.add(contactId.toString())
+ } else {
+ args.addAll(displayContactSources.filter { it.isNotEmpty() })
+ }
+
+ return args.toTypedArray()
+ }
+
fun getStoredGroups(): ArrayList {
val groups = getDeviceStoredGroups()
groups.addAll(activity.dbHelper.getGroups())
@@ -622,13 +646,17 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
fun getContactSources(callback: (ArrayList) -> Unit) {
Thread {
- val sources = getDeviceContactSources()
- sources.add(ContactSource(activity.getString(R.string.phone_storage_hidden), SMT_PRIVATE))
- callback(ArrayList(sources))
+ callback(getContactSourcesSync())
}.start()
}
- private fun getDeviceContactSources(): LinkedHashSet {
+ private fun getContactSourcesSync(): ArrayList {
+ val sources = getDeviceContactSources()
+ sources.add(ContactSource(activity.getString(R.string.phone_storage_hidden), SMT_PRIVATE))
+ return ArrayList(sources)
+ }
+
+ fun getDeviceContactSources(): LinkedHashSet {
val sources = LinkedHashSet()
if (!activity.hasContactPermissions()) {
return sources
@@ -1220,13 +1248,18 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
try {
val operations = ArrayList()
- val selection = "${ContactsContract.Data.CONTACT_ID} = ?"
+ val selection = "${ContactsContract.RawContacts._ID} = ?"
contacts.filter { it.source != SMT_PRIVATE }.forEach {
- ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
- val selectionArgs = arrayOf(it.contactId.toString())
+ ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI).apply {
+ val selectionArgs = arrayOf(it.id.toString())
withSelection(selection, selectionArgs)
operations.add(build())
}
+
+ if (operations.size % BATCH_SIZE == 0) {
+ activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
+ operations.clear()
+ }
}
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt
index e3729c19..63690935 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt
@@ -1,5 +1,6 @@
package com.simplemobiletools.contacts.helpers
+import android.app.Activity
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
@@ -11,7 +12,6 @@ import android.provider.MediaStore
import android.text.TextUtils
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
-import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.getBlobValue
import com.simplemobiletools.commons.extensions.getIntValue
import com.simplemobiletools.commons.extensions.getLongValue
@@ -249,7 +249,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
}
}
- fun getContacts(activity: BaseSimpleActivity, selection: String? = null, selectionArgs: Array? = null): ArrayList {
+ fun getContacts(activity: Activity, selection: String? = null, selectionArgs: Array? = null): ArrayList {
val storedGroups = ContactsHelper(activity).getStoredGroups()
val contacts = ArrayList()
val projection = arrayOf(COL_ID, COL_PREFIX, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_SUFFIX, COL_PHONE_NUMBERS, COL_EMAILS,
@@ -319,7 +319,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
return contacts
}
- fun getContactWithId(activity: BaseSimpleActivity, id: Int): Contact? {
+ fun getContactWithId(activity: Activity, id: Int): Contact? {
val selection = "$COL_ID = ?"
val selectionArgs = arrayOf(id.toString())
return getContacts(activity, selection, selectionArgs).firstOrNull()
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt
index 42cc04cd..5e16348a 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt
@@ -86,6 +86,7 @@ data class Contact(val id: Int, var prefix: String, var firstName: String, var m
fun getHashToCompare(): Int {
val newPhoneNumbers = ArrayList()
phoneNumbers.mapTo(newPhoneNumbers, { PhoneNumber(it.value.replace(pattern, ""), 0) })
- return copy(id = 0, phoneNumbers = newPhoneNumbers).hashCode()
+ return copy(id = 0, prefix = "", firstName = getFullName().toLowerCase(), middleName = "", surname = "", suffix = "", photoUri = "",
+ phoneNumbers = newPhoneNumbers, source = "", starred = 0, contactId = 0, thumbnailUri = "", notes = "").hashCode()
}
}
diff --git a/app/src/main/res/drawable-v26/ic_launcher_foreground.xml b/app/src/main/res/drawable-v26/ic_launcher_foreground.xml
deleted file mode 100644
index 1c77b507..00000000
--- a/app/src/main/res/drawable-v26/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
index d1fedd67..18addc99 100644
--- a/app/src/main/res/layout/activity_settings.xml
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -193,6 +193,29 @@
+
+
+
+
+
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_amber.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_amber.xml
new file mode 100644
index 00000000..ddd51757
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_amber.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_blue.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_blue.xml
new file mode 100644
index 00000000..0bb69cf2
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_blue.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_blue_grey.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_blue_grey.xml
new file mode 100644
index 00000000..aa10bae8
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_blue_grey.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_brown.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_brown.xml
new file mode 100644
index 00000000..8d2fc23f
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_brown.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_cyan.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_cyan.xml
new file mode 100644
index 00000000..89f7a275
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_cyan.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_deep_orange.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_deep_orange.xml
new file mode 100644
index 00000000..0822e55f
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_deep_orange.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_deep_purple.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_deep_purple.xml
new file mode 100644
index 00000000..0735af68
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_deep_purple.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_green.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_green.xml
new file mode 100644
index 00000000..06e60b88
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_green.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_grey_black.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_grey_black.xml
new file mode 100644
index 00000000..4765f7ec
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_grey_black.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_indigo.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_indigo.xml
new file mode 100644
index 00000000..37f5249f
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_indigo.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_light_blue.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_light_blue.xml
new file mode 100644
index 00000000..eed925f1
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_light_blue.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_light_green.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_light_green.xml
new file mode 100644
index 00000000..a051acce
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_light_green.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_lime.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_lime.xml
new file mode 100644
index 00000000..d6df0e23
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_lime.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_pink.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_pink.xml
new file mode 100644
index 00000000..4b6fc188
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_pink.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_purple.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_purple.xml
new file mode 100644
index 00000000..e7e2cb97
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_purple.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_red.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_red.xml
new file mode 100644
index 00000000..972ad3de
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_red.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_teal.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_teal.xml
new file mode 100644
index 00000000..c3020ef7
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_teal.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_yellow.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_yellow.xml
new file mode 100644
index 00000000..0c336264
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_yellow.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
index 809c395b..1685a7cc 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_amber.png b/app/src/main/res/mipmap-hdpi/ic_launcher_amber.png
new file mode 100644
index 00000000..4e603d42
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_amber.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_blue.png b/app/src/main/res/mipmap-hdpi/ic_launcher_blue.png
new file mode 100644
index 00000000..6a3210fc
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_blue.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_blue_grey.png b/app/src/main/res/mipmap-hdpi/ic_launcher_blue_grey.png
new file mode 100644
index 00000000..1c9f3359
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_blue_grey.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_brown.png b/app/src/main/res/mipmap-hdpi/ic_launcher_brown.png
new file mode 100644
index 00000000..df0fb6a8
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_brown.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_cyan.png b/app/src/main/res/mipmap-hdpi/ic_launcher_cyan.png
new file mode 100644
index 00000000..c62c3d4d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_cyan.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_deep_orange.png b/app/src/main/res/mipmap-hdpi/ic_launcher_deep_orange.png
new file mode 100644
index 00000000..4978c3bc
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_deep_orange.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_deep_purple.png b/app/src/main/res/mipmap-hdpi/ic_launcher_deep_purple.png
new file mode 100644
index 00000000..09595649
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_deep_purple.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..4f38c676
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_green.png b/app/src/main/res/mipmap-hdpi/ic_launcher_green.png
new file mode 100644
index 00000000..0486ae93
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_green.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_grey_black.png b/app/src/main/res/mipmap-hdpi/ic_launcher_grey_black.png
new file mode 100644
index 00000000..fdd0b1a9
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_grey_black.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_indigo.png b/app/src/main/res/mipmap-hdpi/ic_launcher_indigo.png
new file mode 100644
index 00000000..1292b500
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_indigo.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_light_blue.png b/app/src/main/res/mipmap-hdpi/ic_launcher_light_blue.png
new file mode 100644
index 00000000..b1e5bf61
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_light_blue.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_light_green.png b/app/src/main/res/mipmap-hdpi/ic_launcher_light_green.png
new file mode 100644
index 00000000..4985547d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_light_green.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_lime.png b/app/src/main/res/mipmap-hdpi/ic_launcher_lime.png
new file mode 100644
index 00000000..4363813b
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_lime.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_pink.png b/app/src/main/res/mipmap-hdpi/ic_launcher_pink.png
new file mode 100644
index 00000000..9d0ac493
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_pink.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_purple.png b/app/src/main/res/mipmap-hdpi/ic_launcher_purple.png
new file mode 100644
index 00000000..b6f8cb8c
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_purple.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_red.png b/app/src/main/res/mipmap-hdpi/ic_launcher_red.png
index f9c78ff8..0419db88 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_red.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_red.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_teal.png b/app/src/main/res/mipmap-hdpi/ic_launcher_teal.png
new file mode 100644
index 00000000..e9857e80
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_teal.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_yellow.png b/app/src/main/res/mipmap-hdpi/ic_launcher_yellow.png
new file mode 100644
index 00000000..59db6f1f
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_yellow.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..5b2f59af
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_amber.png b/app/src/main/res/mipmap-mdpi/ic_launcher_amber.png
new file mode 100644
index 00000000..70922633
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_amber.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_blue.png b/app/src/main/res/mipmap-mdpi/ic_launcher_blue.png
new file mode 100644
index 00000000..f8d0c7ad
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_blue.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_blue_grey.png b/app/src/main/res/mipmap-mdpi/ic_launcher_blue_grey.png
new file mode 100644
index 00000000..c27cdb6f
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_blue_grey.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_brown.png b/app/src/main/res/mipmap-mdpi/ic_launcher_brown.png
new file mode 100644
index 00000000..746851a6
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_brown.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_cyan.png b/app/src/main/res/mipmap-mdpi/ic_launcher_cyan.png
new file mode 100644
index 00000000..8e715cf1
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_cyan.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_deep_orange.png b/app/src/main/res/mipmap-mdpi/ic_launcher_deep_orange.png
new file mode 100644
index 00000000..c7cb450f
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_deep_orange.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_deep_purple.png b/app/src/main/res/mipmap-mdpi/ic_launcher_deep_purple.png
new file mode 100644
index 00000000..8a893870
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_deep_purple.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..f6426358
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_green.png b/app/src/main/res/mipmap-mdpi/ic_launcher_green.png
new file mode 100644
index 00000000..c7fff1be
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_green.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_grey_black.png b/app/src/main/res/mipmap-mdpi/ic_launcher_grey_black.png
new file mode 100644
index 00000000..890de896
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_grey_black.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_indigo.png b/app/src/main/res/mipmap-mdpi/ic_launcher_indigo.png
new file mode 100644
index 00000000..f29e7ff2
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_indigo.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_light_blue.png b/app/src/main/res/mipmap-mdpi/ic_launcher_light_blue.png
new file mode 100644
index 00000000..aa16d0c8
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_light_blue.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_light_green.png b/app/src/main/res/mipmap-mdpi/ic_launcher_light_green.png
new file mode 100644
index 00000000..6f4058c0
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_light_green.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_lime.png b/app/src/main/res/mipmap-mdpi/ic_launcher_lime.png
new file mode 100644
index 00000000..58800f71
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_lime.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_pink.png b/app/src/main/res/mipmap-mdpi/ic_launcher_pink.png
new file mode 100644
index 00000000..efa5922c
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_pink.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_purple.png b/app/src/main/res/mipmap-mdpi/ic_launcher_purple.png
new file mode 100644
index 00000000..9a84445b
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_purple.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_red.png b/app/src/main/res/mipmap-mdpi/ic_launcher_red.png
new file mode 100644
index 00000000..df449b83
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_red.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_teal.png b/app/src/main/res/mipmap-mdpi/ic_launcher_teal.png
new file mode 100644
index 00000000..6114544f
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_teal.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_yellow.png b/app/src/main/res/mipmap-mdpi/ic_launcher_yellow.png
new file mode 100644
index 00000000..397bb3e0
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_yellow.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index 862de41d..c32297f5 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_amber.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_amber.png
new file mode 100644
index 00000000..bc91d7bc
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_amber.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_blue.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_blue.png
new file mode 100644
index 00000000..dc2accde
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_blue.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_blue_grey.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_blue_grey.png
new file mode 100644
index 00000000..6fa7019a
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_blue_grey.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_brown.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_brown.png
new file mode 100644
index 00000000..d56d2067
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_brown.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_cyan.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_cyan.png
new file mode 100644
index 00000000..8db92f75
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_cyan.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_deep_orange.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_deep_orange.png
new file mode 100644
index 00000000..7183ca3b
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_deep_orange.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_deep_purple.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_deep_purple.png
new file mode 100644
index 00000000..c1a75b49
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_deep_purple.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..6c64055f
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_green.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_green.png
new file mode 100644
index 00000000..e2ae8786
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_green.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_grey_black.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_grey_black.png
new file mode 100644
index 00000000..968f4eed
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_grey_black.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_indigo.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_indigo.png
new file mode 100644
index 00000000..570d5cd0
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_indigo.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_light_blue.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_light_blue.png
new file mode 100644
index 00000000..d0bba136
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_light_blue.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_light_green.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_light_green.png
new file mode 100644
index 00000000..5a878f4f
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_light_green.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_lime.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_lime.png
new file mode 100644
index 00000000..5de09f20
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_lime.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_pink.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_pink.png
new file mode 100644
index 00000000..d7f18487
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_pink.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_purple.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_purple.png
new file mode 100644
index 00000000..2a1945e3
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_purple.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_red.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_red.png
index 2649ce6a..2b65c345 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_red.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_red.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_teal.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_teal.png
new file mode 100644
index 00000000..f6881dfe
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_teal.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_yellow.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_yellow.png
new file mode 100644
index 00000000..5d761f5a
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_yellow.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index a5308be6..85da53e6 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_amber.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_amber.png
new file mode 100644
index 00000000..61293920
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_amber.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_blue.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_blue.png
new file mode 100644
index 00000000..38047fbd
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_blue.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_blue_grey.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_blue_grey.png
new file mode 100644
index 00000000..f923c7cf
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_blue_grey.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_brown.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_brown.png
new file mode 100644
index 00000000..7f8c369e
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_brown.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_cyan.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_cyan.png
new file mode 100644
index 00000000..a92637d5
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_cyan.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_deep_orange.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_deep_orange.png
new file mode 100644
index 00000000..b1a34c8b
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_deep_orange.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_deep_purple.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_deep_purple.png
new file mode 100644
index 00000000..05b03b7e
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_deep_purple.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..b0da83dd
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_green.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_green.png
new file mode 100644
index 00000000..686a9a7b
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_green.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_grey_black.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_grey_black.png
new file mode 100644
index 00000000..a672b2d8
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_grey_black.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_indigo.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_indigo.png
new file mode 100644
index 00000000..f70b787c
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_indigo.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_light_blue.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_light_blue.png
new file mode 100644
index 00000000..8f4205b3
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_light_blue.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_light_green.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_light_green.png
new file mode 100644
index 00000000..f7106375
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_light_green.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_lime.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_lime.png
new file mode 100644
index 00000000..df02b109
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_lime.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_pink.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_pink.png
new file mode 100644
index 00000000..d9ad20af
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_pink.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_purple.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_purple.png
new file mode 100644
index 00000000..dc4604c1
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_purple.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_red.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_red.png
index fa6c0e9e..053d4b27 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_red.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_red.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_teal.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_teal.png
new file mode 100644
index 00000000..b5710557
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_teal.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_yellow.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_yellow.png
new file mode 100644
index 00000000..3cc9dc9b
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_yellow.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index e3c805fe..05e7f7b6 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_amber.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_amber.png
new file mode 100644
index 00000000..7132e274
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_amber.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_blue.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_blue.png
new file mode 100644
index 00000000..c8dc9c1a
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_blue.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_blue_grey.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_blue_grey.png
new file mode 100644
index 00000000..8fe9b0f7
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_blue_grey.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_brown.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_brown.png
new file mode 100644
index 00000000..ac7c95d2
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_brown.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_cyan.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_cyan.png
new file mode 100644
index 00000000..4c2bc6cd
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_cyan.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_deep_orange.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_deep_orange.png
new file mode 100644
index 00000000..60060991
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_deep_orange.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_deep_purple.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_deep_purple.png
new file mode 100644
index 00000000..f04e6f2a
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_deep_purple.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..275f40b0
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_green.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_green.png
new file mode 100644
index 00000000..68fb4425
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_green.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_grey_black.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_grey_black.png
new file mode 100644
index 00000000..9d832af1
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_grey_black.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_indigo.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_indigo.png
new file mode 100644
index 00000000..a7b32958
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_indigo.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_light_blue.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_light_blue.png
new file mode 100644
index 00000000..fb9f1c48
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_light_blue.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_light_green.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_light_green.png
new file mode 100644
index 00000000..7df09e7e
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_light_green.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_lime.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_lime.png
new file mode 100644
index 00000000..0d0590c5
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_lime.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_pink.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_pink.png
new file mode 100644
index 00000000..bc5afb4a
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_pink.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_purple.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_purple.png
new file mode 100644
index 00000000..6c82c3c8
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_purple.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_red.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_red.png
index 491e3334..5a44eec3 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_red.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_red.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_teal.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_teal.png
new file mode 100644
index 00000000..0a9ae407
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_teal.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_yellow.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_yellow.png
new file mode 100644
index 00000000..07a71d45
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_yellow.png differ
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index ad6daa49..58b24d96 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -48,6 +48,7 @@
Show favorites tab
Show groups tab
Manage shown contact fields
+ Try filtering out duplicate contacts
Email
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index fc2e9af5..717a7ce1 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -48,6 +48,7 @@
Εμφάνιση καρτέλας αγαπημένων
Εμφάνιση καρτέλας ομάδων
Manage shown contact fields
+ Try filtering out duplicate contacts
Email
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 89a0769e..aaded17e 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -48,6 +48,7 @@
Afficher l\'onglet favoris
Afficher l\'onglet groupes
Configurer l\'affichage des champs des contacts
+ Try filtering out duplicate contacts
E-mail
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
index 446dd86b..08d418e7 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -48,6 +48,7 @@
Prikaži karticu favorita
Prikaži karticu grupa
Manage shown contact fields
+ Try filtering out duplicate contacts
E-pošta
diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml
index a1f591d6..99536a44 100644
--- a/app/src/main/res/values-ko-rKR/strings.xml
+++ b/app/src/main/res/values-ko-rKR/strings.xml
@@ -48,6 +48,7 @@
Show favorites tab
Show groups tab
Manage shown contact fields
+ Try filtering out duplicate contacts
이메일
diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml
index c6c2d496..f5ee1255 100644
--- a/app/src/main/res/values-lt/strings.xml
+++ b/app/src/main/res/values-lt/strings.xml
@@ -48,6 +48,7 @@
Rodyti mėgiamiausiųjų skirtuką
Rodyti grupių skirtuką
Manage shown contact fields
+ Try filtering out duplicate contacts
Elektroninis paštas
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index df49cef5..486feb5a 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -48,6 +48,7 @@
Mostrar favoritos
Mostrar grupos
Gerir campos a exibir
+ Try filtering out duplicate contacts
E-mail
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 93f8ab03..6a44ca04 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -48,6 +48,7 @@
Показывать вкладку избранного
Показывать вкладку групп
Управление отображаемыми полями контактов
+ Try filtering out duplicate contacts
Эл. почта
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index a16d32fb..c1f6d985 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -48,6 +48,7 @@
Zobraziť okno s obľúbenými
Zobraziť okno so skupinami
Spravovať zobrazené polia kontaktov
+ Pokúsiť sa vyfiltrovať duplicitné kontakty
Email
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index c6f7c6d3..42f606b5 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -48,6 +48,7 @@
Visa fliken Favoriter
Visa fliken Grupper
Hantera visade kontaktfält
+ Try filtering out duplicate contacts
E-post
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 22d3d9d1..79766c2a 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -48,6 +48,7 @@
顯示我的最愛頁面
顯示群組頁面
管理顯示的聯絡人欄位
+ Try filtering out duplicate contacts
電子信箱
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a5b8c8ae..a3c3eede 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -48,6 +48,7 @@
Show favorites tab
Show groups tab
Manage shown contact fields
+ Try filtering out duplicate contacts
Email
diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png
index 692e44ce..b5f3b005 100644
Binary files a/fastlane/metadata/android/en-US/images/icon.png and b/fastlane/metadata/android/en-US/images/icon.png differ