From a631a53db6bfaef75a520167ece4b384243d204d Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 18:38:30 +0100 Subject: [PATCH 01/53] create a table for storing local contacts --- app/build.gradle | 2 + .../com/simplemobiletools/contacts/App.kt | 1 + .../contacts/activities/MainActivity.kt | 3 +- .../contacts/extensions/Context.kt | 3 ++ .../contacts/helpers/DBHelper.kt | 42 +++++++++++++++++++ 5 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt diff --git a/app/build.gradle b/app/build.gradle index 92b6ece5..ab8a2dea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -47,6 +47,8 @@ ext { dependencies { implementation 'com.simplemobiletools:commons:3.11.3' implementation 'joda-time:joda-time:2.9.9' + implementation 'com.facebook.stetho:stetho:1.5.0' + implementation 'com.google.code.gson:gson:2.8.2' debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion" releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion" diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/App.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/App.kt index 4507f7c8..12e6ca36 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/App.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/App.kt @@ -12,6 +12,7 @@ class App : Application() { return } LeakCanary.install(this) + Stetho.initializeWithDefaults(this) } checkUseEnglish() 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 6fc48b2c..56b3bf4e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt @@ -372,7 +372,8 @@ class MainActivity : SimpleActivity(), RefreshContactsListener { } private fun launchAbout() { - startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_MULTISELECT or LICENSE_JODA or LICENSE_GLIDE, BuildConfig.VERSION_NAME) + startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_MULTISELECT or LICENSE_JODA or LICENSE_GLIDE or LICENSE_GSON or LICENSE_STETHO, + BuildConfig.VERSION_NAME) } override fun refreshContacts() { diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt index 9d5b9aa0..3e1f947f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt @@ -17,11 +17,14 @@ import com.simplemobiletools.contacts.activities.EditContactActivity import com.simplemobiletools.contacts.activities.ViewContactActivity import com.simplemobiletools.contacts.helpers.CONTACT_ID import com.simplemobiletools.contacts.helpers.Config +import com.simplemobiletools.contacts.helpers.DBHelper import com.simplemobiletools.contacts.models.Contact import java.io.File val Context.config: Config get() = Config.newInstance(applicationContext) +val Context.dbHelper: DBHelper get() = DBHelper.newInstance(applicationContext) + fun Context.viewContact(contact: Contact) { Intent(applicationContext, ViewContactActivity::class.java).apply { putExtra(CONTACT_ID, contact.id) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt new file mode 100644 index 00000000..c9d4bba2 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -0,0 +1,42 @@ +package com.simplemobiletools.contacts.helpers + +import android.content.Context +import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteOpenHelper + +class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { + private val MAIN_TABLE_NAME = "contacts" + private val COL_ID = "id" + private val COL_FIRST_NAME = "first_name" + private val COL_MIDDLE_NAME = "middle_name" + private val COL_SURNAME = "surname" + private val COL_PHOTO = "photo" + private val COL_PHONE_NUMBERS = "phone_numbers" + private val COL_EMAILS = "emails" + private val COL_EVENTS = "events" + private val COL_STARRED = "starred" + + private val mDb: SQLiteDatabase = writableDatabase + + companion object { + private const val DB_VERSION = 1 + const val DB_NAME = "contacts.db" + var dbInstance: DBHelper? = null + + fun newInstance(context: Context): DBHelper { + if (dbInstance == null) + dbInstance = DBHelper(context) + + return dbInstance!! + } + } + + override fun onCreate(db: SQLiteDatabase) { + db.execSQL("CREATE TABLE $MAIN_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_FIRST_NAME TEXT, $COL_MIDDLE_NAME TEXT, " + + "$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER)") + } + + override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + + } +} From 6305785aa9fe95b8b76312846902a8e31fef0169 Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 19:07:14 +0100 Subject: [PATCH 02/53] implementing contact inserting --- .../com/simplemobiletools/contacts/App.kt | 1 + .../contacts/helpers/ContactsHelper.kt | 5 ++-- .../contacts/helpers/DBHelper.kt | 26 +++++++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/App.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/App.kt index 12e6ca36..354a793f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/App.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/App.kt @@ -1,6 +1,7 @@ package com.simplemobiletools.contacts import android.app.Application +import com.facebook.stetho.Stetho import com.simplemobiletools.commons.extensions.checkUseEnglish import com.squareup.leakcanary.LeakCanary 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 d5d8de29..8e9eb3c4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -22,6 +22,7 @@ import com.simplemobiletools.commons.helpers.SORT_BY_SURNAME import com.simplemobiletools.commons.helpers.SORT_DESCENDING import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.extensions.config +import com.simplemobiletools.contacts.extensions.dbHelper import com.simplemobiletools.contacts.models.* import java.io.ByteArrayOutputStream import java.util.* @@ -559,9 +560,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) { } } - private fun insertLocalContact(contact: Contact): Boolean { - return true - } + private fun insertLocalContact(contact: Contact) = activity.dbHelper.insert(contact) private fun addFullSizePhoto(contactId: Long, fullSizePhotoData: ByteArray) { val baseUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, contactId) 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 c9d4bba2..4aedbb14 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -1,11 +1,15 @@ package com.simplemobiletools.contacts.helpers +import android.content.ContentValues import android.content.Context import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper +import com.google.gson.Gson +import com.simplemobiletools.contacts.models.Contact + class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { - private val MAIN_TABLE_NAME = "contacts" + private val CONTACTS_TABLE_NAME = "contacts" private val COL_ID = "id" private val COL_FIRST_NAME = "first_name" private val COL_MIDDLE_NAME = "middle_name" @@ -32,11 +36,29 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont } override fun onCreate(db: SQLiteDatabase) { - db.execSQL("CREATE TABLE $MAIN_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_FIRST_NAME TEXT, $COL_MIDDLE_NAME TEXT, " + + db.execSQL("CREATE TABLE $CONTACTS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_FIRST_NAME TEXT, $COL_MIDDLE_NAME TEXT, " + "$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER)") } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { } + + fun insert(contact: Contact): Boolean { + val contactValues = fillContactValues(contact) + val id = mDb.insert(CONTACTS_TABLE_NAME, null, contactValues).toInt() + return id != -1 + } + + private fun fillContactValues(contact: Contact): ContentValues { + return ContentValues().apply { + put(COL_FIRST_NAME, contact.firstName) + put(COL_MIDDLE_NAME, contact.middleName) + put(COL_SURNAME, contact.surname) + put(COL_PHONE_NUMBERS, Gson().toJson(contact.phoneNumbers)) + put(COL_EMAILS, Gson().toJson(contact.emails)) + put(COL_EVENTS, Gson().toJson(contact.events)) + put(COL_STARRED, contact.starred) + } + } } From 2ed8a4e150a84ef0ada487c7757ce10220839403 Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 19:21:23 +0100 Subject: [PATCH 03/53] create the function for retrieving contacts from the local database --- .../contacts/helpers/DBHelper.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) 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 4aedbb14..8c677d66 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -5,7 +5,13 @@ import android.content.Context import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import com.simplemobiletools.commons.extensions.getIntValue +import com.simplemobiletools.commons.extensions.getStringValue import com.simplemobiletools.contacts.models.Contact +import com.simplemobiletools.contacts.models.Email +import com.simplemobiletools.contacts.models.Event +import com.simplemobiletools.contacts.models.PhoneNumber class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { @@ -61,4 +67,35 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont put(COL_STARRED, contact.starred) } } + + fun getContacts(): ArrayList { + val contacts = ArrayList() + val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED) + val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, null, null, null, null, null) + cursor.use { + while (cursor.moveToNext()) { + val id = cursor.getIntValue(COL_ID) + val firstName = cursor.getStringValue(COL_FIRST_NAME) + val middleName = cursor.getStringValue(COL_MIDDLE_NAME) + val surname = cursor.getStringValue(COL_SURNAME) + + val phoneNumbersJson = cursor.getStringValue(COL_PHONE_NUMBERS) + val phoneNumbersToken = object : TypeToken>() {}.type + val phoneNumbers = Gson().fromJson>(phoneNumbersJson, phoneNumbersToken) ?: ArrayList(1) + + val emailsJson = cursor.getStringValue(COL_EMAILS) + val emailsToken = object : TypeToken>() {}.type + val emails = Gson().fromJson>(emailsJson, emailsToken) ?: ArrayList(1) + + val eventsJson = cursor.getStringValue(COL_EVENTS) + val eventsToken = object : TypeToken>() {}.type + val events = Gson().fromJson>(eventsJson, eventsToken) ?: ArrayList(1) + + val starred = cursor.getIntValue(COL_STARRED) + val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, events, SMT_PRIVATE, starred, id, "") + contacts.add(contact) + } + } + return contacts + } } From eb4833ff1e44fa67765a1105ac88b1e636330bea Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 20:02:46 +0100 Subject: [PATCH 04/53] start contacts autoincrement id from a million to avoid conflicts --- .../com/simplemobiletools/contacts/helpers/DBHelper.kt | 5 +++++ 1 file changed, 5 insertions(+) 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 8c677d66..5fb4a703 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -26,6 +26,8 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont private val COL_EVENTS = "events" private val COL_STARRED = "starred" + private val FIRST_CONTACT_ID = 1000000 + private val mDb: SQLiteDatabase = writableDatabase companion object { @@ -44,6 +46,9 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont override fun onCreate(db: SQLiteDatabase) { db.execSQL("CREATE TABLE $CONTACTS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_FIRST_NAME TEXT, $COL_MIDDLE_NAME TEXT, " + "$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER)") + + // start autoincrement ID from FIRST_CONTACT_ID to avoid conflicts + db.execSQL("REPLACE INTO sqlite_sequence (name, seq) VALUES ('$CONTACTS_TABLE_NAME', $FIRST_CONTACT_ID)") } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { From 6c39757cec43d33036f002d58ed29aaae32fcf0c Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 20:28:45 +0100 Subject: [PATCH 05/53] show local contacts in the lists --- .../contacts/activities/MainActivity.kt | 4 ++-- .../contacts/adapters/FilterContactSourcesAdapter.kt | 5 +++++ .../contacts/dialogs/FilterContactSourcesDialog.kt | 3 ++- .../simplemobiletools/contacts/extensions/Activity.kt | 11 ++++++++++- .../contacts/fragments/MyViewPagerFragment.kt | 2 +- .../contacts/helpers/ContactsHelper.kt | 4 ++++ 6 files changed, 24 insertions(+), 5 deletions(-) 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 56b3bf4e..fec26748 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt @@ -105,8 +105,8 @@ class MainActivity : SimpleActivity(), RefreshContactsListener { 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_fragment.primaryColorChanged() + favorites_fragment.primaryColorChanged() } val configStartNameWithSurname = config.startNameWithSurname diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/FilterContactSourcesAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/FilterContactSourcesAdapter.kt index 1af2218f..69c97584 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/FilterContactSourcesAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/FilterContactSourcesAdapter.kt @@ -9,6 +9,7 @@ import com.simplemobiletools.commons.interfaces.MyAdapterListener import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.activities.SimpleActivity import com.simplemobiletools.contacts.extensions.config +import com.simplemobiletools.contacts.helpers.SMT_PRIVATE import com.simplemobiletools.contacts.models.ContactSource import kotlinx.android.synthetic.main.item_filter_contact_source.view.* import java.util.* @@ -27,6 +28,10 @@ class FilterContactSourcesAdapter(val activity: SimpleActivity, private val cont if (contactSource.name == activity.config.localAccountName && contactSource.type == activity.config.localAccountType) { contactSource.name = activity.getString(R.string.phone_storage) } + + if (contactSource.type == SMT_PRIVATE && displayContactSources.contains(SMT_PRIVATE)) { + selectedPositions.add(index) + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/FilterContactSourcesDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/FilterContactSourcesDialog.kt index a01dc8f8..cc1a9d41 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/FilterContactSourcesDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/FilterContactSourcesDialog.kt @@ -7,6 +7,7 @@ import com.simplemobiletools.contacts.activities.SimpleActivity import com.simplemobiletools.contacts.adapters.FilterContactSourcesAdapter import com.simplemobiletools.contacts.extensions.config import com.simplemobiletools.contacts.helpers.ContactsHelper +import com.simplemobiletools.contacts.helpers.SMT_PRIVATE import com.simplemobiletools.contacts.models.ContactSource import kotlinx.android.synthetic.main.dialog_filter_contact_sources.view.* import java.util.* @@ -41,7 +42,7 @@ class FilterContactSourcesDialog(val activity: SimpleActivity, private val callb val selectedIndexes = (view.filter_contact_sources_list.adapter as FilterContactSourcesAdapter).getSelectedItemsSet() val selectedContactSources = HashSet() selectedIndexes.forEach { - selectedContactSources.add(contactSources[it].name) + selectedContactSources.add(if (contactSources[it].type == SMT_PRIVATE) SMT_PRIVATE else contactSources[it].name) } if (activity.config.displayContactSources != selectedContactSources) { 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 02a87f7b..e47be45f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Activity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Activity.kt @@ -13,6 +13,7 @@ import com.simplemobiletools.contacts.BuildConfig import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.activities.SimpleActivity 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 java.io.File @@ -62,6 +63,8 @@ fun SimpleActivity.showContactSourcePicker(currentSource: String, callback: (new items.add(RadioItem(index, publicAccount)) if (account == currentSource) { currentSourceIndex = index + } else if (currentSource == SMT_PRIVATE && account == getString(R.string.phone_storage_hidden)) { + currentSourceIndex = index } } @@ -73,7 +76,13 @@ fun SimpleActivity.showContactSourcePicker(currentSource: String, callback: (new } } -fun SimpleActivity.getPublicContactSource(source: String) = if (source == config.localAccountName) getString(R.string.phone_storage) else source +fun SimpleActivity.getPublicContactSource(source: String): String { + return when (source) { + config.localAccountName -> getString(R.string.phone_storage) + SMT_PRIVATE -> getString(R.string.phone_storage_hidden) + else -> source + } +} fun BaseSimpleActivity.shareContacts(contacts: ArrayList) { val file = getTempFile() 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 de0ff1ae..f437ec88 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt @@ -59,7 +59,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet) } } - fun primaryColorChanged(color: Int) { + fun primaryColorChanged() { fragment_fastscroller.updatePrimaryColor() fragment_fastscroller.updateBubblePrimaryColor() } 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 8e9eb3c4..a75b083b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -78,6 +78,10 @@ class ContactsHelper(val activity: BaseSimpleActivity) { contacts[key]?.emails = emails.valueAt(i) } + activity.dbHelper.getContacts().forEach { + contacts.put(it.id, it) + } + val contactsSize = contacts.size() var resultContacts = ArrayList(contactsSize) (0 until contactsSize).mapTo(resultContacts) { contacts.valueAt(it) } From 097344dd264262b475222f27f5782aac5a95c2cc Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 20:42:44 +0100 Subject: [PATCH 06/53] properly show private local contact details/edit screen --- .../contacts/activities/EditContactActivity.kt | 2 +- .../contacts/activities/ViewContactActivity.kt | 2 +- .../simplemobiletools/contacts/extensions/Context.kt | 6 +++--- .../simplemobiletools/contacts/helpers/Constants.kt | 3 ++- .../contacts/helpers/ContactsHelper.kt | 4 +++- .../com/simplemobiletools/contacts/helpers/DBHelper.kt | 10 ++++++++-- 6 files changed, 18 insertions(+), 9 deletions(-) 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 3b8b0092..814096f4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -119,7 +119,7 @@ class EditContactActivity : ContactActivity() { } if (contactId != 0) { - contact = ContactsHelper(this).getContactWithId(contactId) + contact = ContactsHelper(this).getContactWithId(contactId, intent.getBooleanExtra(IS_PRIVATE, false)) if (contact == null) { toast(R.string.unknown_error_occurred) finish() diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt index c86ee0c6..417ff0d7 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt @@ -76,7 +76,7 @@ class ViewContactActivity : ContactActivity() { } if (contactId != 0) { - contact = ContactsHelper(this).getContactWithId(contactId) + contact = ContactsHelper(this).getContactWithId(contactId, intent.getBooleanExtra(IS_PRIVATE, false)) if (contact == null) { toast(R.string.unknown_error_occurred) finish() diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt index 3e1f947f..b855371d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt @@ -15,9 +15,7 @@ import com.simplemobiletools.contacts.BuildConfig import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.activities.EditContactActivity import com.simplemobiletools.contacts.activities.ViewContactActivity -import com.simplemobiletools.contacts.helpers.CONTACT_ID -import com.simplemobiletools.contacts.helpers.Config -import com.simplemobiletools.contacts.helpers.DBHelper +import com.simplemobiletools.contacts.helpers.* import com.simplemobiletools.contacts.models.Contact import java.io.File @@ -28,6 +26,7 @@ val Context.dbHelper: DBHelper get() = DBHelper.newInstance(applicationContext) fun Context.viewContact(contact: Contact) { Intent(applicationContext, ViewContactActivity::class.java).apply { putExtra(CONTACT_ID, contact.id) + putExtra(IS_PRIVATE, contact.source == SMT_PRIVATE) startActivity(this) } } @@ -35,6 +34,7 @@ fun Context.viewContact(contact: Contact) { fun Context.editContact(contact: Contact) { Intent(applicationContext, EditContactActivity::class.java).apply { putExtra(CONTACT_ID, contact.id) + putExtra(IS_PRIVATE, contact.source == SMT_PRIVATE) startActivity(this) } } 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 c8dbce1b..be179078 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt @@ -14,7 +14,8 @@ const val LOCAL_ACCOUNT_TYPE = "local_account_type" const val ON_CONTACT_CLICK = "on_contact_click" const val CONTACT_ID = "contact_id" -const val SMT_PRIVATE = "smt_private" +const val SMT_PRIVATE = "smt_private" // used at the contact source of local contacts hidden from other apps +const val IS_PRIVATE = "is_private" // contact photo changes const val PHOTO_ADDED = 1 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 a75b083b..c245632a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -198,9 +198,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return events } - fun getContactWithId(id: Int): Contact? { + fun getContactWithId(id: Int, isLocalPrivate: Boolean): Contact? { if (id == 0) { return null + } else if (isLocalPrivate) { + return activity.dbHelper.getContactWithId(id) } val uri = ContactsContract.Data.CONTENT_URI 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 5fb4a703..8efa77ed 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -73,10 +73,10 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont } } - fun getContacts(): ArrayList { + fun getContacts(selection: String? = null, selectionArgs: Array? = null): ArrayList { val contacts = ArrayList() val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED) - val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, null, null, null, null, null) + val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, selection, selectionArgs, null, null, null) cursor.use { while (cursor.moveToNext()) { val id = cursor.getIntValue(COL_ID) @@ -103,4 +103,10 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont } return contacts } + + fun getContactWithId(id: Int): Contact? { + val selection = "$COL_ID = ?" + val selectionArgs = arrayOf(id.toString()) + return getContacts(selection, selectionArgs).firstOrNull() + } } From dc43fb93f89c677b1f3f86cb73678443ef3bbedf Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 20:50:08 +0100 Subject: [PATCH 07/53] add handling for updating local private contacts --- .../simplemobiletools/contacts/helpers/ContactsHelper.kt | 4 +++- .../com/simplemobiletools/contacts/helpers/DBHelper.kt | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) 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 c245632a..d533380f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -328,7 +328,9 @@ class ContactsHelper(val activity: BaseSimpleActivity) { } fun updateContact(contact: Contact, photoUpdateStatus: Int): Boolean { - return try { + return if (contact.source == SMT_PRIVATE) { + activity.dbHelper.update(contact) + } else try { activity.toast(R.string.updating) val operations = ArrayList() ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI).apply { 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 8efa77ed..9343a4e0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -61,6 +61,13 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont return id != -1 } + fun update(contact: Contact): Boolean { + val contactValues = fillContactValues(contact) + val selection = "$COL_ID = ?" + val selectionArgs = arrayOf(contact.id.toString()) + return mDb.update(CONTACTS_TABLE_NAME, contactValues, selection, selectionArgs) == 1 + } + private fun fillContactValues(contact: Contact): ContentValues { return ContentValues().apply { put(COL_FIRST_NAME, contact.firstName) From 062ee8a6d40fce90f05e94d98596b0fb8b224c14 Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 21:03:19 +0100 Subject: [PATCH 08/53] properly update the View screen if a number/email/event was removed --- .../activities/ViewContactActivity.kt | 54 +++++++------------ .../main/res/layout/activity_view_contact.xml | 18 ++----- 2 files changed, 22 insertions(+), 50 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt index 417ff0d7..8ba8ba9d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt @@ -154,17 +154,13 @@ class ViewContactActivity : ContactActivity() { } private fun setupPhoneNumbers() { + contact_numbers_holder.removeAllViews() val phoneNumbers = contact!!.phoneNumbers - phoneNumbers.forEachIndexed { index, number -> - var numberHolder = contact_numbers_holder.getChildAt(index) - if (numberHolder == null) { - numberHolder = layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false) - contact_numbers_holder.addView(numberHolder) - } - - numberHolder!!.apply { - contact_number.text = number.value - setupPhoneNumberTypePicker(contact_number_type, number.type) + phoneNumbers.forEach { + layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false).apply { + contact_numbers_holder.addView(this) + contact_number.text = it.value + setupPhoneNumberTypePicker(contact_number_type, it.type) } } @@ -173,17 +169,13 @@ class ViewContactActivity : ContactActivity() { } private fun setupEmails() { + contact_emails_holder.removeAllViews() val emails = contact!!.emails - emails.forEachIndexed { index, email -> - var emailHolder = contact_emails_holder.getChildAt(index) - if (emailHolder == null) { - emailHolder = layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false) - contact_emails_holder.addView(emailHolder) - } - - emailHolder!!.apply { - contact_email.text = email.value - setupEmailTypePicker(contact_email_type, email.type) + emails.forEach { + layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false).apply { + contact_emails_holder.addView(this) + contact_email.text = it.value + setupEmailTypePicker(contact_email_type, it.type) } } @@ -192,22 +184,14 @@ class ViewContactActivity : ContactActivity() { } private fun setupEvents() { + contact_events_holder.removeAllViews() val events = contact!!.events - events.forEachIndexed { index, event -> - var eventHolder = contact_events_holder.getChildAt(index) - if (eventHolder == null) { - eventHolder = layoutInflater.inflate(R.layout.item_event, contact_events_holder, false) - contact_events_holder.addView(eventHolder) - } - - (eventHolder as ViewGroup).apply { - contact_event.apply { - getDateTime(event.value, this) - tag = event.value - alpha = 1f - } - - setupEventTypePicker(this, event.type) + events.forEach { + layoutInflater.inflate(R.layout.item_event, contact_events_holder, false).apply { + contact_events_holder.addView(this) + contact_event.alpha = 1f + getDateTime(it.value, contact_event) + setupEventTypePicker(this as ViewGroup, it.type) contact_event_remove.beGone() } } diff --git a/app/src/main/res/layout/activity_view_contact.xml b/app/src/main/res/layout/activity_view_contact.xml index 16e0ea48..457aea55 100644 --- a/app/src/main/res/layout/activity_view_contact.xml +++ b/app/src/main/res/layout/activity_view_contact.xml @@ -154,11 +154,7 @@ android:layout_below="@+id/contact_surname" android:layout_toRightOf="@+id/contact_number_image" android:orientation="vertical" - android:paddingLeft="@dimen/small_margin"> - - - - + android:paddingLeft="@dimen/small_margin"/> - - - - + android:paddingLeft="@dimen/small_margin"/> - - - - + android:orientation="vertical"/> Date: Sun, 11 Feb 2018 21:17:24 +0100 Subject: [PATCH 09/53] handle deleting local private contacts --- .../contacts/helpers/ContactsHelper.kt | 13 +++++++++++-- .../simplemobiletools/contacts/helpers/DBHelper.kt | 9 +++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) 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 d533380f..a70ab7aa 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -639,14 +639,23 @@ class ContactsHelper(val activity: BaseSimpleActivity) { } } - fun deleteContact(contact: Contact) = deleteContacts(arrayListOf(contact)) + fun deleteContact(contact: Contact) { + if (contact.source == SMT_PRIVATE) { + activity.dbHelper.deleteContact(contact.id) + } else { + deleteContacts(arrayListOf(contact)) + } + } fun deleteContacts(contacts: ArrayList) { + val localContacts = contacts.filter { it.source == SMT_PRIVATE }.map { it.id.toString() }.toTypedArray() + activity.dbHelper.deleteContacts(localContacts) + try { val contactIDs = HashSet() val operations = ArrayList() val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ?" - contacts.forEach { + contacts.filter { it.source != SMT_PRIVATE }.forEach { ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply { val selectionArgs = arrayOf(it.id.toString()) withSelection(selection, selectionArgs) 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 9343a4e0..59a8148b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -4,6 +4,7 @@ import android.content.ContentValues import android.content.Context import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper +import android.text.TextUtils import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.simplemobiletools.commons.extensions.getIntValue @@ -68,6 +69,14 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont return mDb.update(CONTACTS_TABLE_NAME, contactValues, selection, selectionArgs) == 1 } + fun deleteContact(id: Int) = deleteContacts(arrayOf(id.toString())) + + fun deleteContacts(ids: Array) { + val args = TextUtils.join(", ", ids) + val selection = "$CONTACTS_TABLE_NAME.$COL_ID IN ($args)" + mDb.delete(CONTACTS_TABLE_NAME, selection, null) + } + private fun fillContactValues(contact: Contact): ContentValues { return ContentValues().apply { put(COL_FIRST_NAME, contact.firstName) From 0651a49cd1b55c286535e7ff0fb8c598af6fa3c2 Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 21:45:25 +0100 Subject: [PATCH 10/53] properly handle Favorite toggling of local private contacts --- .../contacts/adapters/ContactsAdapter.kt | 8 +++---- .../contacts/dialogs/AddFavoritesDialog.kt | 7 +++--- .../contacts/helpers/ContactsHelper.kt | 22 +++++++++++++------ .../contacts/helpers/DBHelper.kt | 9 ++++++++ 4 files changed, 30 insertions(+), 16 deletions(-) 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 9d49925e..681f1d27 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt @@ -145,9 +145,7 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList() - favoritesToRemove.mapTo(favoriteIDsToRemove, { it.contactId.toString() }) - ContactsHelper(activity).removeFavorites(favoriteIDsToRemove) + ContactsHelper(activity).removeFavorites(favoritesToRemove) if (contactItems.isEmpty()) { listener?.refreshFavorites() finishActMode() @@ -161,8 +159,8 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList() - selectedPositions.forEach { newFavorites.add(contactItems[it].contactId.toString()) } + val newFavorites = ArrayList() + selectedPositions.forEach { newFavorites.add(contactItems[it]) } ContactsHelper(activity).addFavorites(newFavorites) listener?.refreshFavorites() finishActMode() diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/AddFavoritesDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/AddFavoritesDialog.kt index f31f0c4a..e0992e10 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/AddFavoritesDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/AddFavoritesDialog.kt @@ -59,12 +59,11 @@ class AddFavoritesDialog(val activity: SimpleActivity, private val callback: () val allDisplayedContacts = ArrayList() allContacts.mapTo(allDisplayedContacts, { it }) val selectedContacts = (view?.select_contact_list?.adapter as? SelectContactsAdapter)?.getSelectedItemsSet() ?: LinkedHashSet() - val contactIDsToAdd = selectedContacts.map { it.contactId.toString() } as ArrayList - contactsHelper.addFavorites(contactIDsToAdd) + val contactsToAdd = selectedContacts.map { it } as ArrayList + contactsHelper.addFavorites(contactsToAdd) allDisplayedContacts.removeAll(selectedContacts) - val contactIDsToRemove = allDisplayedContacts.map { it.contactId.toString() } as ArrayList - contactsHelper.removeFavorites(contactIDsToRemove) + contactsHelper.removeFavorites(allDisplayedContacts) callback() dialog?.dismiss() 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 a70ab7aa..cef49fb6 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -610,24 +610,27 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return "" } - fun addFavorites(ids: ArrayList) { - toggleFavorites(ids, true) + fun addFavorites(contacts: ArrayList) { + toggleLocalFavorites(contacts, true) + toggleFavorites(contacts, true) } - fun removeFavorites(ids: ArrayList) { - toggleFavorites(ids, false) + fun removeFavorites(contacts: ArrayList) { + toggleLocalFavorites(contacts, false) + toggleFavorites(contacts, false) } - private fun toggleFavorites(ids: ArrayList, areFavorites: Boolean) { + private fun toggleFavorites(contacts: ArrayList, addToFavorites: Boolean) { val applyBatchSize = 100 try { val operations = ArrayList() - ids.forEach { + contacts.filter { it.source != SMT_PRIVATE }.map { it.contactId.toString() }.forEach { val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, it) ContentProviderOperation.newUpdate(uri).apply { - withValue(ContactsContract.Contacts.STARRED, if (areFavorites) 1 else 0) + withValue(ContactsContract.Contacts.STARRED, if (addToFavorites) 1 else 0) operations.add(build()) } + if (operations.size % applyBatchSize == 0) { activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations) operations.clear() @@ -639,6 +642,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) { } } + private fun toggleLocalFavorites(contacts: ArrayList, addToFavorites: Boolean) { + val localContacts = contacts.filter { it.source == SMT_PRIVATE }.map { it.id.toString() }.toTypedArray() + activity.dbHelper.toggleFavorites(localContacts, addToFavorites) + } + fun deleteContact(contact: Contact) { if (contact.source == SMT_PRIVATE) { activity.dbHelper.deleteContact(contact.id) 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 59a8148b..10ebc310 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -89,6 +89,15 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont } } + fun toggleFavorites(ids: Array, addToFavorites: Boolean) { + val contactValues = ContentValues() + contactValues.put(COL_STARRED, if (addToFavorites) 1 else 0) + + val args = TextUtils.join(", ", ids) + val selection = "$COL_ID IN ($args)" + mDb.update(CONTACTS_TABLE_NAME, contactValues, selection, null) + } + fun getContacts(selection: String? = null, selectionArgs: Array? = null): ArrayList { val contacts = ArrayList() val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED) From 192658c0d38cefe4857fe0f54f8eda7365c6bb4c Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 21:55:36 +0100 Subject: [PATCH 11/53] properly handle exporting/importing local private contacts --- .../simplemobiletools/contacts/dialogs/ExportContactsDialog.kt | 3 ++- .../simplemobiletools/contacts/dialogs/ImportContactsDialog.kt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ExportContactsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ExportContactsDialog.kt index d59ada5d..30181648 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ExportContactsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ExportContactsDialog.kt @@ -8,6 +8,7 @@ import com.simplemobiletools.contacts.activities.SimpleActivity import com.simplemobiletools.contacts.adapters.FilterContactSourcesAdapter import com.simplemobiletools.contacts.extensions.config import com.simplemobiletools.contacts.helpers.ContactsHelper +import com.simplemobiletools.contacts.helpers.SMT_PRIVATE import com.simplemobiletools.contacts.models.ContactSource import kotlinx.android.synthetic.main.dialog_export_contacts.view.* import java.io.File @@ -48,7 +49,7 @@ class ExportContactsDialog(val activity: SimpleActivity, val path: String, priva val selectedIndexes = (view.export_contacts_list.adapter as FilterContactSourcesAdapter).getSelectedItemsSet() val selectedContactSources = HashSet() selectedIndexes.forEach { - selectedContactSources.add(contactSources[it].name) + selectedContactSources.add(if (contactSources[it].type == SMT_PRIVATE) SMT_PRIVATE else contactSources[it].name) } callback(file, selectedContactSources) dismiss() diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ImportContactsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ImportContactsDialog.kt index 5c872afe..8f2ed22f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ImportContactsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ImportContactsDialog.kt @@ -9,6 +9,7 @@ import com.simplemobiletools.contacts.activities.SimpleActivity import com.simplemobiletools.contacts.extensions.config import com.simplemobiletools.contacts.extensions.getPublicContactSource import com.simplemobiletools.contacts.extensions.showContactSourcePicker +import com.simplemobiletools.contacts.helpers.SMT_PRIVATE import com.simplemobiletools.contacts.helpers.VcfImporter import com.simplemobiletools.contacts.helpers.VcfImporter.ImportResult.IMPORT_FAIL import kotlinx.android.synthetic.main.dialog_import_contacts.view.* @@ -22,7 +23,7 @@ class ImportContactsDialog(val activity: SimpleActivity, val path: String, priva import_contacts_title.text = activity.getPublicContactSource(targetContactSource) import_contacts_title.setOnClickListener { activity.showContactSourcePicker(targetContactSource) { - targetContactSource = it + targetContactSource = if (it == activity.getString(R.string.phone_storage_hidden)) SMT_PRIVATE else it import_contacts_title.text = activity.getPublicContactSource(it) } } From 0b9b1b7f1a09c91879b2bafd4fdc744d04b176ad Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 23:24:16 +0100 Subject: [PATCH 12/53] properly handle displaying local private photos --- app/build.gradle | 2 +- .../contacts/activities/ContactActivity.kt | 6 ++-- .../activities/EditContactActivity.kt | 8 ++--- .../activities/ViewContactActivity.kt | 4 +-- .../contacts/adapters/ContactsAdapter.kt | 28 ++++++++++----- .../contacts/extensions/Bitmap.kt | 15 ++++++++ .../contacts/extensions/Context.kt | 15 ++++++++ .../contacts/helpers/ContactsHelper.kt | 33 ++++++----------- .../contacts/helpers/DBHelper.kt | 36 +++++++++++++++++-- .../contacts/helpers/VcfImporter.kt | 2 +- .../contacts/models/Contact.kt | 3 +- 11 files changed, 106 insertions(+), 46 deletions(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Bitmap.kt diff --git a/app/build.gradle b/app/build.gradle index ab8a2dea..09d798c5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -45,7 +45,7 @@ ext { } dependencies { - implementation 'com.simplemobiletools:commons:3.11.3' + implementation 'com.simplemobiletools:commons:3.11.5' implementation 'joda-time:joda-time:2.9.9' implementation 'com.facebook.stetho:stetho:1.5.0' implementation 'com.google.code.gson:gson:2.8.2' diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt index 01f9ff0e..0df9d306 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt @@ -1,5 +1,6 @@ package com.simplemobiletools.contacts.activities +import android.graphics.Bitmap import android.graphics.drawable.Drawable import android.provider.ContactsContract import android.widget.ImageView @@ -41,16 +42,17 @@ abstract class ContactActivity : SimpleActivity() { photoView.setPadding(padding, padding, padding, padding) photoView.setImageBitmap(placeholder) currentContactPhotoPath = "" + contact!!.photo = null } - fun updateContactPhoto(path: String, photoView: ImageView) { + fun updateContactPhoto(path: String, photoView: ImageView, bitmap: Bitmap? = null) { currentContactPhotoPath = path val options = RequestOptions() .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .centerCrop() Glide.with(this) - .load(path) + .load(bitmap ?: path) .transition(DrawableTransitionOptions.withCrossFade()) .apply(options) .listener(object : RequestListener { 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 814096f4..479acb66 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -146,10 +146,10 @@ class EditContactActivity : ContactActivity() { contact_photo.background = ColorDrawable(config.primaryColor) - if (contact!!.photoUri.isEmpty()) { + if (contact!!.photoUri.isEmpty() && contact!!.photo == null) { showPhotoPlaceholder(contact_photo) } else { - updateContactPhoto(contact!!.photoUri, contact_photo) + updateContactPhoto(contact!!.photoUri, contact_photo, contact!!.photo) } val textColor = config.textColor @@ -283,7 +283,7 @@ class EditContactActivity : ContactActivity() { private fun setupNewContact() { window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) supportActionBar?.title = resources.getString(R.string.new_contact) - contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "") + contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "", null) contact_source.text = getPublicContactSource(contact!!.source) contact_source.setOnClickListener { showContactSourcePicker(contact!!.source) { @@ -577,7 +577,7 @@ class EditContactActivity : ContactActivity() { RadioItem(CHOOSE_PHOTO, getString(R.string.choose_photo)) ) - if (currentContactPhotoPath.isNotEmpty()) { + if (currentContactPhotoPath.isNotEmpty() || contact!!.photo != null) { items.add(RadioItem(REMOVE_PHOTO, getString(R.string.remove_photo))) } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt index 8ba8ba9d..61530bbc 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt @@ -98,10 +98,10 @@ class ViewContactActivity : ContactActivity() { contact_photo.background = ColorDrawable(config.primaryColor) - if (contact!!.photoUri.isEmpty()) { + if (contact!!.photoUri.isEmpty() && contact!!.photo == null) { showPhotoPlaceholder(contact_photo) } else { - updateContactPhoto(contact!!.photoUri, contact_photo) + updateContactPhoto(contact!!.photoUri, contact_photo, contact!!.photo) } val textColor = config.textColor 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 681f1d27..59f61dc4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt @@ -199,16 +199,26 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList { + val options = RequestOptions() + .signature(ObjectKey(contact.photoUri)) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .error(contactDrawable) + .centerCrop() - Glide.with(activity).load(contact.photoUri).transition(DrawableTransitionOptions.withCrossFade()).apply(options).into(contact_tmb) - } else { - contact_tmb.setImageDrawable(contactDrawable) + Glide.with(activity).load(contact.photoUri).transition(DrawableTransitionOptions.withCrossFade()).apply(options).into(contact_tmb) + } + contact.photo != null -> { + val options = RequestOptions() + .signature(ObjectKey(contact.photo!!)) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .error(contactDrawable) + .centerCrop() + + Glide.with(activity).load(contact.photo).transition(DrawableTransitionOptions.withCrossFade()).apply(options).into(contact_tmb) + } + else -> contact_tmb.setImageDrawable(contactDrawable) } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Bitmap.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Bitmap.kt new file mode 100644 index 00000000..55983f24 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Bitmap.kt @@ -0,0 +1,15 @@ +package com.simplemobiletools.contacts.extensions + +import android.graphics.Bitmap +import java.io.ByteArrayOutputStream + +fun Bitmap.getByteArray(): ByteArray { + var baos: ByteArrayOutputStream? = null + try { + baos = ByteArrayOutputStream() + compress(Bitmap.CompressFormat.JPEG, 80, baos) + return baos.toByteArray() + } finally { + baos?.close() + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt index b855371d..19d18f9b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt @@ -128,3 +128,18 @@ fun Context.getCachePhoto(): File { } fun Context.getCachePhotoUri(file: File = getCachePhoto()) = FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.provider", file) + +fun Context.getPhotoThumbnailSize(): Int { + val uri = ContactsContract.DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI + val projection = arrayOf(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM) + var cursor: Cursor? = null + try { + cursor = contentResolver.query(uri, projection, null, null, null) + if (cursor?.moveToFirst() == true) { + return cursor.getIntValue(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM) + } + } finally { + cursor?.close() + } + return 0 +} 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 cef49fb6..4ba069b1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -23,6 +23,8 @@ import com.simplemobiletools.commons.helpers.SORT_DESCENDING import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.extensions.config import com.simplemobiletools.contacts.extensions.dbHelper +import com.simplemobiletools.contacts.extensions.getByteArray +import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize import com.simplemobiletools.contacts.models.* import java.io.ByteArrayOutputStream import java.util.* @@ -54,7 +56,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, events, accountName, starred, contactId, thumbnailUri) + val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, events, accountName, starred, contactId, thumbnailUri, null) contacts.put(id, contact) } while (cursor.moveToNext()) } @@ -224,7 +226,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - return Contact(id, firstName, middleName, surname, photoUri, number, emails, events, accountName, starred, contactId, thumbnailUri) + return Contact(id, firstName, middleName, surname, photoUri, number, emails, events, accountName, starred, contactId, thumbnailUri, null) } } finally { cursor?.close() @@ -429,12 +431,12 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val photoUri = Uri.parse(contact.photoUri) val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, photoUri) - val thumbnailSize = getThumbnailSize() + val thumbnailSize = activity.getPhotoThumbnailSize() val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false) - val scaledSizePhotoData = bitmapToByteArray(scaledPhoto) + val scaledSizePhotoData = scaledPhoto.getByteArray() scaledPhoto.recycle() - val fullSizePhotoData = bitmapToByteArray(bitmap) + val fullSizePhotoData = bitmap.getByteArray() bitmap.recycle() ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply { @@ -522,11 +524,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val photoUri = Uri.parse(contact.photoUri) val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, photoUri) - val thumbnailSize = getThumbnailSize() + val thumbnailSize = activity.getPhotoThumbnailSize() val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false) - scaledSizePhotoData = bitmapToByteArray(scaledPhoto) + scaledSizePhotoData = scaledPhoto.getByteArray() - fullSizePhotoData = bitmapToByteArray(bitmap) + fullSizePhotoData = bitmap.getByteArray() scaledPhoto.recycle() bitmap.recycle() @@ -677,19 +679,4 @@ class ContactsHelper(val activity: BaseSimpleActivity) { activity.showErrorToast(e) } } - - private fun getThumbnailSize(): Int { - val uri = ContactsContract.DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI - val projection = arrayOf(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM) - var cursor: Cursor? = null - try { - cursor = activity.contentResolver.query(uri, projection, null, null, null) - if (cursor?.moveToFirst() == true) { - return cursor.getIntValue(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM) - } - } finally { - cursor?.close() - } - return 0 - } } 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 10ebc310..126316b0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -4,17 +4,23 @@ import android.content.ContentValues import android.content.Context import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.net.Uri +import android.provider.MediaStore import android.text.TextUtils import com.google.gson.Gson import com.google.gson.reflect.TypeToken +import com.simplemobiletools.commons.extensions.getBlobValue import com.simplemobiletools.commons.extensions.getIntValue import com.simplemobiletools.commons.extensions.getStringValue +import com.simplemobiletools.contacts.extensions.getByteArray +import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize import com.simplemobiletools.contacts.models.Contact import com.simplemobiletools.contacts.models.Email import com.simplemobiletools.contacts.models.Event import com.simplemobiletools.contacts.models.PhoneNumber - class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { private val CONTACTS_TABLE_NAME = "contacts" private val COL_ID = "id" @@ -86,9 +92,26 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont put(COL_EMAILS, Gson().toJson(contact.emails)) put(COL_EVENTS, Gson().toJson(contact.events)) put(COL_STARRED, contact.starred) + + if (contact.photoUri.isNotEmpty()) { + put(COL_PHOTO, getPhotoByteArray(contact.photoUri)) + } else if (contact.photo == null) { + putNull(COL_PHOTO) + } } } + private fun getPhotoByteArray(uri: String): ByteArray { + val photoUri = Uri.parse(uri) + val bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, photoUri) + + val thumbnailSize = context.getPhotoThumbnailSize() + val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false) + val scaledSizePhotoData = scaledPhoto.getByteArray() + scaledPhoto.recycle() + return scaledSizePhotoData + } + fun toggleFavorites(ids: Array, addToFavorites: Boolean) { val contactValues = ContentValues() contactValues.put(COL_STARRED, if (addToFavorites) 1 else 0) @@ -100,7 +123,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont fun getContacts(selection: String? = null, selectionArgs: Array? = null): ArrayList { val contacts = ArrayList() - val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED) + val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED, COL_PHOTO) val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, selection, selectionArgs, null, null, null) cursor.use { while (cursor.moveToNext()) { @@ -121,8 +144,15 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont val eventsToken = object : TypeToken>() {}.type val events = Gson().fromJson>(eventsJson, eventsToken) ?: ArrayList(1) + val photoByteArray = cursor.getBlobValue(COL_PHOTO) ?: null + val photo = if (photoByteArray?.isNotEmpty() == true) { + BitmapFactory.decodeByteArray(photoByteArray, 0, photoByteArray.size) + } else { + null + } + val starred = cursor.getIntValue(COL_STARRED) - val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, events, SMT_PRIVATE, starred, id, "") + val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, events, SMT_PRIVATE, starred, id, "", photo) contacts.add(contact) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt index 5d991428..c69a5402 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt @@ -199,7 +199,7 @@ class VcfImporter(val activity: SimpleActivity) { } private fun saveContact(source: String) { - val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curEvents, source, 0, 0, "") + val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curEvents, source, 0, 0, "", null) if (ContactsHelper(activity).insertContact(contact)) { contactsImported++ } 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 b41e6e6b..f98b9770 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt @@ -1,12 +1,13 @@ package com.simplemobiletools.contacts.models +import android.graphics.Bitmap import com.simplemobiletools.commons.helpers.SORT_BY_FIRST_NAME import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME import com.simplemobiletools.commons.helpers.SORT_DESCENDING data class Contact(val id: Int, var firstName: String, var middleName: String, var surname: String, var photoUri: String, var phoneNumbers: ArrayList, var emails: ArrayList, var events: ArrayList, var source: String, - var starred: Int, val contactId: Int, val thumbnailUri: String) : Comparable { + var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?) : Comparable { companion object { var sorting = 0 } From 1be6264cf41b1efd86cf4688e760f6a6dc929f2e Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 23:26:18 +0100 Subject: [PATCH 13/53] increase the resolution of local images for a bit better quality --- .../kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 126316b0..52255721 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -106,7 +106,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont val bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, photoUri) val thumbnailSize = context.getPhotoThumbnailSize() - val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false) + val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize * 2, thumbnailSize * 2, false) val scaledSizePhotoData = scaledPhoto.getByteArray() scaledPhoto.recycle() return scaledSizePhotoData From 3af55404a2ab7f85c0c2b58b74ed47cb023376b6 Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 23:41:53 +0100 Subject: [PATCH 14/53] properly export local private photos in .vcf files --- .../contacts/helpers/VcfExporter.kt | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt index 85fa0bec..a7c4994b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt @@ -11,6 +11,7 @@ import com.simplemobiletools.commons.extensions.showErrorToast import com.simplemobiletools.commons.extensions.writeLn import com.simplemobiletools.contacts.helpers.VcfExporter.ExportResult.* import com.simplemobiletools.contacts.models.Contact +import java.io.BufferedWriter import java.io.ByteArrayOutputStream import java.io.File @@ -55,24 +56,12 @@ class VcfExporter { } if (contact.thumbnailUri.isNotEmpty()) { - val firstLine = "$PHOTO;$ENCODING=$BASE64;$JPEG:" val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, Uri.parse(contact.thumbnailUri)) - val byteArrayOutputStream = ByteArrayOutputStream() - bitmap.compress(Bitmap.CompressFormat.JPEG, 85, byteArrayOutputStream) - bitmap.recycle() - val byteArray = byteArrayOutputStream.toByteArray() - val encoded = Base64.encodeToString(byteArray, Base64.NO_WRAP) + addBitmap(bitmap, out) + } - val encodedFirstLineSection = encoded.substring(0, ENCODED_PHOTO_LINE_LENGTH - firstLine.length) - out.writeLn(firstLine + encodedFirstLineSection) - var curStartIndex = encodedFirstLineSection.length - do { - val part = encoded.substring(curStartIndex, Math.min(curStartIndex + ENCODED_PHOTO_LINE_LENGTH - 1, encoded.length)) - out.writeLn(" $part") - curStartIndex += ENCODED_PHOTO_LINE_LENGTH - 1 - } while (curStartIndex < encoded.length) - - out.writeLn("") + if (contact.photo != null) { + addBitmap(contact.photo!!, out) } out.writeLn(END_VCARD) @@ -91,6 +80,26 @@ class VcfExporter { }) } + private fun addBitmap(bitmap: Bitmap, out: BufferedWriter) { + val firstLine = "$PHOTO;$ENCODING=$BASE64;$JPEG:" + val byteArrayOutputStream = ByteArrayOutputStream() + bitmap.compress(Bitmap.CompressFormat.JPEG, 85, byteArrayOutputStream) + bitmap.recycle() + val byteArray = byteArrayOutputStream.toByteArray() + val encoded = Base64.encodeToString(byteArray, Base64.NO_WRAP) + + val encodedFirstLineSection = encoded.substring(0, ENCODED_PHOTO_LINE_LENGTH - firstLine.length) + out.writeLn(firstLine + encodedFirstLineSection) + var curStartIndex = encodedFirstLineSection.length + do { + val part = encoded.substring(curStartIndex, Math.min(curStartIndex + ENCODED_PHOTO_LINE_LENGTH - 1, encoded.length)) + out.writeLn(" $part") + curStartIndex += ENCODED_PHOTO_LINE_LENGTH - 1 + } while (curStartIndex < encoded.length) + + out.writeLn("") + } + private fun getNames(contact: Contact): String { var result = "" var firstName = contact.firstName From d655aaff13a9e7c9341cc3324722c511f181aab1 Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 23:49:43 +0100 Subject: [PATCH 15/53] add the local private database in release notes --- .../contacts/activities/MainActivity.kt | 9 +++++++++ app/src/main/res/values/donottranslate.xml | 7 +++++++ 2 files changed, 16 insertions(+) create mode 100644 app/src/main/res/values/donottranslate.xml 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 fec26748..72e3dea9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt @@ -14,6 +14,7 @@ import android.view.MenuItem import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* +import com.simplemobiletools.commons.models.Release import com.simplemobiletools.contacts.BuildConfig import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.adapters.ViewPagerAdapter @@ -69,6 +70,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener { } } storeStateVariables() + checkWhatsNewDialog() } override fun onResume() { @@ -384,4 +386,11 @@ class MainActivity : SimpleActivity(), RefreshContactsListener { override fun refreshFavorites() { favorites_fragment?.initContacts() } + + private fun checkWhatsNewDialog() { + arrayListOf().apply { + add(Release(10, R.string.release_10)) + checkWhatsNew(this, BuildConfig.VERSION_CODE) + } + } } diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml new file mode 100644 index 00000000..58053e11 --- /dev/null +++ b/app/src/main/res/values/donottranslate.xml @@ -0,0 +1,7 @@ + + + + + Allow storing contacts in a local database, hidden from other apps + + From 23867b60e8303f5076414d1490bfe79ce2735ff8 Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 23:49:51 +0100 Subject: [PATCH 16/53] update version to 3.2.0 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 09d798c5..1a1ce861 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.simplemobiletools.contacts" minSdkVersion 16 targetSdkVersion 27 - versionCode 9 - versionName "3.1.4" + versionCode 10 + versionName "3.2.0" setProperty("archivesBaseName", "contacts") } From 439e612d53b796d58a197dd562114fcf8de1b951 Mon Sep 17 00:00:00 2001 From: tibbi Date: Sun, 11 Feb 2018 23:49:59 +0100 Subject: [PATCH 17/53] updating changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cc26c16..17b4d282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Changelog ========== +Version 3.2.0 *(2018-02-11)* +---------------------------- + + * Allow storing contacts in a local database, hidden from other apps + * Added a new screen for viewing contact details + * Increased font size + Version 3.1.4 *(2018-02-03)* ---------------------------- From 92700e6382375ec3a063a9ff133fdb73eb8471cc Mon Sep 17 00:00:00 2001 From: en2sv Date: Sat, 17 Feb 2018 20:28:06 +0100 Subject: [PATCH 18/53] Update Swedish translation --- app/src/main/res/values-sv/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 73c90220..2d9fa6a1 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -4,8 +4,8 @@ Adress Lägger till… Uppdaterar… - Phone storage - Phone storage (not visible by other apps) + Telefonens lagringsutrymme + Telefonens lagringsutrymme (inte synligt för andra appar) Ny kontakt Redigera kontakt @@ -23,10 +23,10 @@ Visa efternamn först Visa telefonnummer i huvudvyn - Show contact thumbnails - On contact click - Call contact - View contact details + Visa kontaktminiatyrer + Vid kontakttryckning + Ring kontakt + Visa kontaktuppgifter E-post From 8a4c4f9324c5d424c796956aed73fc8f9be85412 Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 15:32:03 +0100 Subject: [PATCH 19/53] add some null checks at the fragments --- .../simplemobiletools/contacts/fragments/MyViewPagerFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f437ec88..a2517ff1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/fragments/MyViewPagerFragment.kt @@ -193,7 +193,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet) } fun onSearchClosed() { - (fragment_list.adapter as ContactsAdapter).updateItems(contactsIgnoringSearch) + (fragment_list.adapter as? ContactsAdapter)?.updateItems(contactsIgnoringSearch) if (this is FavoritesFragment) { fragment_placeholder.text = activity?.getString(R.string.no_favorites) } From 8dd3dd08cdb597f008ce71220cd2909e6ac9d3fb Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 15:33:35 +0100 Subject: [PATCH 20/53] add a null check at the contact in ContactActivity --- .../simplemobiletools/contacts/activities/ContactActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt index 0df9d306..a17d4f70 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt @@ -42,7 +42,7 @@ abstract class ContactActivity : SimpleActivity() { photoView.setPadding(padding, padding, padding, padding) photoView.setImageBitmap(placeholder) currentContactPhotoPath = "" - contact!!.photo = null + contact?.photo = null } fun updateContactPhoto(path: String, photoView: ImageView, bitmap: Bitmap? = null) { From bcdd8fe40f4be45554b6b3efc97e4be1e2f3069b Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 15:50:56 +0100 Subject: [PATCH 21/53] check if there is an available app for Crop before launching it --- .../contacts/activities/EditContactActivity.kt | 6 +++++- .../contacts/dialogs/ExportContactsDialog.kt | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) 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 479acb66..6d70b9f8 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -204,7 +204,11 @@ class EditContactActivity : ContactActivity() { putExtra("scaleUpIfNeeded", "true") clipData = ClipData("Attachment", arrayOf("text/uri-list"), ClipData.Item(lastPhotoIntentUri)) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - startActivityForResult(this, INTENT_CROP_PHOTO) + if (resolveActivity(packageManager) != null) { + startActivityForResult(this, INTENT_CROP_PHOTO) + } else { + toast(R.string.no_app_found) + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ExportContactsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ExportContactsDialog.kt index 30181648..7aedd1af 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ExportContactsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/dialogs/ExportContactsDialog.kt @@ -36,6 +36,10 @@ class ExportContactsDialog(val activity: SimpleActivity, val path: String, priva .create().apply { activity.setupDialogStuff(view, this, R.string.export_contacts) { getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { + if (view.export_contacts_list.adapter == null) { + return@setOnClickListener + } + val filename = view.export_contacts_filename.value when { filename.isEmpty() -> activity.toast(R.string.empty_name) From 74140b1665f5ea67eb0b4827f6b5ac8f5765ec77 Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 15:57:45 +0100 Subject: [PATCH 22/53] adding a null check at handling Edit Photo result --- .../contacts/activities/EditContactActivity.kt | 9 +++++++-- .../com/simplemobiletools/contacts/helpers/DBHelper.kt | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) 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 6d70b9f8..bb10ac81 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -94,7 +94,7 @@ class EditContactActivity : ContactActivity() { super.onActivityResult(requestCode, resultCode, resultData) if (resultCode == RESULT_OK) { when (requestCode) { - INTENT_TAKE_PHOTO, INTENT_CHOOSE_PHOTO -> startCropPhotoIntent(lastPhotoIntentUri!!) + INTENT_TAKE_PHOTO, INTENT_CHOOSE_PHOTO -> startCropPhotoIntent(lastPhotoIntentUri) INTENT_CROP_PHOTO -> updateContactPhoto(lastPhotoIntentUri.toString(), contact_photo) } } @@ -190,7 +190,12 @@ class EditContactActivity : ContactActivity() { invalidateOptionsMenu() } - private fun startCropPhotoIntent(uri: Uri) { + private fun startCropPhotoIntent(uri: Uri?) { + if (uri == null) { + toast(R.string.unknown_error_occurred) + return + } + lastPhotoIntentUri = getCachePhotoUri() Intent("com.android.camera.action.CROP").apply { setDataAndType(uri, "image/*") 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 52255721..f598e576 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -35,7 +35,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont private val FIRST_CONTACT_ID = 1000000 - private val mDb: SQLiteDatabase = writableDatabase + private val mDb = writableDatabase companion object { private const val DB_VERSION = 1 From 42eb8e460932147210824d9db838ae044d21da12 Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 16:05:23 +0100 Subject: [PATCH 23/53] update commons to 3.12.15 --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 5 +++++ .../simplemobiletools/contacts/activities/MainActivity.kt | 4 +++- .../com/simplemobiletools/contacts/extensions/Activity.kt | 6 ++---- .../kotlin/com/simplemobiletools/contacts/helpers/Config.kt | 6 ------ .../com/simplemobiletools/contacts/helpers/VcfExporter.kt | 3 ++- app/src/main/res/values/integers.xml | 3 +++ 7 files changed, 16 insertions(+), 13 deletions(-) create mode 100644 app/src/main/res/values/integers.xml diff --git a/app/build.gradle b/app/build.gradle index 1a1ce861..0584b78c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -45,7 +45,7 @@ ext { } dependencies { - implementation 'com.simplemobiletools:commons:3.11.5' + implementation 'com.simplemobiletools:commons:3.12.15' implementation 'joda-time:joda-time:2.9.9' implementation 'com.facebook.stetho:stetho:1.5.0' implementation 'com.google.code.gson:gson:2.8.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 99f7f95d..c3692df2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -172,6 +172,11 @@ android:label="@string/customize_colors" android:parentActivityName=".activities.SettingsActivity"/> + + ) { VcfExporter().exportContacts(this, file, contacts) { if (it == VcfExporter.ExportResult.EXPORT_OK) { - val uri = getFilePublicUri(file, BuildConfig.APPLICATION_ID) - shareUri(uri, BuildConfig.APPLICATION_ID) + sharePathIntent(file.absolutePath, BuildConfig.APPLICATION_ID) } } } 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 d34fbc68..f6613b07 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Config.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Config.kt @@ -2,18 +2,12 @@ package com.simplemobiletools.contacts.helpers import android.content.Context import com.simplemobiletools.commons.helpers.BaseConfig -import com.simplemobiletools.commons.helpers.SORTING -import com.simplemobiletools.commons.helpers.SORT_BY_FIRST_NAME class Config(context: Context) : BaseConfig(context) { companion object { fun newInstance(context: Context) = Config(context) } - var sorting: Int - get() = prefs.getInt(SORTING, SORT_BY_FIRST_NAME) - set(sorting) = prefs.edit().putInt(SORTING, sorting).apply() - 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() diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt index a7c4994b..793a8ccc 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt @@ -8,6 +8,7 @@ import android.util.Base64 import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.extensions.getFileOutputStream import com.simplemobiletools.commons.extensions.showErrorToast +import com.simplemobiletools.commons.extensions.toFileDirItem import com.simplemobiletools.commons.extensions.writeLn import com.simplemobiletools.contacts.helpers.VcfExporter.ExportResult.* import com.simplemobiletools.contacts.models.Contact @@ -27,7 +28,7 @@ class VcfExporter { fun exportContacts(activity: BaseSimpleActivity, file: File, contacts: ArrayList, callback: (result: ExportResult) -> Unit) { try { - activity.getFileOutputStream(file) { + activity.getFileOutputStream(file.toFileDirItem(activity)) { if (it == null) { callback(EXPORT_FAIL) return@getFileOutputStream diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml new file mode 100644 index 00000000..11ccda4a --- /dev/null +++ b/app/src/main/res/values/integers.xml @@ -0,0 +1,3 @@ + + 128 + From 08726093ec00b548b597137d83616b11a5050d3b Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 16:36:00 +0100 Subject: [PATCH 24/53] change isFirstResume only if we have the required permissions --- .../simplemobiletools/contacts/activities/MainActivity.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 c20fb24b..4181dc2c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt @@ -122,12 +122,16 @@ class MainActivity : SimpleActivity(), RefreshContactsListener { if (viewpager.adapter == null) { initFragments() } + contacts_fragment?.initContacts() contacts_fragment?.onActivityResume() favorites_fragment?.initContacts() favorites_fragment?.onActivityResume() } - isFirstResume = false + + if (hasPermission(PERMISSION_WRITE_CONTACTS)) { + isFirstResume = false + } } override fun onPause() { From ff3b1ab5ebd81f60d94faa111e2c0d9219febb80 Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 17:54:23 +0100 Subject: [PATCH 25/53] use our custom layout managers --- .../contacts/adapters/ContactsAdapter.kt | 20 ++++++------------- .../res/layout/dialog_export_contacts.xml | 2 +- .../layout/dialog_filter_contact_sources.xml | 2 +- app/src/main/res/layout/fragment_layout.xml | 2 +- .../main/res/layout/layout_select_contact.xml | 2 +- 5 files changed, 10 insertions(+), 18 deletions(-) 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 59f61dc4..0e539d54 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt @@ -27,7 +27,7 @@ import com.simplemobiletools.contacts.models.Contact import kotlinx.android.synthetic.main.item_contact_with_number.view.* import java.util.* -class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList, private val listener: RefreshContactsListener?, +class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList, private val listener: RefreshContactsListener?, private val isFavoritesFragment: Boolean, recyclerView: MyRecyclerView, fastScroller: FastScroller, itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) { @@ -66,6 +66,10 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList editContact() R.id.cab_select_all -> selectAll() @@ -97,7 +101,7 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList) { + fun updateItems(newItems: ArrayList) { contactItems = newItems notifyDataSetChanged() finishActMode() @@ -135,10 +139,6 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList() selectedPositions.sortedDescending().forEach { favoritesToRemove.add(contactItems[it]) @@ -155,10 +155,6 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList() selectedPositions.forEach { newFavorites.add(contactItems[it]) } ContactsHelper(activity).addFavorites(newFavorites) @@ -167,10 +163,6 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList() selectedPositions.forEach { contacts.add(contactItems[it]) diff --git a/app/src/main/res/layout/dialog_export_contacts.xml b/app/src/main/res/layout/dialog_export_contacts.xml index 0f053e06..e8bfc397 100644 --- a/app/src/main/res/layout/dialog_export_contacts.xml +++ b/app/src/main/res/layout/dialog_export_contacts.xml @@ -72,7 +72,7 @@ android:clipToPadding="false" android:overScrollMode="never" android:paddingTop="@dimen/medium_margin" - app:layoutManager="android.support.v7.widget.LinearLayoutManager"/> + app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/> diff --git a/app/src/main/res/layout/dialog_filter_contact_sources.xml b/app/src/main/res/layout/dialog_filter_contact_sources.xml index 4264f88b..432d7ff3 100644 --- a/app/src/main/res/layout/dialog_filter_contact_sources.xml +++ b/app/src/main/res/layout/dialog_filter_contact_sources.xml @@ -8,4 +8,4 @@ android:clipToPadding="false" android:overScrollMode="never" android:paddingTop="@dimen/medium_margin" - app:layoutManager="android.support.v7.widget.LinearLayoutManager"/> + app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/> diff --git a/app/src/main/res/layout/fragment_layout.xml b/app/src/main/res/layout/fragment_layout.xml index 029e3861..55e0a9ae 100644 --- a/app/src/main/res/layout/fragment_layout.xml +++ b/app/src/main/res/layout/fragment_layout.xml @@ -40,7 +40,7 @@ android:layout_height="match_parent" android:clipToPadding="false" android:scrollbars="none" - app:layoutManager="android.support.v7.widget.LinearLayoutManager"/> + app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/> + app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/> Date: Wed, 21 Feb 2018 18:46:42 +0100 Subject: [PATCH 26/53] update commons to 3.12.16 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 0584b78c..8c00a793 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -45,7 +45,7 @@ ext { } dependencies { - implementation 'com.simplemobiletools:commons:3.12.15' + implementation 'com.simplemobiletools:commons:3.12.16' implementation 'joda-time:joda-time:2.9.9' implementation 'com.facebook.stetho:stetho:1.5.0' implementation 'com.google.code.gson:gson:2.8.2' From d3498f96cb1703d1ae84153784dcc6a8ce8c5b43 Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 19:07:10 +0100 Subject: [PATCH 27/53] parse contact addresses --- .../contacts/activities/ContactActivity.kt | 6 +++ .../activities/EditContactActivity.kt | 8 ++- .../contacts/helpers/ContactsHelper.kt | 53 ++++++++++++++++++- .../contacts/helpers/DBHelper.kt | 9 ++-- .../contacts/helpers/VcfImporter.kt | 9 ++-- .../contacts/models/Address.kt | 3 ++ .../contacts/models/Contact.kt | 4 +- 7 files changed, 77 insertions(+), 15 deletions(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/contacts/models/Address.kt diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt index a17d4f70..998a7f80 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt @@ -159,4 +159,10 @@ abstract class ContactActivity : SimpleActivity() { ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY -> R.string.anniversary else -> R.string.other } + + fun getAddressTextId(type: Int) = when (type) { + ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME -> R.string.home + ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK -> R.string.work + else -> R.string.other + } } 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 bb10ac81..06d90f0e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -292,7 +292,7 @@ class EditContactActivity : ContactActivity() { private fun setupNewContact() { window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) supportActionBar?.title = resources.getString(R.string.new_contact) - contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "", null) + contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "", null) contact_source.text = getPublicContactSource(contact!!.source) contact_source.setOnClickListener { showContactSourcePicker(contact!!.source) { @@ -651,4 +651,10 @@ class EditContactActivity : ContactActivity() { getString(R.string.anniversary) -> CommonDataKinds.Event.TYPE_ANNIVERSARY else -> CommonDataKinds.Event.TYPE_OTHER } + + private fun getAddressTypeId(value: String) = when (value) { + getString(R.string.home) -> CommonDataKinds.StructuredPostal.TYPE_HOME + getString(R.string.work) -> CommonDataKinds.StructuredPostal.TYPE_WORK + else -> CommonDataKinds.StructuredPostal.TYPE_OTHER + } } 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 4ba069b1..1468f82b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -28,6 +28,7 @@ import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize import com.simplemobiletools.contacts.models.* import java.io.ByteArrayOutputStream import java.util.* +import kotlin.collections.ArrayList class ContactsHelper(val activity: BaseSimpleActivity) { fun getContacts(callback: (ArrayList) -> Unit) { @@ -52,11 +53,13 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val number = ArrayList() // proper value is obtained below val emails = ArrayList() val events = ArrayList() + val addresses = ArrayList
() val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: "" val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, events, accountName, starred, contactId, thumbnailUri, null) + val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, events, addresses, accountName, + starred, contactId, thumbnailUri, null) contacts.put(id, contact) } while (cursor.moveToNext()) } @@ -80,6 +83,13 @@ class ContactsHelper(val activity: BaseSimpleActivity) { contacts[key]?.emails = emails.valueAt(i) } + val addresses = getAddresses() + size = addresses.size() + for (i in 0 until size) { + val key = addresses.keyAt(i) + contacts[key]?.addresses = addresses.valueAt(i) + } + activity.dbHelper.getContacts().forEach { contacts.put(it.id, it) } @@ -200,6 +210,44 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return events } + private fun getAddresses(contactId: Int? = null): SparseArray> { + val addresses = SparseArray>() + val uri = CommonDataKinds.StructuredPostal.CONTENT_URI + val projection = arrayOf( + ContactsContract.Data.RAW_CONTACT_ID, + CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, + 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()) + + var cursor: Cursor? = null + try { + cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) + if (cursor?.moveToFirst() == true) { + do { + val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID) + val address = cursor.getStringValue(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS) + val type = cursor.getIntValue(CommonDataKinds.StructuredPostal.TYPE) + + if (addresses[id] == null) { + addresses.put(id, ArrayList()) + } + + addresses[id]!!.add(Address(address, type)) + } while (cursor.moveToNext()) + } + + } catch (e: Exception) { + activity.showErrorToast(e) + } finally { + cursor?.close() + } + + return addresses + } + fun getContactWithId(id: Int, isLocalPrivate: Boolean): Contact? { if (id == 0) { return null @@ -222,11 +270,12 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val number = getPhoneNumbers(id)[id] ?: ArrayList() val emails = getEmails(id)[id] ?: ArrayList() val events = getEvents(id)[id] ?: ArrayList() + val addresses = getAddresses(id)[id] ?: ArrayList() val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: "" val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - return Contact(id, firstName, middleName, surname, photoUri, number, emails, events, accountName, starred, contactId, thumbnailUri, null) + return Contact(id, firstName, middleName, surname, photoUri, number, emails, events, addresses, accountName, starred, contactId, thumbnailUri, null) } } finally { cursor?.close() 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 f598e576..615dfad9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -16,10 +16,7 @@ import com.simplemobiletools.commons.extensions.getIntValue import com.simplemobiletools.commons.extensions.getStringValue import com.simplemobiletools.contacts.extensions.getByteArray import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize -import com.simplemobiletools.contacts.models.Contact -import com.simplemobiletools.contacts.models.Email -import com.simplemobiletools.contacts.models.Event -import com.simplemobiletools.contacts.models.PhoneNumber +import com.simplemobiletools.contacts.models.* class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { private val CONTACTS_TABLE_NAME = "contacts" @@ -144,6 +141,8 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont val eventsToken = object : TypeToken>() {}.type val events = Gson().fromJson>(eventsJson, eventsToken) ?: ArrayList(1) + val addresses = ArrayList
() + val photoByteArray = cursor.getBlobValue(COL_PHOTO) ?: null val photo = if (photoByteArray?.isNotEmpty() == true) { BitmapFactory.decodeByteArray(photoByteArray, 0, photoByteArray.size) @@ -152,7 +151,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont } val starred = cursor.getIntValue(COL_STARRED) - val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, events, SMT_PRIVATE, starred, id, "", photo) + val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, events, addresses, SMT_PRIVATE, starred, id, "", photo) contacts.add(contact) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt index c69a5402..7244d247 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt @@ -10,10 +10,7 @@ import com.simplemobiletools.contacts.activities.SimpleActivity import com.simplemobiletools.contacts.extensions.getCachePhoto import com.simplemobiletools.contacts.extensions.getCachePhotoUri import com.simplemobiletools.contacts.helpers.VcfImporter.ImportResult.* -import com.simplemobiletools.contacts.models.Contact -import com.simplemobiletools.contacts.models.Email -import com.simplemobiletools.contacts.models.Event -import com.simplemobiletools.contacts.models.PhoneNumber +import com.simplemobiletools.contacts.models.* import java.io.File import java.io.FileOutputStream @@ -29,6 +26,7 @@ class VcfImporter(val activity: SimpleActivity) { private var curPhoneNumbers = ArrayList() private var curEmails = ArrayList() private var curEvents = ArrayList() + private var curAddresses = ArrayList
() private var isGettingPhoto = false private var currentPhotoString = StringBuilder() @@ -199,7 +197,7 @@ class VcfImporter(val activity: SimpleActivity) { } private fun saveContact(source: String) { - val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curEvents, source, 0, 0, "", null) + val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curEvents, curAddresses, source, 0, 0, "", null) if (ContactsHelper(activity).insertContact(contact)) { contactsImported++ } @@ -213,6 +211,7 @@ class VcfImporter(val activity: SimpleActivity) { curPhoneNumbers = ArrayList() curEmails = ArrayList() curEvents = ArrayList() + curAddresses = ArrayList() isGettingPhoto = false currentPhotoString = StringBuilder() diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/models/Address.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/models/Address.kt new file mode 100644 index 00000000..7571a228 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/models/Address.kt @@ -0,0 +1,3 @@ +package com.simplemobiletools.contacts.models + +data class Address(var value: String, var type: Int) 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 f98b9770..4bf94011 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt @@ -6,8 +6,8 @@ import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME import com.simplemobiletools.commons.helpers.SORT_DESCENDING data class Contact(val id: Int, var firstName: String, var middleName: String, var surname: String, var photoUri: String, - var phoneNumbers: ArrayList, var emails: ArrayList, var events: ArrayList, var source: String, - var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?) : Comparable { + var phoneNumbers: ArrayList, var emails: ArrayList, var events: ArrayList, var addresses: ArrayList
, + var source: String, var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?) : Comparable { companion object { var sorting = 0 } From 835d7bfde689b9cb02f4203d26631087b8c547a3 Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 19:48:55 +0100 Subject: [PATCH 28/53] flip addresses and events at the Contact model --- .../simplemobiletools/contacts/helpers/ContactsHelper.kt | 8 ++++---- .../com/simplemobiletools/contacts/helpers/DBHelper.kt | 6 +++--- .../com/simplemobiletools/contacts/helpers/VcfImporter.kt | 2 +- .../com/simplemobiletools/contacts/models/Contact.kt | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) 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 1468f82b..1b1e65f9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -52,13 +52,13 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val photoUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_URI) ?: "" val number = ArrayList() // proper value is obtained below val emails = ArrayList() - val events = ArrayList() val addresses = ArrayList
() + val events = ArrayList() val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: "" val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, events, addresses, accountName, + val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName, starred, contactId, thumbnailUri, null) contacts.put(id, contact) } while (cursor.moveToNext()) @@ -269,13 +269,13 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val photoUri = cursor.getStringValue(CommonDataKinds.Phone.PHOTO_URI) ?: "" val number = getPhoneNumbers(id)[id] ?: ArrayList() val emails = getEmails(id)[id] ?: ArrayList() - val events = getEvents(id)[id] ?: ArrayList() val addresses = getAddresses(id)[id] ?: ArrayList() + val events = getEvents(id)[id] ?: ArrayList() val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: "" val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - return Contact(id, firstName, middleName, surname, photoUri, number, emails, events, addresses, accountName, starred, contactId, thumbnailUri, null) + return Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName, starred, contactId, thumbnailUri, null) } } finally { cursor?.close() 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 615dfad9..11515eba 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -137,12 +137,12 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont val emailsToken = object : TypeToken>() {}.type val emails = Gson().fromJson>(emailsJson, emailsToken) ?: ArrayList(1) + val addresses = ArrayList
() + val eventsJson = cursor.getStringValue(COL_EVENTS) val eventsToken = object : TypeToken>() {}.type val events = Gson().fromJson>(eventsJson, eventsToken) ?: ArrayList(1) - val addresses = ArrayList
() - val photoByteArray = cursor.getBlobValue(COL_PHOTO) ?: null val photo = if (photoByteArray?.isNotEmpty() == true) { BitmapFactory.decodeByteArray(photoByteArray, 0, photoByteArray.size) @@ -151,7 +151,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont } val starred = cursor.getIntValue(COL_STARRED) - val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, events, addresses, SMT_PRIVATE, starred, id, "", photo) + val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, addresses, events, SMT_PRIVATE, starred, id, "", photo) contacts.add(contact) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt index 7244d247..9dee4a43 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt @@ -197,7 +197,7 @@ class VcfImporter(val activity: SimpleActivity) { } private fun saveContact(source: String) { - val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curEvents, curAddresses, source, 0, 0, "", null) + val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curAddresses, curEvents, source, 0, 0, "", null) if (ContactsHelper(activity).insertContact(contact)) { contactsImported++ } 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 4bf94011..0fa4d06a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt @@ -6,7 +6,7 @@ import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME import com.simplemobiletools.commons.helpers.SORT_DESCENDING data class Contact(val id: Int, var firstName: String, var middleName: String, var surname: String, var photoUri: String, - var phoneNumbers: ArrayList, var emails: ArrayList, var events: ArrayList, var addresses: ArrayList
, + var phoneNumbers: ArrayList, var emails: ArrayList, var addresses: ArrayList
, var events: ArrayList, var source: String, var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?) : Comparable { companion object { var sorting = 0 From 8459160d6ea37123a9d64218946d48715d07db3d Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 20:22:03 +0100 Subject: [PATCH 29/53] show the contact addresses on the View screen --- .../contacts/activities/ContactActivity.kt | 12 ++-- .../activities/EditContactActivity.kt | 5 ++ .../activities/ViewContactActivity.kt | 69 +++++++------------ .../contacts/helpers/Constants.kt | 7 -- .../main/res/layout/activity_view_contact.xml | 22 +++++- app/src/main/res/layout/item_view_address.xml | 37 ++++++++++ app/src/main/res/layout/item_view_email.xml | 1 - .../res/layout/item_view_phone_number.xml | 1 - 8 files changed, 94 insertions(+), 60 deletions(-) create mode 100644 app/src/main/res/layout/item_view_address.xml diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt index 998a7f80..1a63a6bf 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt @@ -154,15 +154,15 @@ abstract class ContactActivity : SimpleActivity() { else -> R.string.other } - fun getEventTextId(type: Int) = when (type) { - ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY -> R.string.birthday - ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY -> R.string.anniversary - else -> R.string.other - } - fun getAddressTextId(type: Int) = when (type) { ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME -> R.string.home ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK -> R.string.work else -> R.string.other } + + fun getEventTextId(type: Int) = when (type) { + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY -> R.string.birthday + ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY -> R.string.anniversary + else -> R.string.other + } } 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 06d90f0e..8b109b16 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -35,6 +35,11 @@ import org.joda.time.format.DateTimeFormat import java.util.* class EditContactActivity : ContactActivity() { + val DEFAULT_EMAIL_TYPE = CommonDataKinds.Email.TYPE_HOME + val DEFAULT_PHONE_NUMBER_TYPE = CommonDataKinds.Phone.TYPE_MOBILE + val DEFAULT_ADDRESS_TYPE = CommonDataKinds.StructuredPostal.TYPE_HOME + val DEFAULT_EVENT_TYPE = CommonDataKinds.Event.TYPE_BIRTHDAY + private val INTENT_TAKE_PHOTO = 1 private val INTENT_CHOOSE_PHOTO = 2 private val INTENT_CROP_PHOTO = 3 diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt index 61530bbc..87d712d2 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt @@ -6,17 +6,18 @@ import android.os.Bundle import android.provider.ContactsContract import android.view.Menu import android.view.MenuItem -import android.view.ViewGroup import android.view.WindowManager import android.widget.RelativeLayout -import android.widget.TextView import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.extensions.* -import com.simplemobiletools.contacts.helpers.* +import com.simplemobiletools.contacts.helpers.CONTACT_ID +import com.simplemobiletools.contacts.helpers.ContactsHelper +import com.simplemobiletools.contacts.helpers.IS_PRIVATE import kotlinx.android.synthetic.main.activity_view_contact.* import kotlinx.android.synthetic.main.item_event.view.* +import kotlinx.android.synthetic.main.item_view_address.view.* import kotlinx.android.synthetic.main.item_view_email.view.* import kotlinx.android.synthetic.main.item_view_phone_number.view.* @@ -89,9 +90,8 @@ class ViewContactActivity : ContactActivity() { return } - setupEditContact() + setupViewContact() - setupTypePickers() contact_send_sms.beVisibleIf(contact!!.phoneNumbers.isNotEmpty()) contact_start_call.beVisibleIf(contact!!.phoneNumbers.isNotEmpty()) contact_send_email.beVisibleIf(contact!!.emails.isNotEmpty()) @@ -122,7 +122,7 @@ class ViewContactActivity : ContactActivity() { invalidateOptionsMenu() } - private fun setupEditContact() { + private fun setupViewContact() { window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) contact!!.apply { contact_first_name.text = firstName @@ -150,6 +150,7 @@ class ViewContactActivity : ContactActivity() { setupPhoneNumbers() setupEmails() + setupAddresses() setupEvents() } @@ -160,7 +161,7 @@ class ViewContactActivity : ContactActivity() { layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false).apply { contact_numbers_holder.addView(this) contact_number.text = it.value - setupPhoneNumberTypePicker(contact_number_type, it.type) + contact_number_type.setText(getPhoneNumberTextId(it.type)) } } @@ -175,7 +176,7 @@ class ViewContactActivity : ContactActivity() { layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false).apply { contact_emails_holder.addView(this) contact_email.text = it.value - setupEmailTypePicker(contact_email_type, it.type) + contact_email_type.setText(getEmailTextId(it.type)) } } @@ -183,6 +184,21 @@ class ViewContactActivity : ContactActivity() { contact_emails_holder.beVisibleIf(emails.isNotEmpty()) } + private fun setupAddresses() { + contact_addresses_holder.removeAllViews() + val addresses = contact!!.addresses + addresses.forEach { + layoutInflater.inflate(R.layout.item_view_address, contact_addresses_holder, false).apply { + contact_addresses_holder.addView(this) + contact_address.text = it.value + contact_address_type.setText(getAddressTextId(it.type)) + } + } + + contact_address_image.beVisibleIf(addresses.isNotEmpty()) + contact_addresses_holder.beVisibleIf(addresses.isNotEmpty()) + } + private fun setupEvents() { contact_events_holder.removeAllViews() val events = contact!!.events @@ -191,7 +207,7 @@ class ViewContactActivity : ContactActivity() { contact_events_holder.addView(this) contact_event.alpha = 1f getDateTime(it.value, contact_event) - setupEventTypePicker(this as ViewGroup, it.type) + contact_event_type.setText(getEventTextId(it.type)) contact_event_remove.beGone() } } @@ -200,40 +216,5 @@ class ViewContactActivity : ContactActivity() { contact_events_holder.beVisibleIf(events.isNotEmpty()) } - private fun setupTypePickers() { - if (contact!!.phoneNumbers.isEmpty()) { - val numberHolder = contact_numbers_holder.getChildAt(0) - (numberHolder as? ViewGroup)?.contact_number_type?.apply { - setupPhoneNumberTypePicker(this) - } - } - - if (contact!!.emails.isEmpty()) { - val emailHolder = contact_emails_holder.getChildAt(0) - (emailHolder as? ViewGroup)?.contact_email_type?.apply { - setupEmailTypePicker(this) - } - } - - if (contact!!.events.isEmpty()) { - val eventHolder = contact_events_holder.getChildAt(0) - (eventHolder as? ViewGroup)?.apply { - setupEventTypePicker(this) - } - } - } - - private fun setupPhoneNumberTypePicker(numberTypeField: TextView, type: Int = DEFAULT_PHONE_NUMBER_TYPE) { - numberTypeField.setText(getPhoneNumberTextId(type)) - } - - private fun setupEmailTypePicker(emailTypeField: TextView, type: Int = DEFAULT_EMAIL_TYPE) { - emailTypeField.setText(getEmailTextId(type)) - } - - private fun setupEventTypePicker(eventHolder: ViewGroup, type: Int = DEFAULT_EVENT_TYPE) { - eventHolder.contact_event_type.setText(getEventTextId(type)) - } - private fun getStarDrawable(on: Boolean) = resources.getDrawable(if (on) R.drawable.ic_star_on_big else R.drawable.ic_star_off_big) } 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 be179078..324d9156 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt @@ -1,7 +1,5 @@ package com.simplemobiletools.contacts.helpers -import android.provider.ContactsContract.CommonDataKinds - // shared prefs const val SHOW_CONTACT_THUMBNAILS = "show_contact_thumbnails" const val SHOW_PHONE_NUMBERS = "show_phone_numbers" @@ -23,11 +21,6 @@ const val PHOTO_REMOVED = 2 const val PHOTO_CHANGED = 3 const val PHOTO_UNCHANGED = 4 -// default contact values -const val DEFAULT_EMAIL_TYPE = CommonDataKinds.Email.TYPE_HOME -const val DEFAULT_PHONE_NUMBER_TYPE = CommonDataKinds.Phone.TYPE_MOBILE -const val DEFAULT_EVENT_TYPE = CommonDataKinds.Event.TYPE_BIRTHDAY - // export/import const val BEGIN_VCARD = "BEGIN:VCARD" const val END_VCARD = "END:VCARD" diff --git a/app/src/main/res/layout/activity_view_contact.xml b/app/src/main/res/layout/activity_view_contact.xml index 457aea55..6877f11a 100644 --- a/app/src/main/res/layout/activity_view_contact.xml +++ b/app/src/main/res/layout/activity_view_contact.xml @@ -176,6 +176,26 @@ android:orientation="vertical" android:paddingLeft="@dimen/small_margin"/> + + + + diff --git a/app/src/main/res/layout/item_view_address.xml b/app/src/main/res/layout/item_view_address.xml new file mode 100644 index 00000000..fce8cbf1 --- /dev/null +++ b/app/src/main/res/layout/item_view_address.xml @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/app/src/main/res/layout/item_view_email.xml b/app/src/main/res/layout/item_view_email.xml index 8c4a2401..9de6e320 100644 --- a/app/src/main/res/layout/item_view_email.xml +++ b/app/src/main/res/layout/item_view_email.xml @@ -28,7 +28,6 @@ android:layout_alignParentRight="true" android:layout_alignTop="@+id/contact_email" android:layout_centerVertical="true" - android:background="?attr/selectableItemBackground" android:gravity="center" android:paddingLeft="@dimen/medium_margin" android:paddingRight="@dimen/medium_margin" diff --git a/app/src/main/res/layout/item_view_phone_number.xml b/app/src/main/res/layout/item_view_phone_number.xml index 8fca1a77..d37bf04e 100644 --- a/app/src/main/res/layout/item_view_phone_number.xml +++ b/app/src/main/res/layout/item_view_phone_number.xml @@ -28,7 +28,6 @@ android:layout_alignParentRight="true" android:layout_alignTop="@+id/contact_number" android:layout_centerVertical="true" - android:background="?attr/selectableItemBackground" android:gravity="center" android:paddingLeft="@dimen/medium_margin" android:paddingRight="@dimen/medium_margin" From ad669b0fc643ef2abfcb33fbd529e2c9c9c7174e Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 20:45:39 +0100 Subject: [PATCH 30/53] add address handling at the Edit screen --- .../activities/EditContactActivity.kt | 82 ++++++++++++++++++- .../main/res/layout/activity_edit_contact.xml | 40 ++++++++- app/src/main/res/layout/item_edit_address.xml | 39 +++++++++ 3 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 app/src/main/res/layout/item_edit_address.xml 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 8b109b16..82ea6e14 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -22,11 +22,9 @@ import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.extensions.* import com.simplemobiletools.contacts.helpers.* -import com.simplemobiletools.contacts.models.Contact -import com.simplemobiletools.contacts.models.Email -import com.simplemobiletools.contacts.models.Event -import com.simplemobiletools.contacts.models.PhoneNumber +import com.simplemobiletools.contacts.models.* import kotlinx.android.synthetic.main.activity_edit_contact.* +import kotlinx.android.synthetic.main.item_edit_address.view.* import kotlinx.android.synthetic.main.item_edit_email.view.* import kotlinx.android.synthetic.main.item_edit_phone_number.view.* import kotlinx.android.synthetic.main.item_event.view.* @@ -164,6 +162,7 @@ class EditContactActivity : ContactActivity() { contact_name_image.applyColorFilter(textColor) contact_number_image.applyColorFilter(textColor) contact_email_image.applyColorFilter(textColor) + contact_address_image.applyColorFilter(textColor) contact_event_image.applyColorFilter(textColor) contact_source_image.applyColorFilter(textColor) @@ -172,6 +171,8 @@ class EditContactActivity : ContactActivity() { contact_number_add_new.background.applyColorFilter(textColor) contact_email_add_new.applyColorFilter(adjustedPrimaryColor) contact_email_add_new.background.applyColorFilter(textColor) + contact_address_add_new.applyColorFilter(adjustedPrimaryColor) + contact_address_add_new.background.applyColorFilter(textColor) contact_event_add_new.applyColorFilter(adjustedPrimaryColor) contact_event_add_new.background.applyColorFilter(textColor) @@ -182,6 +183,7 @@ class EditContactActivity : ContactActivity() { contact_send_email.setOnClickListener { trySendEmail() } contact_number_add_new.setOnClickListener { addNewPhoneNumberField() } contact_email_add_new.setOnClickListener { addNewEmailField() } + contact_address_add_new.setOnClickListener { addNewAddressField() } contact_event_add_new.setOnClickListener { addNewEventField() } contact_toggle_favorite.apply { @@ -232,6 +234,7 @@ class EditContactActivity : ContactActivity() { setupPhoneNumbers() setupEmails() + setupAddresses() setupEvents() } @@ -265,6 +268,21 @@ class EditContactActivity : ContactActivity() { } } + private fun setupAddresses() { + contact!!.addresses.forEachIndexed { index, address -> + var addressHolder = contact_addresses_holder.getChildAt(index) + if (addressHolder == null) { + addressHolder = layoutInflater.inflate(R.layout.item_edit_address, contact_addresses_holder, false) + contact_addresses_holder.addView(addressHolder) + } + + addressHolder!!.apply { + contact_address.setText(address.value) + setupAddressTypePicker(contact_address_type, address.type) + } + } + } + private fun setupEvents() { contact!!.events.forEachIndexed { index, event -> var eventHolder = contact_events_holder.getChildAt(index) @@ -322,6 +340,13 @@ class EditContactActivity : ContactActivity() { } } + if (contact!!.addresses.isEmpty()) { + val addressHolder = contact_addresses_holder.getChildAt(0) + (addressHolder as? ViewGroup)?.contact_address_type?.apply { + setupAddressTypePicker(this) + } + } + if (contact!!.events.isEmpty()) { val eventHolder = contact_events_holder.getChildAt(0) (eventHolder as? ViewGroup)?.apply { @@ -348,6 +373,15 @@ class EditContactActivity : ContactActivity() { } } + private fun setupAddressTypePicker(addressTypeField: TextView, type: Int = DEFAULT_ADDRESS_TYPE) { + addressTypeField.apply { + setText(getAddressTextId(type)) + setOnClickListener { + showAddressTypePicker(it as TextView) + } + } + } + private fun setupEventTypePicker(eventHolder: ViewGroup, type: Int = DEFAULT_EVENT_TYPE) { eventHolder.contact_event_type.apply { setText(getEventTextId(type)) @@ -423,6 +457,19 @@ class EditContactActivity : ContactActivity() { } } + private fun showAddressTypePicker(addressTypeField: TextView) { + val items = arrayListOf( + RadioItem(CommonDataKinds.StructuredPostal.TYPE_HOME, getString(R.string.home)), + RadioItem(CommonDataKinds.StructuredPostal.TYPE_WORK, getString(R.string.work)), + RadioItem(CommonDataKinds.StructuredPostal.TYPE_OTHER, getString(R.string.other)) + ) + + val currentAddressTypeId = getAddressTypeId(addressTypeField.value) + RadioGroupDialog(this, items, currentAddressTypeId) { + addressTypeField.setText(getAddressTextId(it as Int)) + } + } + private fun showEventTypePicker(eventTypeField: TextView) { val items = arrayListOf( RadioItem(CommonDataKinds.Event.TYPE_BIRTHDAY, getString(R.string.birthday)), @@ -450,6 +497,7 @@ class EditContactActivity : ContactActivity() { photoUri = currentContactPhotoPath phoneNumbers = getFilledPhoneNumbers() emails = getFilledEmails() + addresses = getFilledAddresses() events = getFilledEvents() source = contact!!.source starred = if (isContactStarred()) 1 else 0 @@ -496,6 +544,21 @@ class EditContactActivity : ContactActivity() { return emails } + private fun getFilledAddresses(): ArrayList
{ + val addresses = ArrayList
() + val addressesCount = contact_addresses_holder.childCount + for (i in 0 until addressesCount) { + val addressHolder = contact_addresses_holder.getChildAt(i) + val address = addressHolder.contact_address.value + val addressType = getAddressTypeId(addressHolder.contact_address_type.value) + + if (address.isNotEmpty()) { + addresses.add(Address(address, addressType)) + } + } + return addresses + } + private fun getFilledEvents(): ArrayList { val unknown = getString(R.string.unknown) val events = ArrayList() @@ -565,6 +628,17 @@ class EditContactActivity : ContactActivity() { } } + private fun addNewAddressField() { + val addressHolder = layoutInflater.inflate(R.layout.item_edit_address, contact_addresses_holder, false) as ViewGroup + updateTextColors(addressHolder) + setupAddressTypePicker(addressHolder.contact_address_type) + contact_addresses_holder.addView(addressHolder) + contact_addresses_holder.onGlobalLayout { + addressHolder.contact_address.requestFocus() + showKeyboard(addressHolder.contact_address) + } + } + private fun addNewEventField() { val eventHolder = layoutInflater.inflate(R.layout.item_event, contact_events_holder, false) as ViewGroup updateTextColors(eventHolder) diff --git a/app/src/main/res/layout/activity_edit_contact.xml b/app/src/main/res/layout/activity_edit_contact.xml index 6684ce6d..060cbadc 100644 --- a/app/src/main/res/layout/activity_edit_contact.xml +++ b/app/src/main/res/layout/activity_edit_contact.xml @@ -213,6 +213,44 @@ android:paddingTop="@dimen/medium_margin" android:src="@drawable/ic_plus"/> + + + + + + + + + + diff --git a/app/src/main/res/layout/item_edit_address.xml b/app/src/main/res/layout/item_edit_address.xml new file mode 100644 index 00000000..f18e5552 --- /dev/null +++ b/app/src/main/res/layout/item_edit_address.xml @@ -0,0 +1,39 @@ + + + + + + + + From 9edcee71105cb6f3dbb6e56b0b465b8d44bfdc8e Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 20:57:16 +0100 Subject: [PATCH 31/53] handle contact address inserting/updating --- .../contacts/helpers/ContactsHelper.kt | 96 ++++++++++++------- 1 file changed, 63 insertions(+), 33 deletions(-) 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 1b1e65f9..716cd6f3 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -177,39 +177,6 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return emails } - private fun getEvents(contactId: Int): SparseArray> { - val events = SparseArray>() - val uri = ContactsContract.Data.CONTENT_URI - val projection = arrayOf( - CommonDataKinds.Event.START_DATE, - CommonDataKinds.Event.TYPE - ) - val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?" - val selectionArgs = arrayOf(contactId.toString(), CommonDataKinds.Event.CONTENT_ITEM_TYPE) - var cursor: Cursor? = null - try { - cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) - if (cursor?.moveToFirst() == true) { - do { - val startDate = cursor.getStringValue(CommonDataKinds.Event.START_DATE) - val type = cursor.getIntValue(CommonDataKinds.Event.TYPE) - - if (events[contactId] == null) { - events.put(contactId, ArrayList()) - } - - events[contactId]!!.add(Event(startDate, type)) - } while (cursor.moveToNext()) - } - } catch (e: Exception) { - activity.showErrorToast(e) - } finally { - cursor?.close() - } - - return events - } - private fun getAddresses(contactId: Int? = null): SparseArray> { val addresses = SparseArray>() val uri = CommonDataKinds.StructuredPostal.CONTENT_URI @@ -248,6 +215,39 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return addresses } + private fun getEvents(contactId: Int): SparseArray> { + val events = SparseArray>() + val uri = ContactsContract.Data.CONTENT_URI + val projection = arrayOf( + CommonDataKinds.Event.START_DATE, + CommonDataKinds.Event.TYPE + ) + val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?" + val selectionArgs = arrayOf(contactId.toString(), CommonDataKinds.Event.CONTENT_ITEM_TYPE) + var cursor: Cursor? = null + try { + cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) + if (cursor?.moveToFirst() == true) { + do { + val startDate = cursor.getStringValue(CommonDataKinds.Event.START_DATE) + val type = cursor.getIntValue(CommonDataKinds.Event.TYPE) + + if (events[contactId] == null) { + events.put(contactId, ArrayList()) + } + + events[contactId]!!.add(Event(startDate, type)) + } while (cursor.moveToNext()) + } + } catch (e: Exception) { + activity.showErrorToast(e) + } finally { + cursor?.close() + } + + return events + } + fun getContactWithId(id: Int, isLocalPrivate: Boolean): Contact? { if (id == 0) { return null @@ -432,6 +432,25 @@ class ContactsHelper(val activity: BaseSimpleActivity) { } } + // delete addresses + ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply { + val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? " + val selectionArgs = arrayOf(contact.id.toString(), CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) + withSelection(selection, selectionArgs) + operations.add(build()) + } + + // add addresses + contact.addresses.forEach { + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply { + withValue(ContactsContract.Data.RAW_CONTACT_ID, contact.id) + withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) + withValue(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, it.value) + withValue(CommonDataKinds.StructuredPostal.TYPE, it.type) + operations.add(build()) + } + } + // delete events ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply { val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? " @@ -555,6 +574,17 @@ class ContactsHelper(val activity: BaseSimpleActivity) { } } + // addresses + contact.addresses.forEach { + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply { + withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) + withValue(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, it.value) + withValue(CommonDataKinds.StructuredPostal.TYPE, it.type) + operations.add(build()) + } + } + // events contact.events.forEach { ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply { From 51d2d5d22ba85e9b23f689617285a0a7c1ef9d67 Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 21 Feb 2018 21:21:33 +0100 Subject: [PATCH 32/53] handle address field export/importing --- .../contacts/helpers/Constants.kt | 1 + .../contacts/helpers/VcfExporter.kt | 12 +++++++++++ .../contacts/helpers/VcfImporter.kt | 20 +++++++++++++++++++ 3 files changed, 33 insertions(+) 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 324d9156..695fd967 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt @@ -30,6 +30,7 @@ const val BDAY = "BDAY:" const val ANNIVERSARY = "ANNIVERSARY:" const val PHOTO = "PHOTO" const val EMAIL = "EMAIL" +const val ADR = "ADR" const val ENCODING = "ENCODING" const val BASE64 = "BASE64" const val JPEG = "JPEG" diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt index 793a8ccc..21f784ad 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt @@ -50,6 +50,12 @@ class VcfExporter { out.writeLn("$EMAIL$delimiterType:${it.value}") } + contact.addresses.forEach { + val type = getAddressTypeLabel(it.type) + val delimiterType = if (type.isEmpty()) "" else ";$type" + out.writeLn("$ADR$delimiterType:;;${it.value};;;;") + } + contact.events.forEach { if (it.type == CommonDataKinds.Event.TYPE_BIRTHDAY) { out.writeLn("$BDAY${it.value}") @@ -136,4 +142,10 @@ class VcfExporter { CommonDataKinds.Email.TYPE_MOBILE -> MOBILE else -> "" } + + private fun getAddressTypeLabel(type: Int) = when (type) { + CommonDataKinds.StructuredPostal.TYPE_HOME -> HOME + CommonDataKinds.StructuredPostal.TYPE_WORK -> WORK + else -> "" + } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt index 9dee4a43..15c8ca09 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt @@ -67,6 +67,7 @@ class VcfImporter(val activity: SimpleActivity) { line.toUpperCase().startsWith(N) -> addNames(line.substring(N.length)) line.toUpperCase().startsWith(TEL) -> addPhoneNumber(line.substring(TEL.length)) line.toUpperCase().startsWith(EMAIL) -> addEmail(line.substring(EMAIL.length)) + line.toUpperCase().startsWith(ADR) -> addAddress(line.substring(ADR.length)) line.toUpperCase().startsWith(BDAY) -> addBirthday(line.substring(BDAY.length)) line.toUpperCase().startsWith(ANNIVERSARY) -> addAnniversary(line.substring(ANNIVERSARY.length)) line.toUpperCase().startsWith(PHOTO) -> addPhoto(line.substring(PHOTO.length)) @@ -154,6 +155,25 @@ class VcfImporter(val activity: SimpleActivity) { else -> CommonDataKinds.Email.TYPE_OTHER } + private fun addAddress(address: String) { + val addressParts = address.trimStart(';').split(":") + var rawType = addressParts[0] + if (rawType.contains('=')) { + rawType = rawType.split('=').last() + } + val type = getAddressTypeId(rawType.toUpperCase()) + val addresses = addressParts[1].split(";") + if (addresses.size == 7) { + curAddresses.add(Address(addresses[2], type)) + } + } + + private fun getAddressTypeId(type: String) = when (type) { + HOME -> CommonDataKinds.Email.TYPE_HOME + WORK -> CommonDataKinds.Email.TYPE_WORK + else -> CommonDataKinds.Email.TYPE_OTHER + } + private fun addBirthday(birthday: String) { curEvents.add(Event(birthday, CommonDataKinds.Event.TYPE_BIRTHDAY)) } From e7faeffc427e4495854f0417387e0fdf370819ff Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 10:27:00 +0100 Subject: [PATCH 33/53] adding addresses field to the locally stored contacts --- .../contacts/helpers/DBHelper.kt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) 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 11515eba..f91c8c2e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -29,13 +29,14 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont private val COL_EMAILS = "emails" private val COL_EVENTS = "events" private val COL_STARRED = "starred" + private val COL_ADDRESSES = "addresses" private val FIRST_CONTACT_ID = 1000000 private val mDb = writableDatabase companion object { - private const val DB_VERSION = 1 + private const val DB_VERSION = 2 const val DB_NAME = "contacts.db" var dbInstance: DBHelper? = null @@ -49,14 +50,16 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont override fun onCreate(db: SQLiteDatabase) { db.execSQL("CREATE TABLE $CONTACTS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_FIRST_NAME TEXT, $COL_MIDDLE_NAME TEXT, " + - "$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER)") + "$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER, $COL_ADDRESSES TEXT)") // start autoincrement ID from FIRST_CONTACT_ID to avoid conflicts db.execSQL("REPLACE INTO sqlite_sequence (name, seq) VALUES ('$CONTACTS_TABLE_NAME', $FIRST_CONTACT_ID)") } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { - + if (oldVersion == 1) { + db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_ADDRESSES TEXT DEFAULT ''") + } } fun insert(contact: Contact): Boolean { @@ -87,6 +90,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont put(COL_SURNAME, contact.surname) put(COL_PHONE_NUMBERS, Gson().toJson(contact.phoneNumbers)) put(COL_EMAILS, Gson().toJson(contact.emails)) + put(COL_ADDRESSES, Gson().toJson(contact.addresses)) put(COL_EVENTS, Gson().toJson(contact.events)) put(COL_STARRED, contact.starred) @@ -120,7 +124,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont fun getContacts(selection: String? = null, selectionArgs: Array? = null): ArrayList { val contacts = ArrayList() - val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED, COL_PHOTO) + val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED, COL_PHOTO, COL_ADDRESSES) val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, selection, selectionArgs, null, null, null) cursor.use { while (cursor.moveToNext()) { @@ -137,7 +141,9 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont val emailsToken = object : TypeToken>() {}.type val emails = Gson().fromJson>(emailsJson, emailsToken) ?: ArrayList(1) - val addresses = ArrayList
() + val addressesJson = cursor.getStringValue(COL_ADDRESSES) + val addressesToken = object : TypeToken>() {}.type + val addresses = Gson().fromJson>(addressesJson, addressesToken) ?: ArrayList(1) val eventsJson = cursor.getStringValue(COL_EVENTS) val eventsToken = object : TypeToken>() {}.type From 8f743f3397e93fea35adfb9fce8743a7ff751877 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 13:57:08 +0100 Subject: [PATCH 34/53] adding a contact Notes field --- .../activities/EditContactActivity.kt | 2 +- .../contacts/helpers/ContactsHelper.kt | 45 ++++++++++++------- .../contacts/helpers/DBHelper.kt | 4 +- .../contacts/helpers/VcfImporter.kt | 4 +- .../contacts/models/Contact.kt | 2 +- 5 files changed, 37 insertions(+), 20 deletions(-) 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 82ea6e14..df09f780 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -315,7 +315,7 @@ class EditContactActivity : ContactActivity() { private fun setupNewContact() { window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) supportActionBar?.title = resources.getString(R.string.new_contact) - contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "", null) + contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "", null, "") contact_source.text = getPublicContactSource(contact!!.source) contact_source.setOnClickListener { showContactSourcePicker(contact!!.source) { 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 716cd6f3..3041cd1e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -9,6 +9,7 @@ import android.graphics.Bitmap import android.net.Uri import android.provider.ContactsContract import android.provider.ContactsContract.CommonDataKinds +import android.provider.ContactsContract.CommonDataKinds.Note import android.provider.MediaStore import android.util.SparseArray import com.simplemobiletools.commons.activities.BaseSimpleActivity @@ -26,9 +27,7 @@ import com.simplemobiletools.contacts.extensions.dbHelper import com.simplemobiletools.contacts.extensions.getByteArray import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize import com.simplemobiletools.contacts.models.* -import java.io.ByteArrayOutputStream -import java.util.* -import kotlin.collections.ArrayList + class ContactsHelper(val activity: BaseSimpleActivity) { fun getContacts(callback: (ArrayList) -> Unit) { @@ -58,8 +57,9 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" + val notes = "" val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName, - starred, contactId, thumbnailUri, null) + starred, contactId, thumbnailUri, null, notes) contacts.put(id, contact) } while (cursor.moveToNext()) } @@ -90,6 +90,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) { contacts[key]?.addresses = addresses.valueAt(i) } + //getNotes() + activity.dbHelper.getContacts().forEach { contacts.put(it.id, it) } @@ -248,6 +250,27 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return events } + private fun getNotes(contactId: Int): String { + val uri = ContactsContract.Data.CONTENT_URI + val projection = arrayOf(Note.NOTE) + val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = '${Note.CONTENT_ITEM_TYPE}'" + val selectionArgs = arrayOf(contactId.toString()) + + var cursor: Cursor? = null + try { + cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) + if (cursor?.moveToFirst() == true) { + return cursor.getStringValue(CommonDataKinds.Note.NOTE) ?: "" + } + } catch (e: Exception) { + activity.showErrorToast(e) + } finally { + cursor?.close() + } + + return "" + } + fun getContactWithId(id: Int, isLocalPrivate: Boolean): Contact? { if (id == 0) { return null @@ -275,7 +298,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - return Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName, starred, contactId, thumbnailUri, null) + val notes = getNotes(id) + return Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName, starred, contactId, thumbnailUri, null, notes) } } finally { cursor?.close() @@ -661,17 +685,6 @@ class ContactsHelper(val activity: BaseSimpleActivity) { fileDescriptor.close() } - private fun bitmapToByteArray(bitmap: Bitmap): ByteArray { - var baos: ByteArrayOutputStream? = null - try { - baos = ByteArrayOutputStream() - bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos) - return baos.toByteArray() - } finally { - baos?.close() - } - } - fun getContactLookupKey(contactId: String): String { val uri = ContactsContract.Data.CONTENT_URI val projection = arrayOf(ContactsContract.Data.CONTACT_ID, ContactsContract.Data.LOOKUP_KEY) 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 f91c8c2e..6229ec79 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -156,8 +156,10 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont null } + val notes = "" + val starred = cursor.getIntValue(COL_STARRED) - val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, addresses, events, SMT_PRIVATE, starred, id, "", photo) + val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, addresses, events, SMT_PRIVATE, starred, id, "", photo, notes) contacts.add(contact) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt index 15c8ca09..3259600a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt @@ -23,6 +23,7 @@ class VcfImporter(val activity: SimpleActivity) { private var curMiddleName = "" private var curSurname = "" private var curPhotoUri = "" + private var curNotes = "" private var curPhoneNumbers = ArrayList() private var curEmails = ArrayList() private var curEvents = ArrayList() @@ -217,7 +218,7 @@ class VcfImporter(val activity: SimpleActivity) { } private fun saveContact(source: String) { - val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curAddresses, curEvents, source, 0, 0, "", null) + val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curAddresses, curEvents, source, 0, 0, "", null, curNotes) if (ContactsHelper(activity).insertContact(contact)) { contactsImported++ } @@ -228,6 +229,7 @@ class VcfImporter(val activity: SimpleActivity) { curMiddleName = "" curSurname = "" curPhotoUri = "" + curNotes = "" curPhoneNumbers = ArrayList() curEmails = ArrayList() curEvents = ArrayList() 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 0fa4d06a..498e1a52 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt @@ -7,7 +7,7 @@ import com.simplemobiletools.commons.helpers.SORT_DESCENDING data class Contact(val id: Int, var firstName: String, var middleName: String, var surname: String, var photoUri: String, var phoneNumbers: ArrayList, var emails: ArrayList, var addresses: ArrayList
, var events: ArrayList, - var source: String, var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?) : Comparable { + var source: String, var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?, var notes: String) : Comparable { companion object { var sorting = 0 } From 8edab98cb3d9308d608466b56c0a665834986f9d Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 14:01:54 +0100 Subject: [PATCH 35/53] avoid unnecessarily fetching all contact emails and addresses for the main screen --- .../contacts/helpers/ContactsHelper.kt | 69 +++++-------------- 1 file changed, 16 insertions(+), 53 deletions(-) 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 3041cd1e..133d1154 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -76,22 +76,6 @@ class ContactsHelper(val activity: BaseSimpleActivity) { contacts[key]?.phoneNumbers = phoneNumbers.valueAt(i) } - val emails = getEmails() - size = emails.size() - for (i in 0 until size) { - val key = emails.keyAt(i) - contacts[key]?.emails = emails.valueAt(i) - } - - val addresses = getAddresses() - size = addresses.size() - for (i in 0 until size) { - val key = addresses.keyAt(i) - contacts[key]?.addresses = addresses.valueAt(i) - } - - //getNotes() - activity.dbHelper.getContacts().forEach { contacts.put(it.id, it) } @@ -141,35 +125,27 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return phoneNumbers } - private fun getEmails(contactId: Int? = null): SparseArray> { - val emails = SparseArray>() + private fun getEmails(contactId: Int): ArrayList { + val emails = ArrayList() val uri = CommonDataKinds.Email.CONTENT_URI val projection = arrayOf( - ContactsContract.Data.RAW_CONTACT_ID, CommonDataKinds.Email.DATA, 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 = "${ContactsContract.Data.RAW_CONTACT_ID} = ?" + val selectionArgs = arrayOf(contactId.toString()) var cursor: Cursor? = null try { cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) if (cursor?.moveToFirst() == true) { do { - val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID) val email = cursor.getStringValue(CommonDataKinds.Email.DATA) ?: continue val type = cursor.getIntValue(CommonDataKinds.Email.TYPE) - - if (emails[id] == null) { - emails.put(id, ArrayList()) - } - - emails[id]!!.add(Email(email, type)) + emails.add(Email(email, type)) } while (cursor.moveToNext()) } - } catch (e: Exception) { activity.showErrorToast(e) } finally { @@ -179,35 +155,27 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return emails } - private fun getAddresses(contactId: Int? = null): SparseArray> { - val addresses = SparseArray>() + private fun getAddresses(contactId: Int): ArrayList
{ + val addresses = ArrayList
() val uri = CommonDataKinds.StructuredPostal.CONTENT_URI val projection = arrayOf( - ContactsContract.Data.RAW_CONTACT_ID, CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, 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 = "${ContactsContract.Data.RAW_CONTACT_ID} = ?" + val selectionArgs = arrayOf(contactId.toString()) var cursor: Cursor? = null try { cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) if (cursor?.moveToFirst() == true) { do { - val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID) val address = cursor.getStringValue(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS) val type = cursor.getIntValue(CommonDataKinds.StructuredPostal.TYPE) - - if (addresses[id] == null) { - addresses.put(id, ArrayList()) - } - - addresses[id]!!.add(Address(address, type)) + addresses.add(Address(address, type)) } while (cursor.moveToNext()) } - } catch (e: Exception) { activity.showErrorToast(e) } finally { @@ -217,8 +185,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return addresses } - private fun getEvents(contactId: Int): SparseArray> { - val events = SparseArray>() + private fun getEvents(contactId: Int): ArrayList { + val events = ArrayList() val uri = ContactsContract.Data.CONTENT_URI val projection = arrayOf( CommonDataKinds.Event.START_DATE, @@ -233,12 +201,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) { do { val startDate = cursor.getStringValue(CommonDataKinds.Event.START_DATE) val type = cursor.getIntValue(CommonDataKinds.Event.TYPE) - - if (events[contactId] == null) { - events.put(contactId, ArrayList()) - } - - events[contactId]!!.add(Event(startDate, type)) + events.add(Event(startDate, type)) } while (cursor.moveToNext()) } } catch (e: Exception) { @@ -291,9 +254,9 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val surname = cursor.getStringValue(CommonDataKinds.StructuredName.FAMILY_NAME) ?: "" val photoUri = cursor.getStringValue(CommonDataKinds.Phone.PHOTO_URI) ?: "" val number = getPhoneNumbers(id)[id] ?: ArrayList() - val emails = getEmails(id)[id] ?: ArrayList() - val addresses = getAddresses(id)[id] ?: ArrayList() - val events = getEvents(id)[id] ?: ArrayList() + val emails = getEmails(id) + val addresses = getAddresses(id) + val events = getEvents(id) val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: "" val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) From ac99c14c96e30e1cdd6a371fa3ca28a0635967d6 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 14:15:39 +0100 Subject: [PATCH 36/53] show the contact notes at the View screen --- .../activities/ViewContactActivity.kt | 9 +++++++ .../main/res/layout/activity_view_contact.xml | 27 +++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt index 87d712d2..f27ef8d8 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt @@ -113,6 +113,7 @@ class ViewContactActivity : ContactActivity() { contact_email_image.applyColorFilter(textColor) contact_event_image.applyColorFilter(textColor) contact_source_image.applyColorFilter(textColor) + contact_notes_image.applyColorFilter(textColor) contact_send_sms.setOnClickListener { trySendSMS() } contact_start_call.setOnClickListener { tryStartCall(contact!!) } @@ -152,6 +153,7 @@ class ViewContactActivity : ContactActivity() { setupEmails() setupAddresses() setupEvents() + setupNotes() } private fun setupPhoneNumbers() { @@ -216,5 +218,12 @@ class ViewContactActivity : ContactActivity() { contact_events_holder.beVisibleIf(events.isNotEmpty()) } + private fun setupNotes() { + val notes = contact!!.notes + contact_notes.text = notes + contact_notes_image.beVisibleIf(notes.isNotEmpty()) + contact_notes.beVisibleIf(notes.isNotEmpty()) + } + private fun getStarDrawable(on: Boolean) = resources.getDrawable(if (on) R.drawable.ic_star_on_big else R.drawable.ic_star_off_big) } diff --git a/app/src/main/res/layout/activity_view_contact.xml b/app/src/main/res/layout/activity_view_contact.xml index 6877f11a..3a8e9c31 100644 --- a/app/src/main/res/layout/activity_view_contact.xml +++ b/app/src/main/res/layout/activity_view_contact.xml @@ -215,6 +215,30 @@ android:layout_toRightOf="@+id/contact_name_image" android:orientation="vertical"/> + + + + Date: Thu, 22 Feb 2018 15:14:19 +0100 Subject: [PATCH 37/53] handle note inserting and updating --- .../activities/EditContactActivity.kt | 7 +++++ .../contacts/helpers/ContactsHelper.kt | 21 +++++++++++++-- .../main/res/layout/activity_edit_contact.xml | 26 ++++++++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) 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 df09f780..f13c21b0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -164,6 +164,7 @@ class EditContactActivity : ContactActivity() { contact_email_image.applyColorFilter(textColor) contact_address_image.applyColorFilter(textColor) contact_event_image.applyColorFilter(textColor) + contact_notes_image.applyColorFilter(textColor) contact_source_image.applyColorFilter(textColor) val adjustedPrimaryColor = getAdjustedPrimaryColor() @@ -235,6 +236,7 @@ class EditContactActivity : ContactActivity() { setupPhoneNumbers() setupEmails() setupAddresses() + setupNotes() setupEvents() } @@ -283,6 +285,10 @@ class EditContactActivity : ContactActivity() { } } + private fun setupNotes() { + contact_notes.setText(contact!!.notes) + } + private fun setupEvents() { contact!!.events.forEachIndexed { index, event -> var eventHolder = contact_events_holder.getChildAt(index) @@ -501,6 +507,7 @@ class EditContactActivity : ContactActivity() { events = getFilledEvents() source = contact!!.source starred = if (isContactStarred()) 1 else 0 + notes = contact_notes.value.replace("\n", "\\n") Thread { config.lastUsedContactSource = source 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 133d1154..4215fb71 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -216,8 +216,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) { private fun getNotes(contactId: Int): String { val uri = ContactsContract.Data.CONTENT_URI val projection = arrayOf(Note.NOTE) - val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = '${Note.CONTENT_ITEM_TYPE}'" - val selectionArgs = arrayOf(contactId.toString()) + val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?" + val selectionArgs = arrayOf(contactId.toString(), Note.CONTENT_ITEM_TYPE) var cursor: Cursor? = null try { @@ -457,6 +457,15 @@ class ContactsHelper(val activity: BaseSimpleActivity) { } } + // notes + ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI).apply { + val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?" + val selectionArgs = arrayOf(contact.id.toString(), Note.CONTENT_ITEM_TYPE) + withSelection(selection, selectionArgs) + withValue(Note.NOTE, contact.notes) + operations.add(build()) + } + // favorite try { val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, contact.contactId.toString()) @@ -583,6 +592,14 @@ class ContactsHelper(val activity: BaseSimpleActivity) { } } + // notes + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply { + withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + withValue(ContactsContract.Data.MIMETYPE, Note.CONTENT_ITEM_TYPE) + withValue(Note.NOTE, contact.notes) + operations.add(build()) + } + // photo (inspired by https://gist.github.com/slightfoot/5985900) var fullSizePhotoData: ByteArray? = null var scaledSizePhotoData: ByteArray? diff --git a/app/src/main/res/layout/activity_edit_contact.xml b/app/src/main/res/layout/activity_edit_contact.xml index 060cbadc..b5c8cc52 100644 --- a/app/src/main/res/layout/activity_edit_contact.xml +++ b/app/src/main/res/layout/activity_edit_contact.xml @@ -289,6 +289,30 @@ android:paddingTop="@dimen/medium_margin" android:src="@drawable/ic_plus"/> + + + + Date: Thu, 22 Feb 2018 15:25:36 +0100 Subject: [PATCH 38/53] add Notes field at our local database too --- .../contacts/activities/EditContactActivity.kt | 2 +- .../simplemobiletools/contacts/helpers/DBHelper.kt | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) 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 f13c21b0..38b30572 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -507,7 +507,7 @@ class EditContactActivity : ContactActivity() { events = getFilledEvents() source = contact!!.source starred = if (isContactStarred()) 1 else 0 - notes = contact_notes.value.replace("\n", "\\n") + notes = contact_notes.value Thread { config.lastUsedContactSource = source 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 6229ec79..2703ffa8 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -30,6 +30,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont private val COL_EVENTS = "events" private val COL_STARRED = "starred" private val COL_ADDRESSES = "addresses" + private val COL_NOTES = "notes" private val FIRST_CONTACT_ID = 1000000 @@ -50,7 +51,8 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont override fun onCreate(db: SQLiteDatabase) { db.execSQL("CREATE TABLE $CONTACTS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_FIRST_NAME TEXT, $COL_MIDDLE_NAME TEXT, " + - "$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER, $COL_ADDRESSES TEXT)") + "$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER, " + + "$COL_ADDRESSES TEXT, $COL_NOTES TEXT)") // start autoincrement ID from FIRST_CONTACT_ID to avoid conflicts db.execSQL("REPLACE INTO sqlite_sequence (name, seq) VALUES ('$CONTACTS_TABLE_NAME', $FIRST_CONTACT_ID)") @@ -59,6 +61,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { if (oldVersion == 1) { db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_ADDRESSES TEXT DEFAULT ''") + db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_NOTES TEXT DEFAULT ''") } } @@ -93,6 +96,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont put(COL_ADDRESSES, Gson().toJson(contact.addresses)) put(COL_EVENTS, Gson().toJson(contact.events)) put(COL_STARRED, contact.starred) + put(COL_NOTES, contact.notes) if (contact.photoUri.isNotEmpty()) { put(COL_PHOTO, getPhotoByteArray(contact.photoUri)) @@ -124,7 +128,8 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont fun getContacts(selection: String? = null, selectionArgs: Array? = null): ArrayList { val contacts = ArrayList() - val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED, COL_PHOTO, COL_ADDRESSES) + val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED, + COL_PHOTO, COL_ADDRESSES, COL_NOTES) val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, selection, selectionArgs, null, null, null) cursor.use { while (cursor.moveToNext()) { @@ -156,9 +161,9 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont null } - val notes = "" - + val notes = cursor.getStringValue(COL_NOTES) val starred = cursor.getIntValue(COL_STARRED) + val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, addresses, events, SMT_PRIVATE, starred, id, "", photo, notes) contacts.add(contact) } From 926ba81bcdfcb374f8ae72864c8e6d08b80cb526 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 16:04:31 +0100 Subject: [PATCH 39/53] add importing note from vcf file --- .../contacts/helpers/Constants.kt | 1 + .../contacts/helpers/VcfImporter.kt | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) 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 695fd967..b59e18ca 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt @@ -31,6 +31,7 @@ const val ANNIVERSARY = "ANNIVERSARY:" const val PHOTO = "PHOTO" const val EMAIL = "EMAIL" const val ADR = "ADR" +const val NOTE = "NOTE:" const val ENCODING = "ENCODING" const val BASE64 = "BASE64" const val JPEG = "JPEG" diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt index 3259600a..e644d5eb 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt @@ -37,6 +37,9 @@ class VcfImporter(val activity: SimpleActivity) { private var currentNameIsANSI = false private var currentNameString = StringBuilder() + private var isGettingNotes = false + private var currentNotesSB = StringBuilder() + private var contactsImported = 0 private var contactsFailed = 0 @@ -61,10 +64,18 @@ class VcfImporter(val activity: SimpleActivity) { currentNameString.append(line.trimStart('\t')) isGettingName = false parseNames() + } else if (isGettingNotes) { + if (line.startsWith(' ')) { + currentNotesSB.append(line.substring(1)) + } else { + curNotes = currentNotesSB.toString().replace("\\n", "\n").replace("\\,", ",") + isGettingNotes = false + } } when { line.toUpperCase() == BEGIN_VCARD -> resetValues() + line.toUpperCase().startsWith(NOTE) -> addNotes(line.substring(NOTE.length)) line.toUpperCase().startsWith(N) -> addNames(line.substring(N.length)) line.toUpperCase().startsWith(TEL) -> addPhoneNumber(line.substring(TEL.length)) line.toUpperCase().startsWith(EMAIL) -> addEmail(line.substring(EMAIL.length)) @@ -217,6 +228,11 @@ class VcfImporter(val activity: SimpleActivity) { curPhotoUri = activity.getCachePhotoUri(file).toString() } + private fun addNotes(notes: String) { + currentNotesSB.append(notes) + isGettingNotes = true + } + private fun saveContact(source: String) { val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curAddresses, curEvents, source, 0, 0, "", null, curNotes) if (ContactsHelper(activity).insertContact(contact)) { @@ -242,5 +258,8 @@ class VcfImporter(val activity: SimpleActivity) { isGettingName = false currentNameIsANSI = false currentNameString = StringBuilder() + + isGettingNotes = false + currentNotesSB = StringBuilder() } } From 2fa449d60e48085020b60ee14c1dec47b150b6a0 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 16:14:14 +0100 Subject: [PATCH 40/53] add notes exporting --- .../com/simplemobiletools/contacts/helpers/ContactsHelper.kt | 1 - .../com/simplemobiletools/contacts/helpers/VcfExporter.kt | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) 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 4215fb71..d4ad4483 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -28,7 +28,6 @@ import com.simplemobiletools.contacts.extensions.getByteArray import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize import com.simplemobiletools.contacts.models.* - class ContactsHelper(val activity: BaseSimpleActivity) { fun getContacts(callback: (ArrayList) -> Unit) { val contacts = SparseArray() diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt index 21f784ad..ec7e443e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt @@ -62,6 +62,10 @@ class VcfExporter { } } + if (contact.notes.isNotEmpty()) { + out.writeLn("$NOTE${contact.notes.replace("\n", "\\n")}") + } + if (contact.thumbnailUri.isNotEmpty()) { val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, Uri.parse(contact.thumbnailUri)) addBitmap(bitmap, out) From f81700c1205c32de0c749f97d121d204886194a3 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 16:14:33 +0100 Subject: [PATCH 41/53] Revert "avoid unnecessarily fetching all contact emails and addresses for the main screen" This reverts commit 8edab98cb3d9308d608466b56c0a665834986f9d. --- .../contacts/helpers/ContactsHelper.kt | 69 ++++++++++++++----- 1 file changed, 53 insertions(+), 16 deletions(-) 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 d4ad4483..83283a2f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -75,6 +75,22 @@ class ContactsHelper(val activity: BaseSimpleActivity) { contacts[key]?.phoneNumbers = phoneNumbers.valueAt(i) } + val emails = getEmails() + size = emails.size() + for (i in 0 until size) { + val key = emails.keyAt(i) + contacts[key]?.emails = emails.valueAt(i) + } + + val addresses = getAddresses() + size = addresses.size() + for (i in 0 until size) { + val key = addresses.keyAt(i) + contacts[key]?.addresses = addresses.valueAt(i) + } + + //getNotes() + activity.dbHelper.getContacts().forEach { contacts.put(it.id, it) } @@ -124,27 +140,35 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return phoneNumbers } - private fun getEmails(contactId: Int): ArrayList { - val emails = ArrayList() + private fun getEmails(contactId: Int? = null): SparseArray> { + val emails = SparseArray>() val uri = CommonDataKinds.Email.CONTENT_URI val projection = arrayOf( + ContactsContract.Data.RAW_CONTACT_ID, CommonDataKinds.Email.DATA, CommonDataKinds.Email.TYPE ) - val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ?" - val selectionArgs = arrayOf(contactId.toString()) + val selection = if (contactId == null) null else "${ContactsContract.Data.RAW_CONTACT_ID} = ?" + val selectionArgs = if (contactId == null) null else arrayOf(contactId.toString()) var cursor: Cursor? = null try { cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) if (cursor?.moveToFirst() == true) { do { + val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID) val email = cursor.getStringValue(CommonDataKinds.Email.DATA) ?: continue val type = cursor.getIntValue(CommonDataKinds.Email.TYPE) - emails.add(Email(email, type)) + + if (emails[id] == null) { + emails.put(id, ArrayList()) + } + + emails[id]!!.add(Email(email, type)) } while (cursor.moveToNext()) } + } catch (e: Exception) { activity.showErrorToast(e) } finally { @@ -154,27 +178,35 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return emails } - private fun getAddresses(contactId: Int): ArrayList
{ - val addresses = ArrayList
() + private fun getAddresses(contactId: Int? = null): SparseArray> { + val addresses = SparseArray>() val uri = CommonDataKinds.StructuredPostal.CONTENT_URI val projection = arrayOf( + ContactsContract.Data.RAW_CONTACT_ID, CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, CommonDataKinds.StructuredPostal.TYPE ) - val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ?" - val selectionArgs = arrayOf(contactId.toString()) + val selection = if (contactId == null) null else "${ContactsContract.Data.RAW_CONTACT_ID} = ?" + val selectionArgs = if (contactId == null) null else arrayOf(contactId.toString()) var cursor: Cursor? = null try { cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) if (cursor?.moveToFirst() == true) { do { + val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID) val address = cursor.getStringValue(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS) val type = cursor.getIntValue(CommonDataKinds.StructuredPostal.TYPE) - addresses.add(Address(address, type)) + + if (addresses[id] == null) { + addresses.put(id, ArrayList()) + } + + addresses[id]!!.add(Address(address, type)) } while (cursor.moveToNext()) } + } catch (e: Exception) { activity.showErrorToast(e) } finally { @@ -184,8 +216,8 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return addresses } - private fun getEvents(contactId: Int): ArrayList { - val events = ArrayList() + private fun getEvents(contactId: Int): SparseArray> { + val events = SparseArray>() val uri = ContactsContract.Data.CONTENT_URI val projection = arrayOf( CommonDataKinds.Event.START_DATE, @@ -200,7 +232,12 @@ class ContactsHelper(val activity: BaseSimpleActivity) { do { val startDate = cursor.getStringValue(CommonDataKinds.Event.START_DATE) val type = cursor.getIntValue(CommonDataKinds.Event.TYPE) - events.add(Event(startDate, type)) + + if (events[contactId] == null) { + events.put(contactId, ArrayList()) + } + + events[contactId]!!.add(Event(startDate, type)) } while (cursor.moveToNext()) } } catch (e: Exception) { @@ -253,9 +290,9 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val surname = cursor.getStringValue(CommonDataKinds.StructuredName.FAMILY_NAME) ?: "" val photoUri = cursor.getStringValue(CommonDataKinds.Phone.PHOTO_URI) ?: "" val number = getPhoneNumbers(id)[id] ?: ArrayList() - val emails = getEmails(id) - val addresses = getAddresses(id) - val events = getEvents(id) + val emails = getEmails(id)[id] ?: ArrayList() + val addresses = getAddresses(id)[id] ?: ArrayList() + val events = getEvents(id)[id] ?: ArrayList() val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: "" val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) From 7f11945af40e71ec4f6d74efb7210b5f15e4b818 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 16:23:04 +0100 Subject: [PATCH 42/53] make fetching some fields optional, used only at exporting --- .../contacts/activities/MainActivity.kt | 2 +- .../contacts/helpers/ContactsHelper.kt | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) 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 4181dc2c..68cc440d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt @@ -358,7 +358,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener { FilePickerDialog(this, pickFile = false, showFAB = true) { ExportContactsDialog(this, it) { file, contactSources -> Thread { - ContactsHelper(this).getContacts { + ContactsHelper(this).getContacts(true) { val contacts = it.filter { contactSources.contains(it.source) } if (contacts.isEmpty()) { toast(R.string.no_entries_for_exporting) 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 83283a2f..b224dd67 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -29,7 +29,7 @@ import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize import com.simplemobiletools.contacts.models.* class ContactsHelper(val activity: BaseSimpleActivity) { - fun getContacts(callback: (ArrayList) -> Unit) { + fun getContacts(addOptionalFields: Boolean = false, callback: (ArrayList) -> Unit) { val contacts = SparseArray() Thread { val uri = ContactsContract.Data.CONTENT_URI @@ -75,22 +75,22 @@ class ContactsHelper(val activity: BaseSimpleActivity) { contacts[key]?.phoneNumbers = phoneNumbers.valueAt(i) } - val emails = getEmails() - size = emails.size() - for (i in 0 until size) { - val key = emails.keyAt(i) - contacts[key]?.emails = emails.valueAt(i) - } + if (addOptionalFields) { + val emails = getEmails() + size = emails.size() + for (i in 0 until size) { + val key = emails.keyAt(i) + contacts[key]?.emails = emails.valueAt(i) + } - val addresses = getAddresses() - size = addresses.size() - for (i in 0 until size) { - val key = addresses.keyAt(i) - contacts[key]?.addresses = addresses.valueAt(i) + val addresses = getAddresses() + size = addresses.size() + for (i in 0 until size) { + val key = addresses.keyAt(i) + contacts[key]?.addresses = addresses.valueAt(i) + } } - //getNotes() - activity.dbHelper.getContacts().forEach { contacts.put(it.id, it) } From 740dfb090e60397e93c4302ad917c5e69c15c4b5 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 18:06:16 +0100 Subject: [PATCH 43/53] add contact events when adding optional fields is active --- .../contacts/helpers/ContactsHelper.kt | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) 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 b224dd67..47790131 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -89,6 +89,13 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val key = addresses.keyAt(i) contacts[key]?.addresses = addresses.valueAt(i) } + + val events = getEvents() + size = events.size() + for (i in 0 until size) { + val key = events.keyAt(i) + contacts[key]?.events = events.valueAt(i) + } } activity.dbHelper.getContacts().forEach { @@ -216,28 +223,37 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return addresses } - private fun getEvents(contactId: Int): SparseArray> { + private fun getEvents(contactId: Int? = null): SparseArray> { val events = SparseArray>() val uri = ContactsContract.Data.CONTENT_URI val projection = arrayOf( + ContactsContract.Data.RAW_CONTACT_ID, CommonDataKinds.Event.START_DATE, CommonDataKinds.Event.TYPE ) - val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?" - val selectionArgs = arrayOf(contactId.toString(), CommonDataKinds.Event.CONTENT_ITEM_TYPE) + + var selection = "${ContactsContract.Data.MIMETYPE} = ?" + val selectionArgs = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE) + + if (contactId != null) { + selection += " AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?" + selectionArgs[1] = contactId.toString() + } + var cursor: Cursor? = null try { cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) if (cursor?.moveToFirst() == true) { do { - val startDate = cursor.getStringValue(CommonDataKinds.Event.START_DATE) + val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID) + val startDate = cursor.getStringValue(CommonDataKinds.Event.START_DATE) ?: continue val type = cursor.getIntValue(CommonDataKinds.Event.TYPE) - if (events[contactId] == null) { - events.put(contactId, ArrayList()) + if (events[id] == null) { + events.put(id, ArrayList()) } - events[contactId]!!.add(Event(startDate, type)) + events[id]!!.add(Event(startDate, type)) } while (cursor.moveToNext()) } } catch (e: Exception) { From eec5e3aa95c80aaec034f5af60cf44a1bf5b95e5 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 18:18:49 +0100 Subject: [PATCH 44/53] fix setting selectionArgs at a specific contact --- .../com/simplemobiletools/contacts/helpers/ContactsHelper.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 47790131..c4adc05b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -233,11 +233,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) { ) var selection = "${ContactsContract.Data.MIMETYPE} = ?" - val selectionArgs = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE) + var selectionArgs = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE) if (contactId != null) { selection += " AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?" - selectionArgs[1] = contactId.toString() + selectionArgs = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE, contactId.toString()) } var cursor: Cursor? = null From aea1ef464f03541e69d526decc3d07771ccc4ce3 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 18:22:53 +0100 Subject: [PATCH 45/53] adjust getNotes() so it gets all contact notes if needed --- .../contacts/helpers/ContactsHelper.kt | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) 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 c4adc05b..7afe551f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -96,6 +96,13 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val key = events.keyAt(i) contacts[key]?.events = events.valueAt(i) } + + val notes = getNotes() + size = notes.size() + for (i in 0 until size) { + val key = notes.keyAt(i) + contacts[key]?.notes = notes.valueAt(i) + } } activity.dbHelper.getContacts().forEach { @@ -265,17 +272,31 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return events } - private fun getNotes(contactId: Int): String { + private fun getNotes(contactId: Int? = null): SparseArray { + val notes = SparseArray() val uri = ContactsContract.Data.CONTENT_URI - val projection = arrayOf(Note.NOTE) - val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?" - val selectionArgs = arrayOf(contactId.toString(), Note.CONTENT_ITEM_TYPE) + val projection = arrayOf( + ContactsContract.Data.RAW_CONTACT_ID, + 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()) + } var cursor: Cursor? = null try { cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) if (cursor?.moveToFirst() == true) { - return cursor.getStringValue(CommonDataKinds.Note.NOTE) ?: "" + do { + val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID) + val note = cursor.getStringValue(CommonDataKinds.Note.NOTE) ?: continue + notes.put(id, note) + } while (cursor.moveToNext()) } } catch (e: Exception) { activity.showErrorToast(e) @@ -283,7 +304,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) { cursor?.close() } - return "" + return notes } fun getContactWithId(id: Int, isLocalPrivate: Boolean): Contact? { @@ -309,11 +330,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val emails = getEmails(id)[id] ?: ArrayList() val addresses = getAddresses(id)[id] ?: ArrayList() val events = getEvents(id)[id] ?: ArrayList() + val notes = getNotes(id)[id] ?: "" val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: "" val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - val notes = getNotes(id) return Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName, starred, contactId, thumbnailUri, null, notes) } } finally { From 6cc148b816dc27f42b6f7229da9515cf4c476844 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 18:37:15 +0100 Subject: [PATCH 46/53] make sure shared contacts have all appropriate fields filled --- .../contacts/adapters/ContactsAdapter.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 0e539d54..6250fbfe 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt @@ -163,12 +163,15 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList() + val contactsIDs = ArrayList() selectedPositions.forEach { - contacts.add(contactItems[it]) + contactsIDs.add(contactItems[it].id) } - activity.shareContacts(contacts) + ContactsHelper(activity).getContacts(true) { + val filtered = it.filter { contactsIDs.contains(it.id) } as ArrayList + activity.shareContacts(filtered) + } } override fun onViewRecycled(holder: ViewHolder?) { From 2c31cf5bc915dcaac8a6af5d440fe1880cd53b10 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 20:33:24 +0100 Subject: [PATCH 47/53] fix #78, properly return email at Get email intent --- .../activities/SelectContactActivity.kt | 30 +++++++++++++++---- .../contacts/helpers/ContactsHelper.kt | 18 +++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) 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 1d720db2..65a72dcf 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SelectContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SelectContactActivity.kt @@ -14,10 +14,13 @@ import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.adapters.SelectContactsAdapter import com.simplemobiletools.contacts.extensions.config import com.simplemobiletools.contacts.helpers.ContactsHelper +import com.simplemobiletools.contacts.helpers.SMT_PRIVATE import com.simplemobiletools.contacts.models.Contact import kotlinx.android.synthetic.main.layout_select_contact.* class SelectContactActivity : SimpleActivity() { + private var isGetEmailIntent = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.layout_select_contact) @@ -41,12 +44,20 @@ class SelectContactActivity : SimpleActivity() { } private fun initContacts() { - ContactsHelper(this).getContacts { - var contacts = it + isGetEmailIntent = intent.data == ContactsContract.CommonDataKinds.Email.CONTENT_URI + ContactsHelper(this).getContacts(true) { if (isActivityDestroyed()) { return@getContacts } + var contacts = it.filter { + if (isGetEmailIntent) { + (it.source != SMT_PRIVATE && it.emails.isNotEmpty()) + } else { + true + } + } as ArrayList + val contactSources = config.displayContactSources if (!config.showAllContacts()) { contacts = contacts.filter { contactSources.contains(it.source) } as ArrayList @@ -68,14 +79,21 @@ class SelectContactActivity : SimpleActivity() { } private fun confirmSelection(contact: Contact) { - val lookupKey = ContactsHelper(this).getContactLookupKey(contact.id.toString()) - val lookupUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey) - Intent().apply { - data = lookupUri + data = getResultUri(contact) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) setResult(RESULT_OK, this) } finish() } + + private fun getResultUri(contact: Contact): Uri { + return if (isGetEmailIntent) { + val emailID = ContactsHelper(this).getContactDataId(contact.id.toString()) + Uri.withAppendedPath(ContactsContract.Data.CONTENT_URI, emailID) + } else { + val lookupKey = ContactsHelper(this).getContactLookupKey(contact.id.toString()) + Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey) + } + } } 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 7afe551f..1c9c62cb 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -757,6 +757,24 @@ class ContactsHelper(val activity: BaseSimpleActivity) { return "" } + fun getContactDataId(contactId: String): String { + val uri = ContactsContract.Data.CONTENT_URI + val projection = arrayOf(ContactsContract.Data._ID, ContactsContract.Data.RAW_CONTACT_ID, ContactsContract.Data.MIMETYPE) + val selection = "${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?" + val selectionArgs = arrayOf(CommonDataKinds.Email.CONTENT_ITEM_TYPE, contactId) + + var cursor: Cursor? = null + try { + cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) + if (cursor?.moveToFirst() == true) { + return cursor.getStringValue(ContactsContract.Data._ID) + } + } finally { + cursor?.close() + } + return "" + } + fun addFavorites(contacts: ArrayList) { toggleLocalFavorites(contacts, true) toggleFavorites(contacts, true) From 2011464acfa2e39e6106bb835c225f98783d657a Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 20:54:01 +0100 Subject: [PATCH 48/53] add Filter and Sort menu items to the Select contact screen --- .../activities/SelectContactActivity.kt | 33 ++++++++++++++++++- .../main/res/menu/menu_select_activity.xml | 14 ++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/menu/menu_select_activity.xml 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 65a72dcf..c6b82f3e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SelectContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/SelectContactActivity.kt @@ -4,6 +4,8 @@ import android.content.Intent import android.net.Uri 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 @@ -12,6 +14,8 @@ import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CONTACTS import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.adapters.SelectContactsAdapter +import com.simplemobiletools.contacts.dialogs.ChangeSortingDialog +import com.simplemobiletools.contacts.dialogs.FilterContactSourcesDialog import com.simplemobiletools.contacts.extensions.config import com.simplemobiletools.contacts.helpers.ContactsHelper import com.simplemobiletools.contacts.helpers.SMT_PRIVATE @@ -30,6 +34,7 @@ class SelectContactActivity : SimpleActivity() { if (it) { handlePermission(PERMISSION_WRITE_CONTACTS) { if (it) { + isGetEmailIntent = intent.data == ContactsContract.CommonDataKinds.Email.CONTENT_URI initContacts() } else { toast(R.string.no_contacts_permission) @@ -43,8 +48,33 @@ class SelectContactActivity : SimpleActivity() { } } + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.menu_select_activity, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.sort -> showSortingDialog() + R.id.filter -> showFilterDialog() + else -> return super.onOptionsItemSelected(item) + } + return true + } + + private fun showSortingDialog() { + ChangeSortingDialog(this) { + initContacts() + } + } + + private fun showFilterDialog() { + FilterContactSourcesDialog(this) { + initContacts() + } + } + private fun initContacts() { - isGetEmailIntent = intent.data == ContactsContract.CommonDataKinds.Email.CONTENT_URI ContactsHelper(this).getContacts(true) { if (isActivityDestroyed()) { return@getContacts @@ -70,6 +100,7 @@ class SelectContactActivity : SimpleActivity() { select_contact_list.adapter = SelectContactsAdapter(this, contacts, ArrayList(), false) { confirmSelection(it) } + select_contact_fastscroller.allowBubbleDisplay = baseConfig.showInfoBubble select_contact_fastscroller.setViews(select_contact_list) { select_contact_fastscroller.updateBubbleText(contacts[it].getBubbleText()) diff --git a/app/src/main/res/menu/menu_select_activity.xml b/app/src/main/res/menu/menu_select_activity.xml new file mode 100644 index 00000000..a914825b --- /dev/null +++ b/app/src/main/res/menu/menu_select_activity.xml @@ -0,0 +1,14 @@ + + + + + From 3d7f14039bc1d94873cf718f9d97f23680909bd9 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 21:06:00 +0100 Subject: [PATCH 49/53] update commons to 3.12.20 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 8c00a793..42cdc704 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -45,7 +45,7 @@ ext { } dependencies { - implementation 'com.simplemobiletools:commons:3.12.16' + implementation 'com.simplemobiletools:commons:3.12.20' implementation 'joda-time:joda-time:2.9.9' implementation 'com.facebook.stetho:stetho:1.5.0' implementation 'com.google.code.gson:gson:2.8.2' From ec0dbd23e1a7c0dabb1f6c121477fea4e1c9acae Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 21:08:14 +0100 Subject: [PATCH 50/53] add Address and Notes in release notes --- .../com/simplemobiletools/contacts/activities/MainActivity.kt | 1 + app/src/main/res/values/donottranslate.xml | 1 + 2 files changed, 2 insertions(+) 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 68cc440d..68c98bca 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt @@ -396,6 +396,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener { private fun checkWhatsNewDialog() { arrayListOf().apply { add(Release(10, R.string.release_10)) + add(Release(11, R.string.release_11)) checkWhatsNew(this, BuildConfig.VERSION_CODE) } } diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index 58053e11..1943508d 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -2,6 +2,7 @@ + Added Address and Notes fields Allow storing contacts in a local database, hidden from other apps From 88bcaf8c0c184e284284a0bbaeafe35c09118cc0 Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 21:09:06 +0100 Subject: [PATCH 51/53] update version to 3.3.0 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 42cdc704..21c2d2ea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.simplemobiletools.contacts" minSdkVersion 16 targetSdkVersion 27 - versionCode 10 - versionName "3.2.0" + versionCode 11 + versionName "3.3.0" setProperty("archivesBaseName", "contacts") } From ff3de208b92560436a9254553a6388e218e98f5f Mon Sep 17 00:00:00 2001 From: tibbi Date: Thu, 22 Feb 2018 21:09:12 +0100 Subject: [PATCH 52/53] updating changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17b4d282..315a7e95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ Changelog ========== +Version 3.3.0 *(2018-02-22)* +---------------------------- + + * Added Address and Notes fields + * Properly handle Get Email intent + * Fixed some glitches at exporting contacts + * Added FAQ + Version 3.2.0 *(2018-02-11)* ---------------------------- From c33906a874e50b4b7eba704d39cf2e5d22c14175 Mon Sep 17 00:00:00 2001 From: tibbi Date: Mon, 26 Feb 2018 17:17:04 +0100 Subject: [PATCH 53/53] making some views nullable --- .../contacts/activities/MainActivity.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 68c98bca..aa37373e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/MainActivity.kt @@ -196,13 +196,13 @@ class MainActivity : SimpleActivity(), RefreshContactsListener { MenuItemCompat.setOnActionExpandListener(searchMenuItem, object : MenuItemCompat.OnActionExpandListener { override fun onMenuItemActionExpand(item: MenuItem?): Boolean { - getCurrentFragment().onSearchOpened() + getCurrentFragment()?.onSearchOpened() isSearchOpen = true return true } override fun onMenuItemActionCollapse(item: MenuItem?): Boolean { - getCurrentFragment().onSearchClosed() + getCurrentFragment()?.onSearchClosed() isSearchOpen = false return true } @@ -291,15 +291,15 @@ class MainActivity : SimpleActivity(), RefreshContactsListener { private fun showSortingDialog() { ChangeSortingDialog(this) { - contacts_fragment.initContacts() - favorites_fragment.initContacts() + contacts_fragment?.initContacts() + favorites_fragment?.initContacts() } } fun showFilterDialog() { FilterContactSourcesDialog(this) { - contacts_fragment.forceListRedraw = true - contacts_fragment.initContacts() + contacts_fragment?.forceListRedraw = true + contacts_fragment?.initContacts() } }