mirror of
https://github.com/SimpleMobileTools/Simple-Contacts.git
synced 2025-06-05 21:59:27 +02:00
15
CHANGELOG.md
15
CHANGELOG.md
@ -1,6 +1,21 @@
|
|||||||
Changelog
|
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)*
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
* 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)*
|
Version 3.1.4 *(2018-02-03)*
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ android {
|
|||||||
applicationId "com.simplemobiletools.contacts"
|
applicationId "com.simplemobiletools.contacts"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 27
|
targetSdkVersion 27
|
||||||
versionCode 9
|
versionCode 11
|
||||||
versionName "3.1.4"
|
versionName "3.3.0"
|
||||||
setProperty("archivesBaseName", "contacts")
|
setProperty("archivesBaseName", "contacts")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,8 +45,10 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.simplemobiletools:commons:3.11.3'
|
implementation 'com.simplemobiletools:commons:3.12.20'
|
||||||
implementation 'joda-time:joda-time:2.9.9'
|
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"
|
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"
|
||||||
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"
|
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"
|
||||||
|
@ -172,6 +172,11 @@
|
|||||||
android:label="@string/customize_colors"
|
android:label="@string/customize_colors"
|
||||||
android:parentActivityName=".activities.SettingsActivity"/>
|
android:parentActivityName=".activities.SettingsActivity"/>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="com.simplemobiletools.commons.activities.FAQActivity"
|
||||||
|
android:label="@string/frequently_asked_questions"
|
||||||
|
android:parentActivityName="com.simplemobiletools.commons.activities.AboutActivity"/>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="android.support.v4.content.FileProvider"
|
android:name="android.support.v4.content.FileProvider"
|
||||||
android:authorities="${applicationId}.provider"
|
android:authorities="${applicationId}.provider"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.simplemobiletools.contacts
|
package com.simplemobiletools.contacts
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import com.facebook.stetho.Stetho
|
||||||
import com.simplemobiletools.commons.extensions.checkUseEnglish
|
import com.simplemobiletools.commons.extensions.checkUseEnglish
|
||||||
import com.squareup.leakcanary.LeakCanary
|
import com.squareup.leakcanary.LeakCanary
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ class App : Application() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
LeakCanary.install(this)
|
LeakCanary.install(this)
|
||||||
|
Stetho.initializeWithDefaults(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkUseEnglish()
|
checkUseEnglish()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.simplemobiletools.contacts.activities
|
package com.simplemobiletools.contacts.activities
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
@ -41,16 +42,17 @@ abstract class ContactActivity : SimpleActivity() {
|
|||||||
photoView.setPadding(padding, padding, padding, padding)
|
photoView.setPadding(padding, padding, padding, padding)
|
||||||
photoView.setImageBitmap(placeholder)
|
photoView.setImageBitmap(placeholder)
|
||||||
currentContactPhotoPath = ""
|
currentContactPhotoPath = ""
|
||||||
|
contact?.photo = null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateContactPhoto(path: String, photoView: ImageView) {
|
fun updateContactPhoto(path: String, photoView: ImageView, bitmap: Bitmap? = null) {
|
||||||
currentContactPhotoPath = path
|
currentContactPhotoPath = path
|
||||||
val options = RequestOptions()
|
val options = RequestOptions()
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
|
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.load(path)
|
.load(bitmap ?: path)
|
||||||
.transition(DrawableTransitionOptions.withCrossFade())
|
.transition(DrawableTransitionOptions.withCrossFade())
|
||||||
.apply(options)
|
.apply(options)
|
||||||
.listener(object : RequestListener<Drawable> {
|
.listener(object : RequestListener<Drawable> {
|
||||||
@ -152,6 +154,12 @@ abstract class ContactActivity : SimpleActivity() {
|
|||||||
else -> R.string.other
|
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) {
|
fun getEventTextId(type: Int) = when (type) {
|
||||||
ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY -> R.string.birthday
|
ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY -> R.string.birthday
|
||||||
ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY -> R.string.anniversary
|
ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY -> R.string.anniversary
|
||||||
|
@ -22,11 +22,9 @@ import com.simplemobiletools.commons.models.RadioItem
|
|||||||
import com.simplemobiletools.contacts.R
|
import com.simplemobiletools.contacts.R
|
||||||
import com.simplemobiletools.contacts.extensions.*
|
import com.simplemobiletools.contacts.extensions.*
|
||||||
import com.simplemobiletools.contacts.helpers.*
|
import com.simplemobiletools.contacts.helpers.*
|
||||||
import com.simplemobiletools.contacts.models.Contact
|
import com.simplemobiletools.contacts.models.*
|
||||||
import com.simplemobiletools.contacts.models.Email
|
|
||||||
import com.simplemobiletools.contacts.models.Event
|
|
||||||
import com.simplemobiletools.contacts.models.PhoneNumber
|
|
||||||
import kotlinx.android.synthetic.main.activity_edit_contact.*
|
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_email.view.*
|
||||||
import kotlinx.android.synthetic.main.item_edit_phone_number.view.*
|
import kotlinx.android.synthetic.main.item_edit_phone_number.view.*
|
||||||
import kotlinx.android.synthetic.main.item_event.view.*
|
import kotlinx.android.synthetic.main.item_event.view.*
|
||||||
@ -35,6 +33,11 @@ import org.joda.time.format.DateTimeFormat
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class EditContactActivity : ContactActivity() {
|
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_TAKE_PHOTO = 1
|
||||||
private val INTENT_CHOOSE_PHOTO = 2
|
private val INTENT_CHOOSE_PHOTO = 2
|
||||||
private val INTENT_CROP_PHOTO = 3
|
private val INTENT_CROP_PHOTO = 3
|
||||||
@ -94,7 +97,7 @@ class EditContactActivity : ContactActivity() {
|
|||||||
super.onActivityResult(requestCode, resultCode, resultData)
|
super.onActivityResult(requestCode, resultCode, resultData)
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
when (requestCode) {
|
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)
|
INTENT_CROP_PHOTO -> updateContactPhoto(lastPhotoIntentUri.toString(), contact_photo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +122,7 @@ class EditContactActivity : ContactActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (contactId != 0) {
|
if (contactId != 0) {
|
||||||
contact = ContactsHelper(this).getContactWithId(contactId)
|
contact = ContactsHelper(this).getContactWithId(contactId, intent.getBooleanExtra(IS_PRIVATE, false))
|
||||||
if (contact == null) {
|
if (contact == null) {
|
||||||
toast(R.string.unknown_error_occurred)
|
toast(R.string.unknown_error_occurred)
|
||||||
finish()
|
finish()
|
||||||
@ -146,10 +149,10 @@ class EditContactActivity : ContactActivity() {
|
|||||||
|
|
||||||
contact_photo.background = ColorDrawable(config.primaryColor)
|
contact_photo.background = ColorDrawable(config.primaryColor)
|
||||||
|
|
||||||
if (contact!!.photoUri.isEmpty()) {
|
if (contact!!.photoUri.isEmpty() && contact!!.photo == null) {
|
||||||
showPhotoPlaceholder(contact_photo)
|
showPhotoPlaceholder(contact_photo)
|
||||||
} else {
|
} else {
|
||||||
updateContactPhoto(contact!!.photoUri, contact_photo)
|
updateContactPhoto(contact!!.photoUri, contact_photo, contact!!.photo)
|
||||||
}
|
}
|
||||||
|
|
||||||
val textColor = config.textColor
|
val textColor = config.textColor
|
||||||
@ -159,7 +162,9 @@ class EditContactActivity : ContactActivity() {
|
|||||||
contact_name_image.applyColorFilter(textColor)
|
contact_name_image.applyColorFilter(textColor)
|
||||||
contact_number_image.applyColorFilter(textColor)
|
contact_number_image.applyColorFilter(textColor)
|
||||||
contact_email_image.applyColorFilter(textColor)
|
contact_email_image.applyColorFilter(textColor)
|
||||||
|
contact_address_image.applyColorFilter(textColor)
|
||||||
contact_event_image.applyColorFilter(textColor)
|
contact_event_image.applyColorFilter(textColor)
|
||||||
|
contact_notes_image.applyColorFilter(textColor)
|
||||||
contact_source_image.applyColorFilter(textColor)
|
contact_source_image.applyColorFilter(textColor)
|
||||||
|
|
||||||
val adjustedPrimaryColor = getAdjustedPrimaryColor()
|
val adjustedPrimaryColor = getAdjustedPrimaryColor()
|
||||||
@ -167,6 +172,8 @@ class EditContactActivity : ContactActivity() {
|
|||||||
contact_number_add_new.background.applyColorFilter(textColor)
|
contact_number_add_new.background.applyColorFilter(textColor)
|
||||||
contact_email_add_new.applyColorFilter(adjustedPrimaryColor)
|
contact_email_add_new.applyColorFilter(adjustedPrimaryColor)
|
||||||
contact_email_add_new.background.applyColorFilter(textColor)
|
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.applyColorFilter(adjustedPrimaryColor)
|
||||||
contact_event_add_new.background.applyColorFilter(textColor)
|
contact_event_add_new.background.applyColorFilter(textColor)
|
||||||
|
|
||||||
@ -177,6 +184,7 @@ class EditContactActivity : ContactActivity() {
|
|||||||
contact_send_email.setOnClickListener { trySendEmail() }
|
contact_send_email.setOnClickListener { trySendEmail() }
|
||||||
contact_number_add_new.setOnClickListener { addNewPhoneNumberField() }
|
contact_number_add_new.setOnClickListener { addNewPhoneNumberField() }
|
||||||
contact_email_add_new.setOnClickListener { addNewEmailField() }
|
contact_email_add_new.setOnClickListener { addNewEmailField() }
|
||||||
|
contact_address_add_new.setOnClickListener { addNewAddressField() }
|
||||||
contact_event_add_new.setOnClickListener { addNewEventField() }
|
contact_event_add_new.setOnClickListener { addNewEventField() }
|
||||||
|
|
||||||
contact_toggle_favorite.apply {
|
contact_toggle_favorite.apply {
|
||||||
@ -190,7 +198,12 @@ class EditContactActivity : ContactActivity() {
|
|||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startCropPhotoIntent(uri: Uri) {
|
private fun startCropPhotoIntent(uri: Uri?) {
|
||||||
|
if (uri == null) {
|
||||||
|
toast(R.string.unknown_error_occurred)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
lastPhotoIntentUri = getCachePhotoUri()
|
lastPhotoIntentUri = getCachePhotoUri()
|
||||||
Intent("com.android.camera.action.CROP").apply {
|
Intent("com.android.camera.action.CROP").apply {
|
||||||
setDataAndType(uri, "image/*")
|
setDataAndType(uri, "image/*")
|
||||||
@ -204,7 +217,11 @@ class EditContactActivity : ContactActivity() {
|
|||||||
putExtra("scaleUpIfNeeded", "true")
|
putExtra("scaleUpIfNeeded", "true")
|
||||||
clipData = ClipData("Attachment", arrayOf("text/uri-list"), ClipData.Item(lastPhotoIntentUri))
|
clipData = ClipData("Attachment", arrayOf("text/uri-list"), ClipData.Item(lastPhotoIntentUri))
|
||||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,6 +235,8 @@ class EditContactActivity : ContactActivity() {
|
|||||||
|
|
||||||
setupPhoneNumbers()
|
setupPhoneNumbers()
|
||||||
setupEmails()
|
setupEmails()
|
||||||
|
setupAddresses()
|
||||||
|
setupNotes()
|
||||||
setupEvents()
|
setupEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,6 +270,25 @@ 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 setupNotes() {
|
||||||
|
contact_notes.setText(contact!!.notes)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupEvents() {
|
private fun setupEvents() {
|
||||||
contact!!.events.forEachIndexed { index, event ->
|
contact!!.events.forEachIndexed { index, event ->
|
||||||
var eventHolder = contact_events_holder.getChildAt(index)
|
var eventHolder = contact_events_holder.getChildAt(index)
|
||||||
@ -283,7 +321,7 @@ class EditContactActivity : ContactActivity() {
|
|||||||
private fun setupNewContact() {
|
private fun setupNewContact() {
|
||||||
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
|
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
|
||||||
supportActionBar?.title = resources.getString(R.string.new_contact)
|
supportActionBar?.title = resources.getString(R.string.new_contact)
|
||||||
contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "")
|
contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "", null, "")
|
||||||
contact_source.text = getPublicContactSource(contact!!.source)
|
contact_source.text = getPublicContactSource(contact!!.source)
|
||||||
contact_source.setOnClickListener {
|
contact_source.setOnClickListener {
|
||||||
showContactSourcePicker(contact!!.source) {
|
showContactSourcePicker(contact!!.source) {
|
||||||
@ -308,6 +346,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()) {
|
if (contact!!.events.isEmpty()) {
|
||||||
val eventHolder = contact_events_holder.getChildAt(0)
|
val eventHolder = contact_events_holder.getChildAt(0)
|
||||||
(eventHolder as? ViewGroup)?.apply {
|
(eventHolder as? ViewGroup)?.apply {
|
||||||
@ -334,6 +379,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) {
|
private fun setupEventTypePicker(eventHolder: ViewGroup, type: Int = DEFAULT_EVENT_TYPE) {
|
||||||
eventHolder.contact_event_type.apply {
|
eventHolder.contact_event_type.apply {
|
||||||
setText(getEventTextId(type))
|
setText(getEventTextId(type))
|
||||||
@ -409,6 +463,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) {
|
private fun showEventTypePicker(eventTypeField: TextView) {
|
||||||
val items = arrayListOf(
|
val items = arrayListOf(
|
||||||
RadioItem(CommonDataKinds.Event.TYPE_BIRTHDAY, getString(R.string.birthday)),
|
RadioItem(CommonDataKinds.Event.TYPE_BIRTHDAY, getString(R.string.birthday)),
|
||||||
@ -436,9 +503,11 @@ class EditContactActivity : ContactActivity() {
|
|||||||
photoUri = currentContactPhotoPath
|
photoUri = currentContactPhotoPath
|
||||||
phoneNumbers = getFilledPhoneNumbers()
|
phoneNumbers = getFilledPhoneNumbers()
|
||||||
emails = getFilledEmails()
|
emails = getFilledEmails()
|
||||||
|
addresses = getFilledAddresses()
|
||||||
events = getFilledEvents()
|
events = getFilledEvents()
|
||||||
source = contact!!.source
|
source = contact!!.source
|
||||||
starred = if (isContactStarred()) 1 else 0
|
starred = if (isContactStarred()) 1 else 0
|
||||||
|
notes = contact_notes.value
|
||||||
|
|
||||||
Thread {
|
Thread {
|
||||||
config.lastUsedContactSource = source
|
config.lastUsedContactSource = source
|
||||||
@ -482,6 +551,21 @@ class EditContactActivity : ContactActivity() {
|
|||||||
return emails
|
return emails
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getFilledAddresses(): ArrayList<Address> {
|
||||||
|
val addresses = ArrayList<Address>()
|
||||||
|
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<Event> {
|
private fun getFilledEvents(): ArrayList<Event> {
|
||||||
val unknown = getString(R.string.unknown)
|
val unknown = getString(R.string.unknown)
|
||||||
val events = ArrayList<Event>()
|
val events = ArrayList<Event>()
|
||||||
@ -551,6 +635,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() {
|
private fun addNewEventField() {
|
||||||
val eventHolder = layoutInflater.inflate(R.layout.item_event, contact_events_holder, false) as ViewGroup
|
val eventHolder = layoutInflater.inflate(R.layout.item_event, contact_events_holder, false) as ViewGroup
|
||||||
updateTextColors(eventHolder)
|
updateTextColors(eventHolder)
|
||||||
@ -577,7 +672,7 @@ class EditContactActivity : ContactActivity() {
|
|||||||
RadioItem(CHOOSE_PHOTO, getString(R.string.choose_photo))
|
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)))
|
items.add(RadioItem(REMOVE_PHOTO, getString(R.string.remove_photo)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -642,4 +737,10 @@ class EditContactActivity : ContactActivity() {
|
|||||||
getString(R.string.anniversary) -> CommonDataKinds.Event.TYPE_ANNIVERSARY
|
getString(R.string.anniversary) -> CommonDataKinds.Event.TYPE_ANNIVERSARY
|
||||||
else -> CommonDataKinds.Event.TYPE_OTHER
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ import android.view.MenuItem
|
|||||||
import com.simplemobiletools.commons.dialogs.FilePickerDialog
|
import com.simplemobiletools.commons.dialogs.FilePickerDialog
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.*
|
import com.simplemobiletools.commons.helpers.*
|
||||||
|
import com.simplemobiletools.commons.models.FAQItem
|
||||||
|
import com.simplemobiletools.commons.models.Release
|
||||||
import com.simplemobiletools.contacts.BuildConfig
|
import com.simplemobiletools.contacts.BuildConfig
|
||||||
import com.simplemobiletools.contacts.R
|
import com.simplemobiletools.contacts.R
|
||||||
import com.simplemobiletools.contacts.adapters.ViewPagerAdapter
|
import com.simplemobiletools.contacts.adapters.ViewPagerAdapter
|
||||||
@ -69,6 +71,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
storeStateVariables()
|
storeStateVariables()
|
||||||
|
checkWhatsNewDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@ -105,8 +108,8 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
|||||||
if (storedPrimaryColor != configPrimaryColor) {
|
if (storedPrimaryColor != configPrimaryColor) {
|
||||||
main_tabs_holder.setSelectedTabIndicatorColor(getAdjustedPrimaryColor())
|
main_tabs_holder.setSelectedTabIndicatorColor(getAdjustedPrimaryColor())
|
||||||
main_tabs_holder.getTabAt(viewpager.currentItem)?.icon?.applyColorFilter(getAdjustedPrimaryColor())
|
main_tabs_holder.getTabAt(viewpager.currentItem)?.icon?.applyColorFilter(getAdjustedPrimaryColor())
|
||||||
contacts_fragment.primaryColorChanged(configPrimaryColor)
|
contacts_fragment.primaryColorChanged()
|
||||||
favorites_fragment.primaryColorChanged(configPrimaryColor)
|
favorites_fragment.primaryColorChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
val configStartNameWithSurname = config.startNameWithSurname
|
val configStartNameWithSurname = config.startNameWithSurname
|
||||||
@ -119,12 +122,16 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
|||||||
if (viewpager.adapter == null) {
|
if (viewpager.adapter == null) {
|
||||||
initFragments()
|
initFragments()
|
||||||
}
|
}
|
||||||
|
|
||||||
contacts_fragment?.initContacts()
|
contacts_fragment?.initContacts()
|
||||||
contacts_fragment?.onActivityResume()
|
contacts_fragment?.onActivityResume()
|
||||||
favorites_fragment?.initContacts()
|
favorites_fragment?.initContacts()
|
||||||
favorites_fragment?.onActivityResume()
|
favorites_fragment?.onActivityResume()
|
||||||
}
|
}
|
||||||
isFirstResume = false
|
|
||||||
|
if (hasPermission(PERMISSION_WRITE_CONTACTS)) {
|
||||||
|
isFirstResume = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
@ -189,13 +196,13 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
|||||||
|
|
||||||
MenuItemCompat.setOnActionExpandListener(searchMenuItem, object : MenuItemCompat.OnActionExpandListener {
|
MenuItemCompat.setOnActionExpandListener(searchMenuItem, object : MenuItemCompat.OnActionExpandListener {
|
||||||
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
||||||
getCurrentFragment().onSearchOpened()
|
getCurrentFragment()?.onSearchOpened()
|
||||||
isSearchOpen = true
|
isSearchOpen = true
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
||||||
getCurrentFragment().onSearchClosed()
|
getCurrentFragment()?.onSearchClosed()
|
||||||
isSearchOpen = false
|
isSearchOpen = false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -284,15 +291,15 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
|||||||
|
|
||||||
private fun showSortingDialog() {
|
private fun showSortingDialog() {
|
||||||
ChangeSortingDialog(this) {
|
ChangeSortingDialog(this) {
|
||||||
contacts_fragment.initContacts()
|
contacts_fragment?.initContacts()
|
||||||
favorites_fragment.initContacts()
|
favorites_fragment?.initContacts()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showFilterDialog() {
|
fun showFilterDialog() {
|
||||||
FilterContactSourcesDialog(this) {
|
FilterContactSourcesDialog(this) {
|
||||||
contacts_fragment.forceListRedraw = true
|
contacts_fragment?.forceListRedraw = true
|
||||||
contacts_fragment.initContacts()
|
contacts_fragment?.initContacts()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +358,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
|||||||
FilePickerDialog(this, pickFile = false, showFAB = true) {
|
FilePickerDialog(this, pickFile = false, showFAB = true) {
|
||||||
ExportContactsDialog(this, it) { file, contactSources ->
|
ExportContactsDialog(this, it) { file, contactSources ->
|
||||||
Thread {
|
Thread {
|
||||||
ContactsHelper(this).getContacts {
|
ContactsHelper(this).getContacts(true) {
|
||||||
val contacts = it.filter { contactSources.contains(it.source) }
|
val contacts = it.filter { contactSources.contains(it.source) }
|
||||||
if (contacts.isEmpty()) {
|
if (contacts.isEmpty()) {
|
||||||
toast(R.string.no_entries_for_exporting)
|
toast(R.string.no_entries_for_exporting)
|
||||||
@ -372,7 +379,9 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun launchAbout() {
|
private fun launchAbout() {
|
||||||
startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_MULTISELECT or LICENSE_JODA or LICENSE_GLIDE, BuildConfig.VERSION_NAME)
|
val faqItems = arrayListOf(FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons))
|
||||||
|
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, faqItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun refreshContacts() {
|
override fun refreshContacts() {
|
||||||
@ -383,4 +392,12 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
|||||||
override fun refreshFavorites() {
|
override fun refreshFavorites() {
|
||||||
favorites_fragment?.initContacts()
|
favorites_fragment?.initContacts()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkWhatsNewDialog() {
|
||||||
|
arrayListOf<Release>().apply {
|
||||||
|
add(Release(10, R.string.release_10))
|
||||||
|
add(Release(11, R.string.release_11))
|
||||||
|
checkWhatsNew(this, BuildConfig.VERSION_CODE)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
import com.simplemobiletools.commons.extensions.appLaunched
|
import com.simplemobiletools.commons.extensions.appLaunched
|
||||||
import com.simplemobiletools.commons.extensions.baseConfig
|
import com.simplemobiletools.commons.extensions.baseConfig
|
||||||
import com.simplemobiletools.commons.extensions.isActivityDestroyed
|
import com.simplemobiletools.commons.extensions.isActivityDestroyed
|
||||||
@ -12,12 +14,17 @@ import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS
|
|||||||
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CONTACTS
|
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CONTACTS
|
||||||
import com.simplemobiletools.contacts.R
|
import com.simplemobiletools.contacts.R
|
||||||
import com.simplemobiletools.contacts.adapters.SelectContactsAdapter
|
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.extensions.config
|
||||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||||
|
import com.simplemobiletools.contacts.helpers.SMT_PRIVATE
|
||||||
import com.simplemobiletools.contacts.models.Contact
|
import com.simplemobiletools.contacts.models.Contact
|
||||||
import kotlinx.android.synthetic.main.layout_select_contact.*
|
import kotlinx.android.synthetic.main.layout_select_contact.*
|
||||||
|
|
||||||
class SelectContactActivity : SimpleActivity() {
|
class SelectContactActivity : SimpleActivity() {
|
||||||
|
private var isGetEmailIntent = false
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.layout_select_contact)
|
setContentView(R.layout.layout_select_contact)
|
||||||
@ -27,6 +34,7 @@ class SelectContactActivity : SimpleActivity() {
|
|||||||
if (it) {
|
if (it) {
|
||||||
handlePermission(PERMISSION_WRITE_CONTACTS) {
|
handlePermission(PERMISSION_WRITE_CONTACTS) {
|
||||||
if (it) {
|
if (it) {
|
||||||
|
isGetEmailIntent = intent.data == ContactsContract.CommonDataKinds.Email.CONTENT_URI
|
||||||
initContacts()
|
initContacts()
|
||||||
} else {
|
} else {
|
||||||
toast(R.string.no_contacts_permission)
|
toast(R.string.no_contacts_permission)
|
||||||
@ -40,13 +48,46 @@ 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() {
|
private fun initContacts() {
|
||||||
ContactsHelper(this).getContacts {
|
ContactsHelper(this).getContacts(true) {
|
||||||
var contacts = it
|
|
||||||
if (isActivityDestroyed()) {
|
if (isActivityDestroyed()) {
|
||||||
return@getContacts
|
return@getContacts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var contacts = it.filter {
|
||||||
|
if (isGetEmailIntent) {
|
||||||
|
(it.source != SMT_PRIVATE && it.emails.isNotEmpty())
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} as ArrayList<Contact>
|
||||||
|
|
||||||
val contactSources = config.displayContactSources
|
val contactSources = config.displayContactSources
|
||||||
if (!config.showAllContacts()) {
|
if (!config.showAllContacts()) {
|
||||||
contacts = contacts.filter { contactSources.contains(it.source) } as ArrayList<Contact>
|
contacts = contacts.filter { contactSources.contains(it.source) } as ArrayList<Contact>
|
||||||
@ -59,6 +100,7 @@ class SelectContactActivity : SimpleActivity() {
|
|||||||
select_contact_list.adapter = SelectContactsAdapter(this, contacts, ArrayList(), false) {
|
select_contact_list.adapter = SelectContactsAdapter(this, contacts, ArrayList(), false) {
|
||||||
confirmSelection(it)
|
confirmSelection(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
select_contact_fastscroller.allowBubbleDisplay = baseConfig.showInfoBubble
|
select_contact_fastscroller.allowBubbleDisplay = baseConfig.showInfoBubble
|
||||||
select_contact_fastscroller.setViews(select_contact_list) {
|
select_contact_fastscroller.setViews(select_contact_list) {
|
||||||
select_contact_fastscroller.updateBubbleText(contacts[it].getBubbleText())
|
select_contact_fastscroller.updateBubbleText(contacts[it].getBubbleText())
|
||||||
@ -68,14 +110,21 @@ class SelectContactActivity : SimpleActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun confirmSelection(contact: Contact) {
|
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 {
|
Intent().apply {
|
||||||
data = lookupUri
|
data = getResultUri(contact)
|
||||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
setResult(RESULT_OK, this)
|
setResult(RESULT_OK, this)
|
||||||
}
|
}
|
||||||
finish()
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,17 +6,18 @@ import android.os.Bundle
|
|||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.TextView
|
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS
|
import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS
|
||||||
import com.simplemobiletools.contacts.R
|
import com.simplemobiletools.contacts.R
|
||||||
import com.simplemobiletools.contacts.extensions.*
|
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.activity_view_contact.*
|
||||||
import kotlinx.android.synthetic.main.item_event.view.*
|
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_email.view.*
|
||||||
import kotlinx.android.synthetic.main.item_view_phone_number.view.*
|
import kotlinx.android.synthetic.main.item_view_phone_number.view.*
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ class ViewContactActivity : ContactActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (contactId != 0) {
|
if (contactId != 0) {
|
||||||
contact = ContactsHelper(this).getContactWithId(contactId)
|
contact = ContactsHelper(this).getContactWithId(contactId, intent.getBooleanExtra(IS_PRIVATE, false))
|
||||||
if (contact == null) {
|
if (contact == null) {
|
||||||
toast(R.string.unknown_error_occurred)
|
toast(R.string.unknown_error_occurred)
|
||||||
finish()
|
finish()
|
||||||
@ -89,19 +90,18 @@ class ViewContactActivity : ContactActivity() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setupEditContact()
|
setupViewContact()
|
||||||
|
|
||||||
setupTypePickers()
|
|
||||||
contact_send_sms.beVisibleIf(contact!!.phoneNumbers.isNotEmpty())
|
contact_send_sms.beVisibleIf(contact!!.phoneNumbers.isNotEmpty())
|
||||||
contact_start_call.beVisibleIf(contact!!.phoneNumbers.isNotEmpty())
|
contact_start_call.beVisibleIf(contact!!.phoneNumbers.isNotEmpty())
|
||||||
contact_send_email.beVisibleIf(contact!!.emails.isNotEmpty())
|
contact_send_email.beVisibleIf(contact!!.emails.isNotEmpty())
|
||||||
|
|
||||||
contact_photo.background = ColorDrawable(config.primaryColor)
|
contact_photo.background = ColorDrawable(config.primaryColor)
|
||||||
|
|
||||||
if (contact!!.photoUri.isEmpty()) {
|
if (contact!!.photoUri.isEmpty() && contact!!.photo == null) {
|
||||||
showPhotoPlaceholder(contact_photo)
|
showPhotoPlaceholder(contact_photo)
|
||||||
} else {
|
} else {
|
||||||
updateContactPhoto(contact!!.photoUri, contact_photo)
|
updateContactPhoto(contact!!.photoUri, contact_photo, contact!!.photo)
|
||||||
}
|
}
|
||||||
|
|
||||||
val textColor = config.textColor
|
val textColor = config.textColor
|
||||||
@ -113,6 +113,7 @@ class ViewContactActivity : ContactActivity() {
|
|||||||
contact_email_image.applyColorFilter(textColor)
|
contact_email_image.applyColorFilter(textColor)
|
||||||
contact_event_image.applyColorFilter(textColor)
|
contact_event_image.applyColorFilter(textColor)
|
||||||
contact_source_image.applyColorFilter(textColor)
|
contact_source_image.applyColorFilter(textColor)
|
||||||
|
contact_notes_image.applyColorFilter(textColor)
|
||||||
|
|
||||||
contact_send_sms.setOnClickListener { trySendSMS() }
|
contact_send_sms.setOnClickListener { trySendSMS() }
|
||||||
contact_start_call.setOnClickListener { tryStartCall(contact!!) }
|
contact_start_call.setOnClickListener { tryStartCall(contact!!) }
|
||||||
@ -122,7 +123,7 @@ class ViewContactActivity : ContactActivity() {
|
|||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupEditContact() {
|
private fun setupViewContact() {
|
||||||
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
|
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
|
||||||
contact!!.apply {
|
contact!!.apply {
|
||||||
contact_first_name.text = firstName
|
contact_first_name.text = firstName
|
||||||
@ -150,21 +151,19 @@ class ViewContactActivity : ContactActivity() {
|
|||||||
|
|
||||||
setupPhoneNumbers()
|
setupPhoneNumbers()
|
||||||
setupEmails()
|
setupEmails()
|
||||||
|
setupAddresses()
|
||||||
setupEvents()
|
setupEvents()
|
||||||
|
setupNotes()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupPhoneNumbers() {
|
private fun setupPhoneNumbers() {
|
||||||
|
contact_numbers_holder.removeAllViews()
|
||||||
val phoneNumbers = contact!!.phoneNumbers
|
val phoneNumbers = contact!!.phoneNumbers
|
||||||
phoneNumbers.forEachIndexed { index, number ->
|
phoneNumbers.forEach {
|
||||||
var numberHolder = contact_numbers_holder.getChildAt(index)
|
layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false).apply {
|
||||||
if (numberHolder == null) {
|
contact_numbers_holder.addView(this)
|
||||||
numberHolder = layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false)
|
contact_number.text = it.value
|
||||||
contact_numbers_holder.addView(numberHolder)
|
contact_number_type.setText(getPhoneNumberTextId(it.type))
|
||||||
}
|
|
||||||
|
|
||||||
numberHolder!!.apply {
|
|
||||||
contact_number.text = number.value
|
|
||||||
setupPhoneNumberTypePicker(contact_number_type, number.type)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,17 +172,13 @@ class ViewContactActivity : ContactActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupEmails() {
|
private fun setupEmails() {
|
||||||
|
contact_emails_holder.removeAllViews()
|
||||||
val emails = contact!!.emails
|
val emails = contact!!.emails
|
||||||
emails.forEachIndexed { index, email ->
|
emails.forEach {
|
||||||
var emailHolder = contact_emails_holder.getChildAt(index)
|
layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false).apply {
|
||||||
if (emailHolder == null) {
|
contact_emails_holder.addView(this)
|
||||||
emailHolder = layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false)
|
contact_email.text = it.value
|
||||||
contact_emails_holder.addView(emailHolder)
|
contact_email_type.setText(getEmailTextId(it.type))
|
||||||
}
|
|
||||||
|
|
||||||
emailHolder!!.apply {
|
|
||||||
contact_email.text = email.value
|
|
||||||
setupEmailTypePicker(contact_email_type, email.type)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,23 +186,30 @@ class ViewContactActivity : ContactActivity() {
|
|||||||
contact_emails_holder.beVisibleIf(emails.isNotEmpty())
|
contact_emails_holder.beVisibleIf(emails.isNotEmpty())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupEvents() {
|
private fun setupAddresses() {
|
||||||
val events = contact!!.events
|
contact_addresses_holder.removeAllViews()
|
||||||
events.forEachIndexed { index, event ->
|
val addresses = contact!!.addresses
|
||||||
var eventHolder = contact_events_holder.getChildAt(index)
|
addresses.forEach {
|
||||||
if (eventHolder == null) {
|
layoutInflater.inflate(R.layout.item_view_address, contact_addresses_holder, false).apply {
|
||||||
eventHolder = layoutInflater.inflate(R.layout.item_event, contact_events_holder, false)
|
contact_addresses_holder.addView(this)
|
||||||
contact_events_holder.addView(eventHolder)
|
contact_address.text = it.value
|
||||||
|
contact_address_type.setText(getAddressTextId(it.type))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(eventHolder as ViewGroup).apply {
|
contact_address_image.beVisibleIf(addresses.isNotEmpty())
|
||||||
contact_event.apply {
|
contact_addresses_holder.beVisibleIf(addresses.isNotEmpty())
|
||||||
getDateTime(event.value, this)
|
}
|
||||||
tag = event.value
|
|
||||||
alpha = 1f
|
|
||||||
}
|
|
||||||
|
|
||||||
setupEventTypePicker(this, event.type)
|
private fun setupEvents() {
|
||||||
|
contact_events_holder.removeAllViews()
|
||||||
|
val events = contact!!.events
|
||||||
|
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)
|
||||||
|
contact_event_type.setText(getEventTextId(it.type))
|
||||||
contact_event_remove.beGone()
|
contact_event_remove.beGone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,39 +218,11 @@ class ViewContactActivity : ContactActivity() {
|
|||||||
contact_events_holder.beVisibleIf(events.isNotEmpty())
|
contact_events_holder.beVisibleIf(events.isNotEmpty())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupTypePickers() {
|
private fun setupNotes() {
|
||||||
if (contact!!.phoneNumbers.isEmpty()) {
|
val notes = contact!!.notes
|
||||||
val numberHolder = contact_numbers_holder.getChildAt(0)
|
contact_notes.text = notes
|
||||||
(numberHolder as? ViewGroup)?.contact_number_type?.apply {
|
contact_notes_image.beVisibleIf(notes.isNotEmpty())
|
||||||
setupPhoneNumberTypePicker(this)
|
contact_notes.beVisibleIf(notes.isNotEmpty())
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
private fun getStarDrawable(on: Boolean) = resources.getDrawable(if (on) R.drawable.ic_star_on_big else R.drawable.ic_star_off_big)
|
||||||
|
@ -27,7 +27,7 @@ import com.simplemobiletools.contacts.models.Contact
|
|||||||
import kotlinx.android.synthetic.main.item_contact_with_number.view.*
|
import kotlinx.android.synthetic.main.item_contact_with_number.view.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList<Contact>, private val listener: RefreshContactsListener?,
|
class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Contact>, private val listener: RefreshContactsListener?,
|
||||||
private val isFavoritesFragment: Boolean, recyclerView: MyRecyclerView, fastScroller: FastScroller, itemClick: (Any) -> Unit) :
|
private val isFavoritesFragment: Boolean, recyclerView: MyRecyclerView, fastScroller: FastScroller, itemClick: (Any) -> Unit) :
|
||||||
MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
|
MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
|
||||||
|
|
||||||
@ -66,6 +66,10 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList<Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun actionItemPressed(id: Int) {
|
override fun actionItemPressed(id: Int) {
|
||||||
|
if (selectedPositions.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
when (id) {
|
when (id) {
|
||||||
R.id.cab_edit -> editContact()
|
R.id.cab_edit -> editContact()
|
||||||
R.id.cab_select_all -> selectAll()
|
R.id.cab_select_all -> selectAll()
|
||||||
@ -97,7 +101,7 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList<Co
|
|||||||
contactDrawable = activity.resources.getColoredDrawableWithColor(R.drawable.ic_person, textColor)
|
contactDrawable = activity.resources.getColoredDrawableWithColor(R.drawable.ic_person, textColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateItems(newItems: MutableList<Contact>) {
|
fun updateItems(newItems: ArrayList<Contact>) {
|
||||||
contactItems = newItems
|
contactItems = newItems
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
finishActMode()
|
finishActMode()
|
||||||
@ -135,19 +139,13 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList<Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun removeFavorites() {
|
private fun removeFavorites() {
|
||||||
if (selectedPositions.isEmpty()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val favoritesToRemove = ArrayList<Contact>()
|
val favoritesToRemove = ArrayList<Contact>()
|
||||||
selectedPositions.sortedDescending().forEach {
|
selectedPositions.sortedDescending().forEach {
|
||||||
favoritesToRemove.add(contactItems[it])
|
favoritesToRemove.add(contactItems[it])
|
||||||
}
|
}
|
||||||
contactItems.removeAll(favoritesToRemove)
|
contactItems.removeAll(favoritesToRemove)
|
||||||
|
|
||||||
val favoriteIDsToRemove = ArrayList<String>()
|
ContactsHelper(activity).removeFavorites(favoritesToRemove)
|
||||||
favoritesToRemove.mapTo(favoriteIDsToRemove, { it.contactId.toString() })
|
|
||||||
ContactsHelper(activity).removeFavorites(favoriteIDsToRemove)
|
|
||||||
if (contactItems.isEmpty()) {
|
if (contactItems.isEmpty()) {
|
||||||
listener?.refreshFavorites()
|
listener?.refreshFavorites()
|
||||||
finishActMode()
|
finishActMode()
|
||||||
@ -157,28 +155,23 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList<Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addToFavorites() {
|
private fun addToFavorites() {
|
||||||
if (selectedPositions.isEmpty()) {
|
val newFavorites = ArrayList<Contact>()
|
||||||
return
|
selectedPositions.forEach { newFavorites.add(contactItems[it]) }
|
||||||
}
|
|
||||||
|
|
||||||
val newFavorites = ArrayList<String>()
|
|
||||||
selectedPositions.forEach { newFavorites.add(contactItems[it].contactId.toString()) }
|
|
||||||
ContactsHelper(activity).addFavorites(newFavorites)
|
ContactsHelper(activity).addFavorites(newFavorites)
|
||||||
listener?.refreshFavorites()
|
listener?.refreshFavorites()
|
||||||
finishActMode()
|
finishActMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shareContacts() {
|
private fun shareContacts() {
|
||||||
if (selectedPositions.isEmpty()) {
|
val contactsIDs = ArrayList<Int>()
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val contacts = ArrayList<Contact>()
|
|
||||||
selectedPositions.forEach {
|
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<Contact>
|
||||||
|
activity.shareContacts(filtered)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewRecycled(holder: ViewHolder?) {
|
override fun onViewRecycled(holder: ViewHolder?) {
|
||||||
@ -201,16 +194,26 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList<Co
|
|||||||
contact_tmb.beVisibleIf(showContactThumbnails)
|
contact_tmb.beVisibleIf(showContactThumbnails)
|
||||||
|
|
||||||
if (showContactThumbnails) {
|
if (showContactThumbnails) {
|
||||||
if (contact.photoUri.isNotEmpty()) {
|
when {
|
||||||
val options = RequestOptions()
|
contact.photoUri.isNotEmpty() -> {
|
||||||
.signature(ObjectKey(contact.photoUri))
|
val options = RequestOptions()
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.signature(ObjectKey(contact.photoUri))
|
||||||
.error(contactDrawable)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
.centerCrop()
|
.error(contactDrawable)
|
||||||
|
.centerCrop()
|
||||||
|
|
||||||
Glide.with(activity).load(contact.photoUri).transition(DrawableTransitionOptions.withCrossFade()).apply(options).into(contact_tmb)
|
Glide.with(activity).load(contact.photoUri).transition(DrawableTransitionOptions.withCrossFade()).apply(options).into(contact_tmb)
|
||||||
} else {
|
}
|
||||||
contact_tmb.setImageDrawable(contactDrawable)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import com.simplemobiletools.commons.interfaces.MyAdapterListener
|
|||||||
import com.simplemobiletools.contacts.R
|
import com.simplemobiletools.contacts.R
|
||||||
import com.simplemobiletools.contacts.activities.SimpleActivity
|
import com.simplemobiletools.contacts.activities.SimpleActivity
|
||||||
import com.simplemobiletools.contacts.extensions.config
|
import com.simplemobiletools.contacts.extensions.config
|
||||||
|
import com.simplemobiletools.contacts.helpers.SMT_PRIVATE
|
||||||
import com.simplemobiletools.contacts.models.ContactSource
|
import com.simplemobiletools.contacts.models.ContactSource
|
||||||
import kotlinx.android.synthetic.main.item_filter_contact_source.view.*
|
import kotlinx.android.synthetic.main.item_filter_contact_source.view.*
|
||||||
import java.util.*
|
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) {
|
if (contactSource.name == activity.config.localAccountName && contactSource.type == activity.config.localAccountType) {
|
||||||
contactSource.name = activity.getString(R.string.phone_storage)
|
contactSource.name = activity.getString(R.string.phone_storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contactSource.type == SMT_PRIVATE && displayContactSources.contains(SMT_PRIVATE)) {
|
||||||
|
selectedPositions.add(index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,12 +59,11 @@ class AddFavoritesDialog(val activity: SimpleActivity, private val callback: ()
|
|||||||
val allDisplayedContacts = ArrayList<Contact>()
|
val allDisplayedContacts = ArrayList<Contact>()
|
||||||
allContacts.mapTo(allDisplayedContacts, { it })
|
allContacts.mapTo(allDisplayedContacts, { it })
|
||||||
val selectedContacts = (view?.select_contact_list?.adapter as? SelectContactsAdapter)?.getSelectedItemsSet() ?: LinkedHashSet()
|
val selectedContacts = (view?.select_contact_list?.adapter as? SelectContactsAdapter)?.getSelectedItemsSet() ?: LinkedHashSet()
|
||||||
val contactIDsToAdd = selectedContacts.map { it.contactId.toString() } as ArrayList<String>
|
val contactsToAdd = selectedContacts.map { it } as ArrayList<Contact>
|
||||||
contactsHelper.addFavorites(contactIDsToAdd)
|
contactsHelper.addFavorites(contactsToAdd)
|
||||||
|
|
||||||
allDisplayedContacts.removeAll(selectedContacts)
|
allDisplayedContacts.removeAll(selectedContacts)
|
||||||
val contactIDsToRemove = allDisplayedContacts.map { it.contactId.toString() } as ArrayList<String>
|
contactsHelper.removeFavorites(allDisplayedContacts)
|
||||||
contactsHelper.removeFavorites(contactIDsToRemove)
|
|
||||||
|
|
||||||
callback()
|
callback()
|
||||||
dialog?.dismiss()
|
dialog?.dismiss()
|
||||||
|
@ -8,6 +8,7 @@ import com.simplemobiletools.contacts.activities.SimpleActivity
|
|||||||
import com.simplemobiletools.contacts.adapters.FilterContactSourcesAdapter
|
import com.simplemobiletools.contacts.adapters.FilterContactSourcesAdapter
|
||||||
import com.simplemobiletools.contacts.extensions.config
|
import com.simplemobiletools.contacts.extensions.config
|
||||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||||
|
import com.simplemobiletools.contacts.helpers.SMT_PRIVATE
|
||||||
import com.simplemobiletools.contacts.models.ContactSource
|
import com.simplemobiletools.contacts.models.ContactSource
|
||||||
import kotlinx.android.synthetic.main.dialog_export_contacts.view.*
|
import kotlinx.android.synthetic.main.dialog_export_contacts.view.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -35,6 +36,10 @@ class ExportContactsDialog(val activity: SimpleActivity, val path: String, priva
|
|||||||
.create().apply {
|
.create().apply {
|
||||||
activity.setupDialogStuff(view, this, R.string.export_contacts) {
|
activity.setupDialogStuff(view, this, R.string.export_contacts) {
|
||||||
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||||
|
if (view.export_contacts_list.adapter == null) {
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
|
||||||
val filename = view.export_contacts_filename.value
|
val filename = view.export_contacts_filename.value
|
||||||
when {
|
when {
|
||||||
filename.isEmpty() -> activity.toast(R.string.empty_name)
|
filename.isEmpty() -> activity.toast(R.string.empty_name)
|
||||||
@ -48,7 +53,7 @@ class ExportContactsDialog(val activity: SimpleActivity, val path: String, priva
|
|||||||
val selectedIndexes = (view.export_contacts_list.adapter as FilterContactSourcesAdapter).getSelectedItemsSet()
|
val selectedIndexes = (view.export_contacts_list.adapter as FilterContactSourcesAdapter).getSelectedItemsSet()
|
||||||
val selectedContactSources = HashSet<String>()
|
val selectedContactSources = HashSet<String>()
|
||||||
selectedIndexes.forEach {
|
selectedIndexes.forEach {
|
||||||
selectedContactSources.add(contactSources[it].name)
|
selectedContactSources.add(if (contactSources[it].type == SMT_PRIVATE) SMT_PRIVATE else contactSources[it].name)
|
||||||
}
|
}
|
||||||
callback(file, selectedContactSources)
|
callback(file, selectedContactSources)
|
||||||
dismiss()
|
dismiss()
|
||||||
|
@ -7,6 +7,7 @@ import com.simplemobiletools.contacts.activities.SimpleActivity
|
|||||||
import com.simplemobiletools.contacts.adapters.FilterContactSourcesAdapter
|
import com.simplemobiletools.contacts.adapters.FilterContactSourcesAdapter
|
||||||
import com.simplemobiletools.contacts.extensions.config
|
import com.simplemobiletools.contacts.extensions.config
|
||||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||||
|
import com.simplemobiletools.contacts.helpers.SMT_PRIVATE
|
||||||
import com.simplemobiletools.contacts.models.ContactSource
|
import com.simplemobiletools.contacts.models.ContactSource
|
||||||
import kotlinx.android.synthetic.main.dialog_filter_contact_sources.view.*
|
import kotlinx.android.synthetic.main.dialog_filter_contact_sources.view.*
|
||||||
import java.util.*
|
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 selectedIndexes = (view.filter_contact_sources_list.adapter as FilterContactSourcesAdapter).getSelectedItemsSet()
|
||||||
val selectedContactSources = HashSet<String>()
|
val selectedContactSources = HashSet<String>()
|
||||||
selectedIndexes.forEach {
|
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) {
|
if (activity.config.displayContactSources != selectedContactSources) {
|
||||||
|
@ -9,6 +9,7 @@ import com.simplemobiletools.contacts.activities.SimpleActivity
|
|||||||
import com.simplemobiletools.contacts.extensions.config
|
import com.simplemobiletools.contacts.extensions.config
|
||||||
import com.simplemobiletools.contacts.extensions.getPublicContactSource
|
import com.simplemobiletools.contacts.extensions.getPublicContactSource
|
||||||
import com.simplemobiletools.contacts.extensions.showContactSourcePicker
|
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
|
||||||
import com.simplemobiletools.contacts.helpers.VcfImporter.ImportResult.IMPORT_FAIL
|
import com.simplemobiletools.contacts.helpers.VcfImporter.ImportResult.IMPORT_FAIL
|
||||||
import kotlinx.android.synthetic.main.dialog_import_contacts.view.*
|
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.text = activity.getPublicContactSource(targetContactSource)
|
||||||
import_contacts_title.setOnClickListener {
|
import_contacts_title.setOnClickListener {
|
||||||
activity.showContactSourcePicker(targetContactSource) {
|
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)
|
import_contacts_title.text = activity.getPublicContactSource(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,7 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||||
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||||
import com.simplemobiletools.commons.extensions.getFilePublicUri
|
import com.simplemobiletools.commons.extensions.sharePathIntent
|
||||||
import com.simplemobiletools.commons.extensions.shareUri
|
|
||||||
import com.simplemobiletools.commons.extensions.toast
|
import com.simplemobiletools.commons.extensions.toast
|
||||||
import com.simplemobiletools.commons.helpers.PERMISSION_CALL_PHONE
|
import com.simplemobiletools.commons.helpers.PERMISSION_CALL_PHONE
|
||||||
import com.simplemobiletools.commons.models.RadioItem
|
import com.simplemobiletools.commons.models.RadioItem
|
||||||
@ -13,6 +12,7 @@ import com.simplemobiletools.contacts.BuildConfig
|
|||||||
import com.simplemobiletools.contacts.R
|
import com.simplemobiletools.contacts.R
|
||||||
import com.simplemobiletools.contacts.activities.SimpleActivity
|
import com.simplemobiletools.contacts.activities.SimpleActivity
|
||||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||||
|
import com.simplemobiletools.contacts.helpers.SMT_PRIVATE
|
||||||
import com.simplemobiletools.contacts.helpers.VcfExporter
|
import com.simplemobiletools.contacts.helpers.VcfExporter
|
||||||
import com.simplemobiletools.contacts.models.Contact
|
import com.simplemobiletools.contacts.models.Contact
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -62,6 +62,8 @@ fun SimpleActivity.showContactSourcePicker(currentSource: String, callback: (new
|
|||||||
items.add(RadioItem(index, publicAccount))
|
items.add(RadioItem(index, publicAccount))
|
||||||
if (account == currentSource) {
|
if (account == currentSource) {
|
||||||
currentSourceIndex = index
|
currentSourceIndex = index
|
||||||
|
} else if (currentSource == SMT_PRIVATE && account == getString(R.string.phone_storage_hidden)) {
|
||||||
|
currentSourceIndex = index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +75,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<Contact>) {
|
fun BaseSimpleActivity.shareContacts(contacts: ArrayList<Contact>) {
|
||||||
val file = getTempFile()
|
val file = getTempFile()
|
||||||
@ -84,8 +92,7 @@ fun BaseSimpleActivity.shareContacts(contacts: ArrayList<Contact>) {
|
|||||||
|
|
||||||
VcfExporter().exportContacts(this, file, contacts) {
|
VcfExporter().exportContacts(this, file, contacts) {
|
||||||
if (it == VcfExporter.ExportResult.EXPORT_OK) {
|
if (it == VcfExporter.ExportResult.EXPORT_OK) {
|
||||||
val uri = getFilePublicUri(file, BuildConfig.APPLICATION_ID)
|
sharePathIntent(file.absolutePath, BuildConfig.APPLICATION_ID)
|
||||||
shareUri(uri, BuildConfig.APPLICATION_ID)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
@ -15,16 +15,18 @@ import com.simplemobiletools.contacts.BuildConfig
|
|||||||
import com.simplemobiletools.contacts.R
|
import com.simplemobiletools.contacts.R
|
||||||
import com.simplemobiletools.contacts.activities.EditContactActivity
|
import com.simplemobiletools.contacts.activities.EditContactActivity
|
||||||
import com.simplemobiletools.contacts.activities.ViewContactActivity
|
import com.simplemobiletools.contacts.activities.ViewContactActivity
|
||||||
import com.simplemobiletools.contacts.helpers.CONTACT_ID
|
import com.simplemobiletools.contacts.helpers.*
|
||||||
import com.simplemobiletools.contacts.helpers.Config
|
|
||||||
import com.simplemobiletools.contacts.models.Contact
|
import com.simplemobiletools.contacts.models.Contact
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
val Context.config: Config get() = Config.newInstance(applicationContext)
|
val Context.config: Config get() = Config.newInstance(applicationContext)
|
||||||
|
|
||||||
|
val Context.dbHelper: DBHelper get() = DBHelper.newInstance(applicationContext)
|
||||||
|
|
||||||
fun Context.viewContact(contact: Contact) {
|
fun Context.viewContact(contact: Contact) {
|
||||||
Intent(applicationContext, ViewContactActivity::class.java).apply {
|
Intent(applicationContext, ViewContactActivity::class.java).apply {
|
||||||
putExtra(CONTACT_ID, contact.id)
|
putExtra(CONTACT_ID, contact.id)
|
||||||
|
putExtra(IS_PRIVATE, contact.source == SMT_PRIVATE)
|
||||||
startActivity(this)
|
startActivity(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,6 +34,7 @@ fun Context.viewContact(contact: Contact) {
|
|||||||
fun Context.editContact(contact: Contact) {
|
fun Context.editContact(contact: Contact) {
|
||||||
Intent(applicationContext, EditContactActivity::class.java).apply {
|
Intent(applicationContext, EditContactActivity::class.java).apply {
|
||||||
putExtra(CONTACT_ID, contact.id)
|
putExtra(CONTACT_ID, contact.id)
|
||||||
|
putExtra(IS_PRIVATE, contact.source == SMT_PRIVATE)
|
||||||
startActivity(this)
|
startActivity(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,3 +128,18 @@ fun Context.getCachePhoto(): File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getCachePhotoUri(file: File = getCachePhoto()) = FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.provider", 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
|
||||||
|
}
|
||||||
|
@ -59,7 +59,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun primaryColorChanged(color: Int) {
|
fun primaryColorChanged() {
|
||||||
fragment_fastscroller.updatePrimaryColor()
|
fragment_fastscroller.updatePrimaryColor()
|
||||||
fragment_fastscroller.updateBubblePrimaryColor()
|
fragment_fastscroller.updateBubblePrimaryColor()
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onSearchClosed() {
|
fun onSearchClosed() {
|
||||||
(fragment_list.adapter as ContactsAdapter).updateItems(contactsIgnoringSearch)
|
(fragment_list.adapter as? ContactsAdapter)?.updateItems(contactsIgnoringSearch)
|
||||||
if (this is FavoritesFragment) {
|
if (this is FavoritesFragment) {
|
||||||
fragment_placeholder.text = activity?.getString(R.string.no_favorites)
|
fragment_placeholder.text = activity?.getString(R.string.no_favorites)
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,12 @@ package com.simplemobiletools.contacts.helpers
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.simplemobiletools.commons.helpers.BaseConfig
|
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) {
|
class Config(context: Context) : BaseConfig(context) {
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance(context: Context) = Config(context)
|
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<String>
|
var displayContactSources: Set<String>
|
||||||
get() = prefs.getStringSet(DISPLAY_CONTACT_SOURCES, hashSetOf("-1"))
|
get() = prefs.getStringSet(DISPLAY_CONTACT_SOURCES, hashSetOf("-1"))
|
||||||
set(displayContactSources) = prefs.edit().remove(DISPLAY_CONTACT_SOURCES).putStringSet(DISPLAY_CONTACT_SOURCES, displayContactSources).apply()
|
set(displayContactSources) = prefs.edit().remove(DISPLAY_CONTACT_SOURCES).putStringSet(DISPLAY_CONTACT_SOURCES, displayContactSources).apply()
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package com.simplemobiletools.contacts.helpers
|
package com.simplemobiletools.contacts.helpers
|
||||||
|
|
||||||
import android.provider.ContactsContract.CommonDataKinds
|
|
||||||
|
|
||||||
// shared prefs
|
// shared prefs
|
||||||
const val SHOW_CONTACT_THUMBNAILS = "show_contact_thumbnails"
|
const val SHOW_CONTACT_THUMBNAILS = "show_contact_thumbnails"
|
||||||
const val SHOW_PHONE_NUMBERS = "show_phone_numbers"
|
const val SHOW_PHONE_NUMBERS = "show_phone_numbers"
|
||||||
@ -14,7 +12,8 @@ const val LOCAL_ACCOUNT_TYPE = "local_account_type"
|
|||||||
const val ON_CONTACT_CLICK = "on_contact_click"
|
const val ON_CONTACT_CLICK = "on_contact_click"
|
||||||
|
|
||||||
const val CONTACT_ID = "contact_id"
|
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
|
// contact photo changes
|
||||||
const val PHOTO_ADDED = 1
|
const val PHOTO_ADDED = 1
|
||||||
@ -22,11 +21,6 @@ const val PHOTO_REMOVED = 2
|
|||||||
const val PHOTO_CHANGED = 3
|
const val PHOTO_CHANGED = 3
|
||||||
const val PHOTO_UNCHANGED = 4
|
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
|
// export/import
|
||||||
const val BEGIN_VCARD = "BEGIN:VCARD"
|
const val BEGIN_VCARD = "BEGIN:VCARD"
|
||||||
const val END_VCARD = "END:VCARD"
|
const val END_VCARD = "END:VCARD"
|
||||||
@ -36,6 +30,8 @@ const val BDAY = "BDAY:"
|
|||||||
const val ANNIVERSARY = "ANNIVERSARY:"
|
const val ANNIVERSARY = "ANNIVERSARY:"
|
||||||
const val PHOTO = "PHOTO"
|
const val PHOTO = "PHOTO"
|
||||||
const val EMAIL = "EMAIL"
|
const val EMAIL = "EMAIL"
|
||||||
|
const val ADR = "ADR"
|
||||||
|
const val NOTE = "NOTE:"
|
||||||
const val ENCODING = "ENCODING"
|
const val ENCODING = "ENCODING"
|
||||||
const val BASE64 = "BASE64"
|
const val BASE64 = "BASE64"
|
||||||
const val JPEG = "JPEG"
|
const val JPEG = "JPEG"
|
||||||
|
@ -9,6 +9,7 @@ import android.graphics.Bitmap
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import android.provider.ContactsContract.CommonDataKinds
|
import android.provider.ContactsContract.CommonDataKinds
|
||||||
|
import android.provider.ContactsContract.CommonDataKinds.Note
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||||
@ -22,12 +23,13 @@ import com.simplemobiletools.commons.helpers.SORT_BY_SURNAME
|
|||||||
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
||||||
import com.simplemobiletools.contacts.R
|
import com.simplemobiletools.contacts.R
|
||||||
import com.simplemobiletools.contacts.extensions.config
|
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 com.simplemobiletools.contacts.models.*
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class ContactsHelper(val activity: BaseSimpleActivity) {
|
class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||||
fun getContacts(callback: (ArrayList<Contact>) -> Unit) {
|
fun getContacts(addOptionalFields: Boolean = false, callback: (ArrayList<Contact>) -> Unit) {
|
||||||
val contacts = SparseArray<Contact>()
|
val contacts = SparseArray<Contact>()
|
||||||
Thread {
|
Thread {
|
||||||
val uri = ContactsContract.Data.CONTENT_URI
|
val uri = ContactsContract.Data.CONTENT_URI
|
||||||
@ -48,12 +50,15 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
val photoUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_URI) ?: ""
|
val photoUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_URI) ?: ""
|
||||||
val number = ArrayList<PhoneNumber>() // proper value is obtained below
|
val number = ArrayList<PhoneNumber>() // proper value is obtained below
|
||||||
val emails = ArrayList<Email>()
|
val emails = ArrayList<Email>()
|
||||||
|
val addresses = ArrayList<Address>()
|
||||||
val events = ArrayList<Event>()
|
val events = ArrayList<Event>()
|
||||||
val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: ""
|
val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: ""
|
||||||
val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED)
|
val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED)
|
||||||
val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
|
val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
|
||||||
val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
|
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 notes = ""
|
||||||
|
val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName,
|
||||||
|
starred, contactId, thumbnailUri, null, notes)
|
||||||
contacts.put(id, contact)
|
contacts.put(id, contact)
|
||||||
} while (cursor.moveToNext())
|
} while (cursor.moveToNext())
|
||||||
}
|
}
|
||||||
@ -70,11 +75,38 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
contacts[key]?.phoneNumbers = phoneNumbers.valueAt(i)
|
contacts[key]?.phoneNumbers = phoneNumbers.valueAt(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
val emails = getEmails()
|
if (addOptionalFields) {
|
||||||
size = emails.size()
|
val emails = getEmails()
|
||||||
for (i in 0 until size) {
|
size = emails.size()
|
||||||
val key = emails.keyAt(i)
|
for (i in 0 until size) {
|
||||||
contacts[key]?.emails = emails.valueAt(i)
|
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 events = getEvents()
|
||||||
|
size = events.size()
|
||||||
|
for (i in 0 until size) {
|
||||||
|
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 {
|
||||||
|
contacts.put(it.id, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
val contactsSize = contacts.size()
|
val contactsSize = contacts.size()
|
||||||
@ -160,28 +192,75 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
return emails
|
return emails
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getEvents(contactId: Int): SparseArray<ArrayList<Event>> {
|
private fun getAddresses(contactId: Int? = null): SparseArray<ArrayList<Address>> {
|
||||||
val events = SparseArray<ArrayList<Event>>()
|
val addresses = SparseArray<ArrayList<Address>>()
|
||||||
val uri = ContactsContract.Data.CONTENT_URI
|
val uri = CommonDataKinds.StructuredPostal.CONTENT_URI
|
||||||
val projection = arrayOf(
|
val projection = arrayOf(
|
||||||
CommonDataKinds.Event.START_DATE,
|
ContactsContract.Data.RAW_CONTACT_ID,
|
||||||
CommonDataKinds.Event.TYPE
|
CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS,
|
||||||
|
CommonDataKinds.StructuredPostal.TYPE
|
||||||
)
|
)
|
||||||
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?"
|
|
||||||
val selectionArgs = arrayOf(contactId.toString(), CommonDataKinds.Event.CONTENT_ITEM_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
|
var cursor: Cursor? = null
|
||||||
try {
|
try {
|
||||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||||
if (cursor?.moveToFirst() == true) {
|
if (cursor?.moveToFirst() == true) {
|
||||||
do {
|
do {
|
||||||
val startDate = cursor.getStringValue(CommonDataKinds.Event.START_DATE)
|
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||||
val type = cursor.getIntValue(CommonDataKinds.Event.TYPE)
|
val address = cursor.getStringValue(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS)
|
||||||
|
val type = cursor.getIntValue(CommonDataKinds.StructuredPostal.TYPE)
|
||||||
|
|
||||||
if (events[contactId] == null) {
|
if (addresses[id] == null) {
|
||||||
events.put(contactId, ArrayList())
|
addresses.put(id, ArrayList())
|
||||||
}
|
}
|
||||||
|
|
||||||
events[contactId]!!.add(Event(startDate, type))
|
addresses[id]!!.add(Address(address, type))
|
||||||
|
} while (cursor.moveToNext())
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
activity.showErrorToast(e)
|
||||||
|
} finally {
|
||||||
|
cursor?.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getEvents(contactId: Int? = null): SparseArray<ArrayList<Event>> {
|
||||||
|
val events = SparseArray<ArrayList<Event>>()
|
||||||
|
val uri = ContactsContract.Data.CONTENT_URI
|
||||||
|
val projection = arrayOf(
|
||||||
|
ContactsContract.Data.RAW_CONTACT_ID,
|
||||||
|
CommonDataKinds.Event.START_DATE,
|
||||||
|
CommonDataKinds.Event.TYPE
|
||||||
|
)
|
||||||
|
|
||||||
|
var selection = "${ContactsContract.Data.MIMETYPE} = ?"
|
||||||
|
var selectionArgs = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE)
|
||||||
|
|
||||||
|
if (contactId != null) {
|
||||||
|
selection += " AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
|
||||||
|
selectionArgs = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE, contactId.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
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 startDate = cursor.getStringValue(CommonDataKinds.Event.START_DATE) ?: continue
|
||||||
|
val type = cursor.getIntValue(CommonDataKinds.Event.TYPE)
|
||||||
|
|
||||||
|
if (events[id] == null) {
|
||||||
|
events.put(id, ArrayList())
|
||||||
|
}
|
||||||
|
|
||||||
|
events[id]!!.add(Event(startDate, type))
|
||||||
} while (cursor.moveToNext())
|
} while (cursor.moveToNext())
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@ -193,9 +272,46 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
return events
|
return events
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getContactWithId(id: Int): Contact? {
|
private fun getNotes(contactId: Int? = null): SparseArray<String> {
|
||||||
|
val notes = SparseArray<String>()
|
||||||
|
val uri = ContactsContract.Data.CONTENT_URI
|
||||||
|
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) {
|
||||||
|
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)
|
||||||
|
} finally {
|
||||||
|
cursor?.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return notes
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getContactWithId(id: Int, isLocalPrivate: Boolean): Contact? {
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
return null
|
return null
|
||||||
|
} else if (isLocalPrivate) {
|
||||||
|
return activity.dbHelper.getContactWithId(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
val uri = ContactsContract.Data.CONTENT_URI
|
val uri = ContactsContract.Data.CONTENT_URI
|
||||||
@ -212,12 +328,14 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
val photoUri = cursor.getStringValue(CommonDataKinds.Phone.PHOTO_URI) ?: ""
|
val photoUri = cursor.getStringValue(CommonDataKinds.Phone.PHOTO_URI) ?: ""
|
||||||
val number = getPhoneNumbers(id)[id] ?: ArrayList()
|
val number = getPhoneNumbers(id)[id] ?: ArrayList()
|
||||||
val emails = getEmails(id)[id] ?: ArrayList()
|
val emails = getEmails(id)[id] ?: ArrayList()
|
||||||
|
val addresses = getAddresses(id)[id] ?: ArrayList()
|
||||||
val events = getEvents(id)[id] ?: ArrayList()
|
val events = getEvents(id)[id] ?: ArrayList()
|
||||||
|
val notes = getNotes(id)[id] ?: ""
|
||||||
val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: ""
|
val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: ""
|
||||||
val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED)
|
val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED)
|
||||||
val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
|
val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
|
||||||
val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
|
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, addresses, events, accountName, starred, contactId, thumbnailUri, null, notes)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
cursor?.close()
|
cursor?.close()
|
||||||
@ -321,7 +439,9 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateContact(contact: Contact, photoUpdateStatus: Int): Boolean {
|
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)
|
activity.toast(R.string.updating)
|
||||||
val operations = ArrayList<ContentProviderOperation>()
|
val operations = ArrayList<ContentProviderOperation>()
|
||||||
ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI).apply {
|
ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI).apply {
|
||||||
@ -372,6 +492,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
|
// delete events
|
||||||
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
|
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
|
||||||
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? "
|
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? "
|
||||||
@ -391,6 +530,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
|
// favorite
|
||||||
try {
|
try {
|
||||||
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, contact.contactId.toString())
|
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, contact.contactId.toString())
|
||||||
@ -420,12 +568,12 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
val photoUri = Uri.parse(contact.photoUri)
|
val photoUri = Uri.parse(contact.photoUri)
|
||||||
val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, 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 scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false)
|
||||||
val scaledSizePhotoData = bitmapToByteArray(scaledPhoto)
|
val scaledSizePhotoData = scaledPhoto.getByteArray()
|
||||||
scaledPhoto.recycle()
|
scaledPhoto.recycle()
|
||||||
|
|
||||||
val fullSizePhotoData = bitmapToByteArray(bitmap)
|
val fullSizePhotoData = bitmap.getByteArray()
|
||||||
bitmap.recycle()
|
bitmap.recycle()
|
||||||
|
|
||||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||||
@ -495,6 +643,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
|
// events
|
||||||
contact.events.forEach {
|
contact.events.forEach {
|
||||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||||
@ -506,6 +665,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)
|
// photo (inspired by https://gist.github.com/slightfoot/5985900)
|
||||||
var fullSizePhotoData: ByteArray? = null
|
var fullSizePhotoData: ByteArray? = null
|
||||||
var scaledSizePhotoData: ByteArray?
|
var scaledSizePhotoData: ByteArray?
|
||||||
@ -513,11 +680,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
val photoUri = Uri.parse(contact.photoUri)
|
val photoUri = Uri.parse(contact.photoUri)
|
||||||
val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, 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 scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false)
|
||||||
scaledSizePhotoData = bitmapToByteArray(scaledPhoto)
|
scaledSizePhotoData = scaledPhoto.getByteArray()
|
||||||
|
|
||||||
fullSizePhotoData = bitmapToByteArray(bitmap)
|
fullSizePhotoData = bitmap.getByteArray()
|
||||||
scaledPhoto.recycle()
|
scaledPhoto.recycle()
|
||||||
bitmap.recycle()
|
bitmap.recycle()
|
||||||
|
|
||||||
@ -559,9 +726,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun insertLocalContact(contact: Contact): Boolean {
|
private fun insertLocalContact(contact: Contact) = activity.dbHelper.insert(contact)
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addFullSizePhoto(contactId: Long, fullSizePhotoData: ByteArray) {
|
private fun addFullSizePhoto(contactId: Long, fullSizePhotoData: ByteArray) {
|
||||||
val baseUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, contactId)
|
val baseUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, contactId)
|
||||||
@ -573,17 +738,6 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
fileDescriptor.close()
|
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 {
|
fun getContactLookupKey(contactId: String): String {
|
||||||
val uri = ContactsContract.Data.CONTENT_URI
|
val uri = ContactsContract.Data.CONTENT_URI
|
||||||
val projection = arrayOf(ContactsContract.Data.CONTACT_ID, ContactsContract.Data.LOOKUP_KEY)
|
val projection = arrayOf(ContactsContract.Data.CONTACT_ID, ContactsContract.Data.LOOKUP_KEY)
|
||||||
@ -603,24 +757,45 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addFavorites(ids: ArrayList<String>) {
|
fun getContactDataId(contactId: String): String {
|
||||||
toggleFavorites(ids, true)
|
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 removeFavorites(ids: ArrayList<String>) {
|
fun addFavorites(contacts: ArrayList<Contact>) {
|
||||||
toggleFavorites(ids, false)
|
toggleLocalFavorites(contacts, true)
|
||||||
|
toggleFavorites(contacts, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleFavorites(ids: ArrayList<String>, areFavorites: Boolean) {
|
fun removeFavorites(contacts: ArrayList<Contact>) {
|
||||||
|
toggleLocalFavorites(contacts, false)
|
||||||
|
toggleFavorites(contacts, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleFavorites(contacts: ArrayList<Contact>, addToFavorites: Boolean) {
|
||||||
val applyBatchSize = 100
|
val applyBatchSize = 100
|
||||||
try {
|
try {
|
||||||
val operations = ArrayList<ContentProviderOperation>()
|
val operations = ArrayList<ContentProviderOperation>()
|
||||||
ids.forEach {
|
contacts.filter { it.source != SMT_PRIVATE }.map { it.contactId.toString() }.forEach {
|
||||||
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, it)
|
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, it)
|
||||||
ContentProviderOperation.newUpdate(uri).apply {
|
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())
|
operations.add(build())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operations.size % applyBatchSize == 0) {
|
if (operations.size % applyBatchSize == 0) {
|
||||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||||
operations.clear()
|
operations.clear()
|
||||||
@ -632,14 +807,28 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteContact(contact: Contact) = deleteContacts(arrayListOf(contact))
|
private fun toggleLocalFavorites(contacts: ArrayList<Contact>, 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)
|
||||||
|
} else {
|
||||||
|
deleteContacts(arrayListOf(contact))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun deleteContacts(contacts: ArrayList<Contact>) {
|
fun deleteContacts(contacts: ArrayList<Contact>) {
|
||||||
|
val localContacts = contacts.filter { it.source == SMT_PRIVATE }.map { it.id.toString() }.toTypedArray()
|
||||||
|
activity.dbHelper.deleteContacts(localContacts)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val contactIDs = HashSet<String>()
|
val contactIDs = HashSet<String>()
|
||||||
val operations = ArrayList<ContentProviderOperation>()
|
val operations = ArrayList<ContentProviderOperation>()
|
||||||
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ?"
|
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ?"
|
||||||
contacts.forEach {
|
contacts.filter { it.source != SMT_PRIVATE }.forEach {
|
||||||
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
|
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
|
||||||
val selectionArgs = arrayOf(it.id.toString())
|
val selectionArgs = arrayOf(it.id.toString())
|
||||||
withSelection(selection, selectionArgs)
|
withSelection(selection, selectionArgs)
|
||||||
@ -653,19 +842,4 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
|||||||
activity.showErrorToast(e)
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,179 @@
|
|||||||
|
package com.simplemobiletools.contacts.helpers
|
||||||
|
|
||||||
|
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.*
|
||||||
|
|
||||||
|
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"
|
||||||
|
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 COL_ADDRESSES = "addresses"
|
||||||
|
private val COL_NOTES = "notes"
|
||||||
|
|
||||||
|
private val FIRST_CONTACT_ID = 1000000
|
||||||
|
|
||||||
|
private val mDb = writableDatabase
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val DB_VERSION = 2
|
||||||
|
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 $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_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)")
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ''")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insert(contact: Contact): Boolean {
|
||||||
|
val contactValues = fillContactValues(contact)
|
||||||
|
val id = mDb.insert(CONTACTS_TABLE_NAME, null, contactValues).toInt()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteContact(id: Int) = deleteContacts(arrayOf(id.toString()))
|
||||||
|
|
||||||
|
fun deleteContacts(ids: Array<String>) {
|
||||||
|
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)
|
||||||
|
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_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))
|
||||||
|
} 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 * 2, thumbnailSize * 2, false)
|
||||||
|
val scaledSizePhotoData = scaledPhoto.getByteArray()
|
||||||
|
scaledPhoto.recycle()
|
||||||
|
return scaledSizePhotoData
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleFavorites(ids: Array<String>, 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<String>? = null): ArrayList<Contact> {
|
||||||
|
val contacts = ArrayList<Contact>()
|
||||||
|
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()) {
|
||||||
|
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<List<PhoneNumber>>() {}.type
|
||||||
|
val phoneNumbers = Gson().fromJson<ArrayList<PhoneNumber>>(phoneNumbersJson, phoneNumbersToken) ?: ArrayList(1)
|
||||||
|
|
||||||
|
val emailsJson = cursor.getStringValue(COL_EMAILS)
|
||||||
|
val emailsToken = object : TypeToken<List<Email>>() {}.type
|
||||||
|
val emails = Gson().fromJson<ArrayList<Email>>(emailsJson, emailsToken) ?: ArrayList(1)
|
||||||
|
|
||||||
|
val addressesJson = cursor.getStringValue(COL_ADDRESSES)
|
||||||
|
val addressesToken = object : TypeToken<List<Address>>() {}.type
|
||||||
|
val addresses = Gson().fromJson<ArrayList<Address>>(addressesJson, addressesToken) ?: ArrayList(1)
|
||||||
|
|
||||||
|
val eventsJson = cursor.getStringValue(COL_EVENTS)
|
||||||
|
val eventsToken = object : TypeToken<List<Event>>() {}.type
|
||||||
|
val events = Gson().fromJson<ArrayList<Event>>(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 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return contacts
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getContactWithId(id: Int): Contact? {
|
||||||
|
val selection = "$COL_ID = ?"
|
||||||
|
val selectionArgs = arrayOf(id.toString())
|
||||||
|
return getContacts(selection, selectionArgs).firstOrNull()
|
||||||
|
}
|
||||||
|
}
|
@ -8,9 +8,11 @@ import android.util.Base64
|
|||||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||||
import com.simplemobiletools.commons.extensions.getFileOutputStream
|
import com.simplemobiletools.commons.extensions.getFileOutputStream
|
||||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||||
|
import com.simplemobiletools.commons.extensions.toFileDirItem
|
||||||
import com.simplemobiletools.commons.extensions.writeLn
|
import com.simplemobiletools.commons.extensions.writeLn
|
||||||
import com.simplemobiletools.contacts.helpers.VcfExporter.ExportResult.*
|
import com.simplemobiletools.contacts.helpers.VcfExporter.ExportResult.*
|
||||||
import com.simplemobiletools.contacts.models.Contact
|
import com.simplemobiletools.contacts.models.Contact
|
||||||
|
import java.io.BufferedWriter
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@ -26,7 +28,7 @@ class VcfExporter {
|
|||||||
|
|
||||||
fun exportContacts(activity: BaseSimpleActivity, file: File, contacts: ArrayList<Contact>, callback: (result: ExportResult) -> Unit) {
|
fun exportContacts(activity: BaseSimpleActivity, file: File, contacts: ArrayList<Contact>, callback: (result: ExportResult) -> Unit) {
|
||||||
try {
|
try {
|
||||||
activity.getFileOutputStream(file) {
|
activity.getFileOutputStream(file.toFileDirItem(activity)) {
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
callback(EXPORT_FAIL)
|
callback(EXPORT_FAIL)
|
||||||
return@getFileOutputStream
|
return@getFileOutputStream
|
||||||
@ -48,31 +50,29 @@ class VcfExporter {
|
|||||||
out.writeLn("$EMAIL$delimiterType:${it.value}")
|
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 {
|
contact.events.forEach {
|
||||||
if (it.type == CommonDataKinds.Event.TYPE_BIRTHDAY) {
|
if (it.type == CommonDataKinds.Event.TYPE_BIRTHDAY) {
|
||||||
out.writeLn("$BDAY${it.value}")
|
out.writeLn("$BDAY${it.value}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contact.notes.isNotEmpty()) {
|
||||||
|
out.writeLn("$NOTE${contact.notes.replace("\n", "\\n")}")
|
||||||
|
}
|
||||||
|
|
||||||
if (contact.thumbnailUri.isNotEmpty()) {
|
if (contact.thumbnailUri.isNotEmpty()) {
|
||||||
val firstLine = "$PHOTO;$ENCODING=$BASE64;$JPEG:"
|
|
||||||
val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, Uri.parse(contact.thumbnailUri))
|
val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, Uri.parse(contact.thumbnailUri))
|
||||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
addBitmap(bitmap, out)
|
||||||
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)
|
if (contact.photo != null) {
|
||||||
out.writeLn(firstLine + encodedFirstLineSection)
|
addBitmap(contact.photo!!, out)
|
||||||
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("")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.writeLn(END_VCARD)
|
out.writeLn(END_VCARD)
|
||||||
@ -91,6 +91,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 {
|
private fun getNames(contact: Contact): String {
|
||||||
var result = ""
|
var result = ""
|
||||||
var firstName = contact.firstName
|
var firstName = contact.firstName
|
||||||
@ -126,4 +146,10 @@ class VcfExporter {
|
|||||||
CommonDataKinds.Email.TYPE_MOBILE -> MOBILE
|
CommonDataKinds.Email.TYPE_MOBILE -> MOBILE
|
||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getAddressTypeLabel(type: Int) = when (type) {
|
||||||
|
CommonDataKinds.StructuredPostal.TYPE_HOME -> HOME
|
||||||
|
CommonDataKinds.StructuredPostal.TYPE_WORK -> WORK
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,7 @@ import com.simplemobiletools.contacts.activities.SimpleActivity
|
|||||||
import com.simplemobiletools.contacts.extensions.getCachePhoto
|
import com.simplemobiletools.contacts.extensions.getCachePhoto
|
||||||
import com.simplemobiletools.contacts.extensions.getCachePhotoUri
|
import com.simplemobiletools.contacts.extensions.getCachePhotoUri
|
||||||
import com.simplemobiletools.contacts.helpers.VcfImporter.ImportResult.*
|
import com.simplemobiletools.contacts.helpers.VcfImporter.ImportResult.*
|
||||||
import com.simplemobiletools.contacts.models.Contact
|
import com.simplemobiletools.contacts.models.*
|
||||||
import com.simplemobiletools.contacts.models.Email
|
|
||||||
import com.simplemobiletools.contacts.models.Event
|
|
||||||
import com.simplemobiletools.contacts.models.PhoneNumber
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
|
||||||
@ -26,9 +23,11 @@ class VcfImporter(val activity: SimpleActivity) {
|
|||||||
private var curMiddleName = ""
|
private var curMiddleName = ""
|
||||||
private var curSurname = ""
|
private var curSurname = ""
|
||||||
private var curPhotoUri = ""
|
private var curPhotoUri = ""
|
||||||
|
private var curNotes = ""
|
||||||
private var curPhoneNumbers = ArrayList<PhoneNumber>()
|
private var curPhoneNumbers = ArrayList<PhoneNumber>()
|
||||||
private var curEmails = ArrayList<Email>()
|
private var curEmails = ArrayList<Email>()
|
||||||
private var curEvents = ArrayList<Event>()
|
private var curEvents = ArrayList<Event>()
|
||||||
|
private var curAddresses = ArrayList<Address>()
|
||||||
|
|
||||||
private var isGettingPhoto = false
|
private var isGettingPhoto = false
|
||||||
private var currentPhotoString = StringBuilder()
|
private var currentPhotoString = StringBuilder()
|
||||||
@ -38,6 +37,9 @@ class VcfImporter(val activity: SimpleActivity) {
|
|||||||
private var currentNameIsANSI = false
|
private var currentNameIsANSI = false
|
||||||
private var currentNameString = StringBuilder()
|
private var currentNameString = StringBuilder()
|
||||||
|
|
||||||
|
private var isGettingNotes = false
|
||||||
|
private var currentNotesSB = StringBuilder()
|
||||||
|
|
||||||
private var contactsImported = 0
|
private var contactsImported = 0
|
||||||
private var contactsFailed = 0
|
private var contactsFailed = 0
|
||||||
|
|
||||||
@ -62,13 +64,22 @@ class VcfImporter(val activity: SimpleActivity) {
|
|||||||
currentNameString.append(line.trimStart('\t'))
|
currentNameString.append(line.trimStart('\t'))
|
||||||
isGettingName = false
|
isGettingName = false
|
||||||
parseNames()
|
parseNames()
|
||||||
|
} else if (isGettingNotes) {
|
||||||
|
if (line.startsWith(' ')) {
|
||||||
|
currentNotesSB.append(line.substring(1))
|
||||||
|
} else {
|
||||||
|
curNotes = currentNotesSB.toString().replace("\\n", "\n").replace("\\,", ",")
|
||||||
|
isGettingNotes = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when {
|
when {
|
||||||
line.toUpperCase() == BEGIN_VCARD -> resetValues()
|
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(N) -> addNames(line.substring(N.length))
|
||||||
line.toUpperCase().startsWith(TEL) -> addPhoneNumber(line.substring(TEL.length))
|
line.toUpperCase().startsWith(TEL) -> addPhoneNumber(line.substring(TEL.length))
|
||||||
line.toUpperCase().startsWith(EMAIL) -> addEmail(line.substring(EMAIL.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(BDAY) -> addBirthday(line.substring(BDAY.length))
|
||||||
line.toUpperCase().startsWith(ANNIVERSARY) -> addAnniversary(line.substring(ANNIVERSARY.length))
|
line.toUpperCase().startsWith(ANNIVERSARY) -> addAnniversary(line.substring(ANNIVERSARY.length))
|
||||||
line.toUpperCase().startsWith(PHOTO) -> addPhoto(line.substring(PHOTO.length))
|
line.toUpperCase().startsWith(PHOTO) -> addPhoto(line.substring(PHOTO.length))
|
||||||
@ -156,6 +167,25 @@ class VcfImporter(val activity: SimpleActivity) {
|
|||||||
else -> CommonDataKinds.Email.TYPE_OTHER
|
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) {
|
private fun addBirthday(birthday: String) {
|
||||||
curEvents.add(Event(birthday, CommonDataKinds.Event.TYPE_BIRTHDAY))
|
curEvents.add(Event(birthday, CommonDataKinds.Event.TYPE_BIRTHDAY))
|
||||||
}
|
}
|
||||||
@ -198,8 +228,13 @@ class VcfImporter(val activity: SimpleActivity) {
|
|||||||
curPhotoUri = activity.getCachePhotoUri(file).toString()
|
curPhotoUri = activity.getCachePhotoUri(file).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addNotes(notes: String) {
|
||||||
|
currentNotesSB.append(notes)
|
||||||
|
isGettingNotes = true
|
||||||
|
}
|
||||||
|
|
||||||
private fun saveContact(source: String) {
|
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, curAddresses, curEvents, source, 0, 0, "", null, curNotes)
|
||||||
if (ContactsHelper(activity).insertContact(contact)) {
|
if (ContactsHelper(activity).insertContact(contact)) {
|
||||||
contactsImported++
|
contactsImported++
|
||||||
}
|
}
|
||||||
@ -210,9 +245,11 @@ class VcfImporter(val activity: SimpleActivity) {
|
|||||||
curMiddleName = ""
|
curMiddleName = ""
|
||||||
curSurname = ""
|
curSurname = ""
|
||||||
curPhotoUri = ""
|
curPhotoUri = ""
|
||||||
|
curNotes = ""
|
||||||
curPhoneNumbers = ArrayList()
|
curPhoneNumbers = ArrayList()
|
||||||
curEmails = ArrayList()
|
curEmails = ArrayList()
|
||||||
curEvents = ArrayList()
|
curEvents = ArrayList()
|
||||||
|
curAddresses = ArrayList()
|
||||||
|
|
||||||
isGettingPhoto = false
|
isGettingPhoto = false
|
||||||
currentPhotoString = StringBuilder()
|
currentPhotoString = StringBuilder()
|
||||||
@ -221,5 +258,8 @@ class VcfImporter(val activity: SimpleActivity) {
|
|||||||
isGettingName = false
|
isGettingName = false
|
||||||
currentNameIsANSI = false
|
currentNameIsANSI = false
|
||||||
currentNameString = StringBuilder()
|
currentNameString = StringBuilder()
|
||||||
|
|
||||||
|
isGettingNotes = false
|
||||||
|
currentNotesSB = StringBuilder()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
package com.simplemobiletools.contacts.models
|
||||||
|
|
||||||
|
data class Address(var value: String, var type: Int)
|
@ -1,12 +1,13 @@
|
|||||||
package com.simplemobiletools.contacts.models
|
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_FIRST_NAME
|
||||||
import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME
|
import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME
|
||||||
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
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,
|
data class Contact(val id: Int, var firstName: String, var middleName: String, var surname: String, var photoUri: String,
|
||||||
var phoneNumbers: ArrayList<PhoneNumber>, var emails: ArrayList<Email>, var events: ArrayList<Event>, var source: String,
|
var phoneNumbers: ArrayList<PhoneNumber>, var emails: ArrayList<Email>, var addresses: ArrayList<Address>, var events: ArrayList<Event>,
|
||||||
var starred: Int, val contactId: Int, val thumbnailUri: String) : Comparable<Contact> {
|
var source: String, var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?, var notes: String) : Comparable<Contact> {
|
||||||
companion object {
|
companion object {
|
||||||
var sorting = 0
|
var sorting = 0
|
||||||
}
|
}
|
||||||
|
@ -213,6 +213,44 @@
|
|||||||
android:paddingTop="@dimen/medium_margin"
|
android:paddingTop="@dimen/medium_margin"
|
||||||
android:src="@drawable/ic_plus"/>
|
android:src="@drawable/ic_plus"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/contact_address_image"
|
||||||
|
android:layout_width="@dimen/contact_icons_size"
|
||||||
|
android:layout_height="@dimen/contact_icons_size"
|
||||||
|
android:layout_alignTop="@+id/contact_addresses_holder"
|
||||||
|
android:paddingBottom="@dimen/small_margin"
|
||||||
|
android:paddingEnd="@dimen/small_margin"
|
||||||
|
android:paddingRight="@dimen/small_margin"
|
||||||
|
android:paddingTop="@dimen/medium_margin"
|
||||||
|
android:src="@drawable/ic_place"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/contact_addresses_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/contact_email_add_new"
|
||||||
|
android:layout_marginTop="@dimen/medium_margin"
|
||||||
|
android:layout_toRightOf="@+id/contact_name_image"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/item_edit_address"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/contact_address_add_new"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/contact_addresses_holder"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="@dimen/small_margin"
|
||||||
|
android:background="@drawable/button_background"
|
||||||
|
android:paddingBottom="@dimen/medium_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_margin"
|
||||||
|
android:paddingRight="@dimen/activity_margin"
|
||||||
|
android:paddingTop="@dimen/medium_margin"
|
||||||
|
android:src="@drawable/ic_plus"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/contact_event_image"
|
android:id="@+id/contact_event_image"
|
||||||
android:layout_width="@dimen/contact_icons_size"
|
android:layout_width="@dimen/contact_icons_size"
|
||||||
@ -228,7 +266,7 @@
|
|||||||
android:id="@+id/contact_events_holder"
|
android:id="@+id/contact_events_holder"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/contact_email_add_new"
|
android:layout_below="@+id/contact_address_add_new"
|
||||||
android:layout_marginTop="@dimen/medium_margin"
|
android:layout_marginTop="@dimen/medium_margin"
|
||||||
android:layout_toRightOf="@+id/contact_name_image"
|
android:layout_toRightOf="@+id/contact_name_image"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
@ -251,6 +289,30 @@
|
|||||||
android:paddingTop="@dimen/medium_margin"
|
android:paddingTop="@dimen/medium_margin"
|
||||||
android:src="@drawable/ic_plus"/>
|
android:src="@drawable/ic_plus"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/contact_notes_image"
|
||||||
|
android:layout_width="@dimen/contact_icons_size"
|
||||||
|
android:layout_height="@dimen/contact_icons_size"
|
||||||
|
android:layout_alignTop="@+id/contact_notes"
|
||||||
|
android:paddingBottom="@dimen/small_margin"
|
||||||
|
android:paddingEnd="@dimen/small_margin"
|
||||||
|
android:paddingRight="@dimen/small_margin"
|
||||||
|
android:paddingTop="@dimen/medium_margin"
|
||||||
|
android:src="@drawable/ic_label"/>
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyEditText
|
||||||
|
android:id="@+id/contact_notes"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/contact_event_add_new"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginTop="@dimen/normal_margin"
|
||||||
|
android:layout_toRightOf="@+id/contact_notes_image"
|
||||||
|
android:hint="@string/notes"
|
||||||
|
android:inputType="textCapWords|textMultiLine"
|
||||||
|
android:textCursorDrawable="@null"
|
||||||
|
android:textSize="@dimen/bigger_text_size"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/contact_source_image"
|
android:id="@+id/contact_source_image"
|
||||||
android:layout_width="@dimen/contact_icons_size"
|
android:layout_width="@dimen/contact_icons_size"
|
||||||
@ -266,7 +328,7 @@
|
|||||||
android:id="@+id/contact_source"
|
android:id="@+id/contact_source"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/contact_event_add_new"
|
android:layout_below="@+id/contact_notes"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_marginTop="@dimen/medium_margin"
|
android:layout_marginTop="@dimen/medium_margin"
|
||||||
android:layout_toRightOf="@+id/contact_name_image"
|
android:layout_toRightOf="@+id/contact_name_image"
|
||||||
|
@ -154,11 +154,7 @@
|
|||||||
android:layout_below="@+id/contact_surname"
|
android:layout_below="@+id/contact_surname"
|
||||||
android:layout_toRightOf="@+id/contact_number_image"
|
android:layout_toRightOf="@+id/contact_number_image"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingLeft="@dimen/small_margin">
|
android:paddingLeft="@dimen/small_margin"/>
|
||||||
|
|
||||||
<include layout="@layout/item_view_phone_number"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/contact_email_image"
|
android:id="@+id/contact_email_image"
|
||||||
@ -178,11 +174,27 @@
|
|||||||
android:layout_below="@+id/contact_numbers_holder"
|
android:layout_below="@+id/contact_numbers_holder"
|
||||||
android:layout_toRightOf="@+id/contact_name_image"
|
android:layout_toRightOf="@+id/contact_name_image"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingLeft="@dimen/small_margin">
|
android:paddingLeft="@dimen/small_margin"/>
|
||||||
|
|
||||||
<include layout="@layout/item_view_email"/>
|
<ImageView
|
||||||
|
android:id="@+id/contact_address_image"
|
||||||
|
android:layout_width="@dimen/contact_icons_size"
|
||||||
|
android:layout_height="@dimen/contact_icons_size"
|
||||||
|
android:layout_alignTop="@+id/contact_addresses_holder"
|
||||||
|
android:paddingBottom="@dimen/small_margin"
|
||||||
|
android:paddingEnd="@dimen/small_margin"
|
||||||
|
android:paddingRight="@dimen/small_margin"
|
||||||
|
android:paddingTop="@dimen/medium_margin"
|
||||||
|
android:src="@drawable/ic_place"/>
|
||||||
|
|
||||||
</LinearLayout>
|
<LinearLayout
|
||||||
|
android:id="@+id/contact_addresses_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/contact_emails_holder"
|
||||||
|
android:layout_toRightOf="@+id/contact_name_image"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="@dimen/small_margin"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/contact_event_image"
|
android:id="@+id/contact_event_image"
|
||||||
@ -199,13 +211,33 @@
|
|||||||
android:id="@+id/contact_events_holder"
|
android:id="@+id/contact_events_holder"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/contact_emails_holder"
|
android:layout_below="@+id/contact_addresses_holder"
|
||||||
android:layout_toRightOf="@+id/contact_name_image"
|
android:layout_toRightOf="@+id/contact_name_image"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"/>
|
||||||
|
|
||||||
<include layout="@layout/item_event"/>
|
<ImageView
|
||||||
|
android:id="@+id/contact_notes_image"
|
||||||
|
android:layout_width="@dimen/contact_icons_size"
|
||||||
|
android:layout_height="@dimen/contact_icons_size"
|
||||||
|
android:layout_alignTop="@+id/contact_notes"
|
||||||
|
android:paddingBottom="@dimen/small_margin"
|
||||||
|
android:paddingEnd="@dimen/small_margin"
|
||||||
|
android:paddingRight="@dimen/small_margin"
|
||||||
|
android:paddingTop="@dimen/medium_margin"
|
||||||
|
android:src="@drawable/ic_label"/>
|
||||||
|
|
||||||
</LinearLayout>
|
<com.simplemobiletools.commons.views.MyTextView
|
||||||
|
android:id="@+id/contact_notes"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/contact_events_holder"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toRightOf="@+id/contact_notes_image"
|
||||||
|
android:lineSpacingExtra="@dimen/medium_margin"
|
||||||
|
android:paddingBottom="@dimen/normal_margin"
|
||||||
|
android:paddingLeft="@dimen/small_margin"
|
||||||
|
android:paddingTop="@dimen/normal_margin"
|
||||||
|
android:textSize="@dimen/bigger_text_size"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/contact_source_image"
|
android:id="@+id/contact_source_image"
|
||||||
@ -222,10 +254,9 @@
|
|||||||
android:id="@+id/contact_source"
|
android:id="@+id/contact_source"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/contact_events_holder"
|
android:layout_below="@+id/contact_notes"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_toRightOf="@+id/contact_name_image"
|
android:layout_toRightOf="@+id/contact_name_image"
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:paddingBottom="@dimen/normal_margin"
|
android:paddingBottom="@dimen/normal_margin"
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:overScrollMode="never"
|
android:overScrollMode="never"
|
||||||
android:paddingTop="@dimen/medium_margin"
|
android:paddingTop="@dimen/medium_margin"
|
||||||
app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>
|
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -8,4 +8,4 @@
|
|||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:overScrollMode="never"
|
android:overScrollMode="never"
|
||||||
android:paddingTop="@dimen/medium_margin"
|
android:paddingTop="@dimen/medium_margin"
|
||||||
app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>
|
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/>
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>
|
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/>
|
||||||
|
|
||||||
<com.simplemobiletools.commons.views.FastScroller
|
<com.simplemobiletools.commons.views.FastScroller
|
||||||
android:id="@+id/fragment_fastscroller"
|
android:id="@+id/fragment_fastscroller"
|
||||||
|
39
app/src/main/res/layout/item_edit_address.xml
Normal file
39
app/src/main/res/layout/item_edit_address.xml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/contact_address_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyEditText
|
||||||
|
android:id="@+id/contact_address"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toLeftOf="@+id/contact_address_type"
|
||||||
|
android:layout_toStartOf="@+id/contact_address_type"
|
||||||
|
android:hint="@string/address"
|
||||||
|
android:inputType="textCapWords"
|
||||||
|
android:lines="1"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textCursorDrawable="@null"
|
||||||
|
android:textSize="@dimen/bigger_text_size"/>
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyTextView
|
||||||
|
android:id="@+id/contact_address_type"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignBottom="@+id/contact_address"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignTop="@+id/contact_address"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingLeft="@dimen/medium_margin"
|
||||||
|
android:paddingRight="@dimen/medium_margin"
|
||||||
|
android:text="@string/address"
|
||||||
|
android:textSize="@dimen/bigger_text_size"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
37
app/src/main/res/layout/item_view_address.xml
Normal file
37
app/src/main/res/layout/item_view_address.xml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/contact_address_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="@dimen/normal_margin"
|
||||||
|
android:paddingTop="@dimen/normal_margin">
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyTextView
|
||||||
|
android:id="@+id/contact_address"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toLeftOf="@+id/contact_address_type"
|
||||||
|
android:layout_toStartOf="@+id/contact_address_type"
|
||||||
|
android:lines="1"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textSize="@dimen/bigger_text_size"/>
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyTextView
|
||||||
|
android:id="@+id/contact_address_type"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignBottom="@+id/contact_address"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignTop="@+id/contact_address"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingLeft="@dimen/medium_margin"
|
||||||
|
android:paddingRight="@dimen/medium_margin"
|
||||||
|
android:text="@string/home"
|
||||||
|
android:textSize="@dimen/bigger_text_size"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -28,7 +28,6 @@
|
|||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_alignTop="@+id/contact_email"
|
android:layout_alignTop="@+id/contact_email"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingLeft="@dimen/medium_margin"
|
android:paddingLeft="@dimen/medium_margin"
|
||||||
android:paddingRight="@dimen/medium_margin"
|
android:paddingRight="@dimen/medium_margin"
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_alignTop="@+id/contact_number"
|
android:layout_alignTop="@+id/contact_number"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingLeft="@dimen/medium_margin"
|
android:paddingLeft="@dimen/medium_margin"
|
||||||
android:paddingRight="@dimen/medium_margin"
|
android:paddingRight="@dimen/medium_margin"
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>
|
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/>
|
||||||
|
|
||||||
<com.simplemobiletools.commons.views.FastScroller
|
<com.simplemobiletools.commons.views.FastScroller
|
||||||
android:id="@+id/select_contact_fastscroller"
|
android:id="@+id/select_contact_fastscroller"
|
||||||
|
14
app/src/main/res/menu/menu_select_activity.xml
Normal file
14
app/src/main/res/menu/menu_select_activity.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/sort"
|
||||||
|
android:icon="@drawable/ic_sort"
|
||||||
|
android:title="@string/sort_by"
|
||||||
|
app:showAsAction="ifRoom"/>
|
||||||
|
<item
|
||||||
|
android:id="@+id/filter"
|
||||||
|
android:icon="@drawable/ic_filter"
|
||||||
|
android:title="@string/filter"
|
||||||
|
app:showAsAction="ifRoom"/>
|
||||||
|
</menu>
|
@ -4,8 +4,8 @@
|
|||||||
<string name="address">Adress</string>
|
<string name="address">Adress</string>
|
||||||
<string name="inserting">Lägger till…</string>
|
<string name="inserting">Lägger till…</string>
|
||||||
<string name="updating">Uppdaterar…</string>
|
<string name="updating">Uppdaterar…</string>
|
||||||
<string name="phone_storage">Phone storage</string>
|
<string name="phone_storage">Telefonens lagringsutrymme</string>
|
||||||
<string name="phone_storage_hidden">Phone storage (not visible by other apps)</string>
|
<string name="phone_storage_hidden">Telefonens lagringsutrymme (inte synligt för andra appar)</string>
|
||||||
|
|
||||||
<string name="new_contact">Ny kontakt</string>
|
<string name="new_contact">Ny kontakt</string>
|
||||||
<string name="edit_contact">Redigera kontakt</string>
|
<string name="edit_contact">Redigera kontakt</string>
|
||||||
@ -23,10 +23,10 @@
|
|||||||
<!-- Settings -->
|
<!-- Settings -->
|
||||||
<string name="start_name_with_surname">Visa efternamn först</string>
|
<string name="start_name_with_surname">Visa efternamn först</string>
|
||||||
<string name="show_phone_numbers">Visa telefonnummer i huvudvyn</string>
|
<string name="show_phone_numbers">Visa telefonnummer i huvudvyn</string>
|
||||||
<string name="show_contact_thumbnails">Show contact thumbnails</string>
|
<string name="show_contact_thumbnails">Visa kontaktminiatyrer</string>
|
||||||
<string name="on_contact_click">On contact click</string>
|
<string name="on_contact_click">Vid kontakttryckning</string>
|
||||||
<string name="call_contact">Call contact</string>
|
<string name="call_contact">Ring kontakt</string>
|
||||||
<string name="view_contact">View contact details</string>
|
<string name="view_contact">Visa kontaktuppgifter</string>
|
||||||
|
|
||||||
<!-- Emails -->
|
<!-- Emails -->
|
||||||
<string name="email">E-post</string>
|
<string name="email">E-post</string>
|
||||||
|
8
app/src/main/res/values/donottranslate.xml
Normal file
8
app/src/main/res/values/donottranslate.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Release notes -->
|
||||||
|
<string name="release_11">Added Address and Notes fields</string>
|
||||||
|
<string name="release_10">Allow storing contacts in a local database, hidden from other apps</string>
|
||||||
|
|
||||||
|
</resources>
|
3
app/src/main/res/values/integers.xml
Normal file
3
app/src/main/res/values/integers.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<integer name="default_sorting">128</integer>
|
||||||
|
</resources>
|
Reference in New Issue
Block a user