diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ContactActivity.kt index 4e8b5fd00..958a3ae6d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ContactActivity.kt @@ -30,6 +30,7 @@ import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.contacts.pro.R import com.simplemobiletools.contacts.pro.extensions.shareContacts import com.simplemobiletools.commons.models.contacts.Contact +import com.simplemobiletools.commons.models.contacts.ContactRelation abstract class ContactActivity : SimpleActivity() { protected val PICK_RINGTONE_INTENT_ID = 1500 @@ -212,6 +213,80 @@ abstract class ContactActivity : SimpleActivity() { else -> R.string.other } + fun getRelationTypeText(type: Int, label: String): String { + return if (type == BaseTypes.TYPE_CUSTOM) { + label + } else { + getString( + when (type) { + // Relation.TYPE_CUSTOM -> R.string.custom + Relation.TYPE_ASSISTANT -> R.string.relation_assistant + Relation.TYPE_BROTHER -> R.string.relation_brother + Relation.TYPE_CHILD -> R.string.relation_child + Relation.TYPE_DOMESTIC_PARTNER -> R.string.relation_domestic_partner + Relation.TYPE_FATHER -> R.string.relation_father + Relation.TYPE_FRIEND -> R.string.relation_friend + Relation.TYPE_MANAGER -> R.string.relation_manager + Relation.TYPE_MOTHER -> R.string.relation_mother + Relation.TYPE_PARENT -> R.string.relation_parent + Relation.TYPE_PARTNER -> R.string.relation_partner + Relation.TYPE_REFERRED_BY -> R.string.relation_referred_by + Relation.TYPE_RELATIVE -> R.string.relation_relative + Relation.TYPE_SISTER -> R.string.relation_sister + Relation.TYPE_SPOUSE -> R.string.relation_spouse + + // Relation types defined in vCard 4.0 + ContactRelation.TYPE_CONTACT -> R.string.relation_contact + ContactRelation.TYPE_ACQUAINTANCE -> R.string.relation_acquaintance + // ContactRelation.TYPE_FRIEND -> R.string.relation_friend + ContactRelation.TYPE_MET -> R.string.relation_met + ContactRelation.TYPE_CO_WORKER -> R.string.relation_co_worker + ContactRelation.TYPE_COLLEAGUE -> R.string.relation_colleague + ContactRelation.TYPE_CO_RESIDENT -> R.string.relation_co_resident + ContactRelation.TYPE_NEIGHBOR -> R.string.relation_neighbor + // ContactRelation.TYPE_CHILD -> R.string.relation_child + // ContactRelation.TYPE_PARENT -> R.string.relation_parent + ContactRelation.TYPE_SIBLING -> R.string.relation_sibling + // ContactRelation.TYPE_SPOUSE -> R.string.relation_spouse + ContactRelation.TYPE_KIN -> R.string.relation_kin + ContactRelation.TYPE_MUSE -> R.string.relation_muse + ContactRelation.TYPE_CRUSH -> R.string.relation_crush + ContactRelation.TYPE_DATE -> R.string.relation_date + ContactRelation.TYPE_SWEETHEART -> R.string.relation_sweetheart + ContactRelation.TYPE_ME -> R.string.relation_me + ContactRelation.TYPE_AGENT -> R.string.relation_agent + ContactRelation.TYPE_EMERGENCY -> R.string.relation_emergency + + ContactRelation.TYPE_SUPERIOR -> R.string.relation_superior + ContactRelation.TYPE_SUBORDINATE -> R.string.relation_subordinate + ContactRelation.TYPE_HUSBAND -> R.string.relation_husband + ContactRelation.TYPE_WIFE -> R.string.relation_wife + ContactRelation.TYPE_SON -> R.string.relation_son + ContactRelation.TYPE_DAUGHTER -> R.string.relation_daughter + ContactRelation.TYPE_GRANDPARENT -> R.string.relation_grandparent + ContactRelation.TYPE_GRANDFATHER -> R.string.relation_grandfather + ContactRelation.TYPE_GRANDMOTHER -> R.string.relation_grandmother + ContactRelation.TYPE_GRANDCHILD -> R.string.relation_grandchild + ContactRelation.TYPE_GRANDSON -> R.string.relation_grandson + ContactRelation.TYPE_GRANDDAUGHTER -> R.string.relation_granddaughter + ContactRelation.TYPE_UNCLE -> R.string.relation_uncle + ContactRelation.TYPE_AUNT -> R.string.relation_aunt + ContactRelation.TYPE_NEPHEW -> R.string.relation_nephew + ContactRelation.TYPE_NIECE -> R.string.relation_niece + ContactRelation.TYPE_FATHER_IN_LAW -> R.string.relation_father_in_law + ContactRelation.TYPE_MOTHER_IN_LAW -> R.string.relation_mother_in_law + ContactRelation.TYPE_SON_IN_LAW -> R.string.relation_son_in_law + ContactRelation.TYPE_DAUGHTER_IN_LAW -> R.string.relation_daughter_in_law + ContactRelation.TYPE_BROTHER_IN_LAW -> R.string.relation_brother_in_law + ContactRelation.TYPE_SISTER_IN_LAW -> R.string.relation_sister_in_law + + else -> R.string.other + } + ) + } + } + + private fun getBigLetterPlaceholder(name: String): Bitmap { val letter = name.getNameLetter() val height = resources.getDimension(R.dimen.top_contact_image_height).toInt() diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt index 10c475fdf..52f295057 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt @@ -46,6 +46,7 @@ import kotlinx.android.synthetic.main.item_edit_email.view.* import kotlinx.android.synthetic.main.item_edit_group.view.* import kotlinx.android.synthetic.main.item_edit_im.view.* import kotlinx.android.synthetic.main.item_edit_phone_number.view.* +import kotlinx.android.synthetic.main.item_edit_relation.view.* import kotlinx.android.synthetic.main.item_edit_website.view.* import kotlinx.android.synthetic.main.item_event.view.* @@ -211,23 +212,29 @@ class EditContactActivity : ContactActivity() { val textColor = getProperTextColor() arrayOf( - contact_name_image, contact_numbers_image, contact_emails_image, contact_addresses_image, contact_ims_image, contact_events_image, - contact_notes_image, contact_ringtone_image, contact_organization_image, contact_websites_image, contact_groups_image, contact_source_image + contact_name_image, contact_numbers_image, contact_emails_image, + contact_addresses_image, contact_ims_image, contact_events_image, + contact_notes_image, contact_ringtone_image, contact_organization_image, + contact_websites_image, contact_relations_image, contact_groups_image, + contact_source_image ).forEach { it.applyColorFilter(textColor) } val properPrimaryColor = getProperPrimaryColor() arrayOf( - contact_numbers_add_new, contact_emails_add_new, contact_addresses_add_new, contact_ims_add_new, contact_events_add_new, - contact_websites_add_new, contact_groups_add_new + contact_numbers_add_new, contact_emails_add_new, contact_addresses_add_new, + contact_ims_add_new, contact_events_add_new, contact_websites_add_new, + contact_relations_add_new,contact_groups_add_new ).forEach { it.applyColorFilter(properPrimaryColor) } arrayOf( - contact_numbers_add_new.background, contact_emails_add_new.background, contact_addresses_add_new.background, contact_ims_add_new.background, - contact_events_add_new.background, contact_websites_add_new.background, contact_groups_add_new.background + contact_numbers_add_new.background, contact_emails_add_new.background, + contact_addresses_add_new.background, contact_ims_add_new.background, + contact_events_add_new.background, contact_websites_add_new.background, + contact_relations_add_new.background, contact_groups_add_new.background ).forEach { it.applyColorFilter(textColor) } @@ -241,6 +248,7 @@ class EditContactActivity : ContactActivity() { contact_ims_add_new.setOnClickListener { addNewIMField() } contact_events_add_new.setOnClickListener { addNewEventField() } contact_websites_add_new.setOnClickListener { addNewWebsiteField() } + contact_relations_add_new.setOnClickListener { addNewRelationsField() } contact_groups_add_new.setOnClickListener { showSelectGroupsDialog() } contact_source.setOnClickListener { showSelectContactSourceDialog() } @@ -428,6 +436,11 @@ class EditContactActivity : ContactActivity() { contact_websites_holder.beVisibleIf(areWebsitesVisible) contact_websites_add_new.beVisibleIf(areWebsitesVisible) + val areRelationsVisible = ((showFields and SHOW_RELATIONS_FIELD) != 0) + contact_relations_image.beVisibleIf(areRelationsVisible) + contact_relations_holder.beVisibleIf(areRelationsVisible) + contact_relations_add_new.beVisibleIf(areRelationsVisible) + val areGroupsVisible = showFields and SHOW_GROUPS_FIELD != 0 contact_groups_image.beVisibleIf(areGroupsVisible) contact_groups_holder.beVisibleIf(areGroupsVisible) @@ -452,6 +465,7 @@ class EditContactActivity : ContactActivity() { setupNotes() setupOrganization() setupWebsites() + setupRelations() setupEvents() setupGroups() setupContactSource() @@ -640,6 +654,21 @@ class EditContactActivity : ContactActivity() { } } + private fun setupRelations() { + contact!!.relations.forEachIndexed { index, relation -> + var relationsHolder = contact_relations_holder.getChildAt(index) + if (relationsHolder == null) { + relationsHolder = layoutInflater.inflate(R.layout.item_edit_relation, contact_relations_holder, false) + contact_relations_holder.addView(relationsHolder) + } + + relationsHolder!!.apply { + contact_relation.setText(relation.name) + setupRelationTypePicker(contact_relation_type, relation.type, relation.label) + } + } + } + private fun setupEvents() { contact!!.events.forEachIndexed { index, event -> var eventHolder = contact_events_holder.getChildAt(index) @@ -782,6 +811,13 @@ class EditContactActivity : ContactActivity() { } } + if (contact!!.relations.isEmpty()) { + val relationHolder = contact_relations_holder.getChildAt(0) + (relationHolder as? ViewGroup)?.contact_relation_type?.apply { + setupRelationTypePicker(this, DEFAULT_RELATION_TYPE, "") + } + } + if (contact!!.groups.isEmpty()) { val groupsHolder = contact_groups_holder.getChildAt(0) (groupsHolder as? ViewGroup)?.contact_group?.apply { @@ -854,6 +890,15 @@ class EditContactActivity : ContactActivity() { } } + private fun setupRelationTypePicker(relationTypeField: TextView, type: Int, label: String) { + relationTypeField.apply { + text = getRelationTypeText(type, label) + setOnClickListener { + showRelationTypePicker(it as TextView) + } + } + } + private fun setupGroupsPicker(groupTitleField: TextView, group: Group? = null) { groupTitleField.apply { text = group?.title ?: getString(R.string.no_groups) @@ -982,6 +1027,80 @@ class EditContactActivity : ContactActivity() { } } + private fun showRelationTypePicker(relationTypeField: TextView) { + val items = arrayListOf( + RadioItem(CommonDataKinds.Relation.TYPE_CUSTOM, getString(R.string.custom)), + + RadioItem(Relation.TYPE_FRIEND, getString(R.string.relation_friend)), // 6 + + RadioItem(Relation.TYPE_SPOUSE, getString(R.string.relation_spouse)), // 14 + RadioItem(ContactRelation.TYPE_HUSBAND, getString(R.string.relation_husband)), // 103 + RadioItem(ContactRelation.TYPE_WIFE, getString(R.string.relation_wife)), // 104 + RadioItem(Relation.TYPE_DOMESTIC_PARTNER, getString(R.string.relation_domestic_partner)), // 4 + RadioItem(Relation.TYPE_PARTNER, getString(R.string.relation_partner)), // 10 + RadioItem(ContactRelation.TYPE_CO_RESIDENT, getString(R.string.relation_co_resident)), // 56 + RadioItem(ContactRelation.TYPE_NEIGHBOR, getString(R.string.relation_neighbor)), // 57 + RadioItem(Relation.TYPE_PARENT, getString(R.string.relation_parent)), // 9 + RadioItem(Relation.TYPE_FATHER, getString(R.string.relation_father)), // 5 + RadioItem(Relation.TYPE_MOTHER, getString(R.string.relation_mother)), // 8 + RadioItem(Relation.TYPE_CHILD, getString(R.string.relation_child)), // 3 + RadioItem(ContactRelation.TYPE_SON, getString(R.string.relation_son)), // 105 + RadioItem(ContactRelation.TYPE_DAUGHTER, getString(R.string.relation_daughter)), // 106 + RadioItem(ContactRelation.TYPE_SIBLING, getString(R.string.relation_sibling)), // 58 + RadioItem(Relation.TYPE_BROTHER, getString(R.string.relation_brother)), // 2 + RadioItem(Relation.TYPE_SISTER, getString(R.string.relation_sister)), // 13 + RadioItem(ContactRelation.TYPE_GRANDPARENT, getString(R.string.relation_grandparent)), // 107 + RadioItem(ContactRelation.TYPE_GRANDFATHER, getString(R.string.relation_grandfather)), // 108 + RadioItem(ContactRelation.TYPE_GRANDMOTHER, getString(R.string.relation_grandmother)), // 109 + RadioItem(ContactRelation.TYPE_GRANDCHILD, getString(R.string.relation_grandchild)), // 110 + RadioItem(ContactRelation.TYPE_GRANDSON, getString(R.string.relation_grandson)), // 111 + RadioItem(ContactRelation.TYPE_GRANDDAUGHTER, getString(R.string.relation_granddaughter)), // 112 + RadioItem(ContactRelation.TYPE_UNCLE, getString(R.string.relation_uncle)), // 113 + RadioItem(ContactRelation.TYPE_AUNT, getString(R.string.relation_aunt)), // 114 + RadioItem(ContactRelation.TYPE_NEPHEW, getString(R.string.relation_nephew)), // 115 + RadioItem(ContactRelation.TYPE_NIECE, getString(R.string.relation_niece)), // 116 + RadioItem(ContactRelation.TYPE_FATHER_IN_LAW, getString(R.string.relation_father_in_law)), // 117 + RadioItem(ContactRelation.TYPE_MOTHER_IN_LAW, getString(R.string.relation_mother_in_law)), // 118 + RadioItem(ContactRelation.TYPE_SON_IN_LAW, getString(R.string.relation_son_in_law)), // 119 + RadioItem(ContactRelation.TYPE_DAUGHTER_IN_LAW, getString(R.string.relation_daughter_in_law)), // 120 + RadioItem(ContactRelation.TYPE_BROTHER_IN_LAW, getString(R.string.relation_brother_in_law)), // 121 + RadioItem(ContactRelation.TYPE_SISTER_IN_LAW, getString(R.string.relation_sister_in_law)), // 122 + RadioItem(Relation.TYPE_RELATIVE, getString(R.string.relation_relative)), // 12 + RadioItem(ContactRelation.TYPE_KIN, getString(R.string.relation_kin)), // 59 + + RadioItem(ContactRelation.TYPE_MUSE, getString(R.string.relation_muse)), // 60 + RadioItem(ContactRelation.TYPE_CRUSH, getString(R.string.relation_crush)), // 61 + RadioItem(ContactRelation.TYPE_DATE, getString(R.string.relation_date)), // 62 + RadioItem(ContactRelation.TYPE_SWEETHEART, getString(R.string.relation_sweetheart)), // 63 + + RadioItem(ContactRelation.TYPE_CONTACT, getString(R.string.relation_contact)), // 51 + RadioItem(ContactRelation.TYPE_ACQUAINTANCE, getString(R.string.relation_acquaintance)), // 52 + RadioItem(ContactRelation.TYPE_MET, getString(R.string.relation_met)), // 53 + RadioItem(Relation.TYPE_REFERRED_BY, getString(R.string.relation_referred_by)), // 11 + RadioItem(ContactRelation.TYPE_AGENT, getString(R.string.relation_agent)), // 64 + + RadioItem(ContactRelation.TYPE_COLLEAGUE, getString(R.string.relation_colleague)), // 55 + RadioItem(ContactRelation.TYPE_CO_WORKER, getString(R.string.relation_co_worker)), // 54 + RadioItem(ContactRelation.TYPE_SUPERIOR, getString(R.string.relation_superior)), // 101 + RadioItem(ContactRelation.TYPE_SUBORDINATE, getString(R.string.relation_subordinate)), // 102 + RadioItem(Relation.TYPE_MANAGER, getString(R.string.relation_manager)), // 7 + RadioItem(Relation.TYPE_ASSISTANT, getString(R.string.relation_assistant)), // 1 + + RadioItem(ContactRelation.TYPE_ME, getString(R.string.relation_me)), // 66 + RadioItem(ContactRelation.TYPE_EMERGENCY, getString(R.string.relation_emergency)) // 65 + ) + val currentRelationTypeId = getRelationTypeId(relationTypeField.value) + RadioGroupDialog(this, items, currentRelationTypeId) { + if (it as Int == CommonDataKinds.Relation.TYPE_CUSTOM) { + CustomLabelDialog(this) { + relationTypeField.text = it + } + } else { + relationTypeField.text = getRelationTypeText(it, "") + } + } + } + private fun showSelectGroupsDialog() { SelectGroupsDialog(this@EditContactActivity, contact!!.groups) { contact!!.groups = it @@ -1051,6 +1170,7 @@ class EditContactActivity : ContactActivity() { val filledIMs = getFilledIMs() val filledEvents = getFilledEvents() val filledWebsites = getFilledWebsites() + val filledRelations = getFilledRelations() val newContact = contact!!.copy( prefix = contact_prefix.value, @@ -1068,6 +1188,7 @@ class EditContactActivity : ContactActivity() { starred = if (isContactStarred()) 1 else 0, notes = contact_notes.value, websites = filledWebsites, + relations = filledRelations, ) val company = contact_organization_company.value @@ -1179,6 +1300,24 @@ class EditContactActivity : ContactActivity() { return websites } + private fun getFilledRelations(): ArrayList { + val relations = ArrayList() + val relationsCount = contact_relations_holder.childCount + for (i in 0 until relationsCount) { + val relationHolder = contact_relations_holder.getChildAt(i) + val name: String = relationHolder.contact_relation.value + if (name.isNotEmpty()) { + var label = relationHolder.contact_relation_type.value.trim() + val type = getRelationTypeId(label) + if (type != ContactRelation.TYPE_CUSTOM) { + label = "" + } + relations.add(ContactRelation(name, type, label)) + } + } + return relations + } + private fun insertNewContact(deleteCurrentContact: Boolean) { isSaving = true if (!deleteCurrentContact) { @@ -1357,6 +1496,17 @@ class EditContactActivity : ContactActivity() { } } + private fun addNewRelationsField() { + val relationHolder = layoutInflater.inflate(R.layout.item_edit_relation, contact_relations_holder, false) as ViewGroup + updateTextColors(relationHolder) + setupRelationTypePicker(relationHolder.contact_relation_type, DEFAULT_RELATION_TYPE, "") + contact_relations_holder.addView(relationHolder) + contact_relations_holder.onGlobalLayout { + relationHolder.contact_relation.requestFocus() + showKeyboard(relationHolder.contact_relation) + } + } + private fun isContactStarred() = contact_toggle_favorite.tag == 1 private fun getStarDrawable(on: Boolean) = resources.getDrawable(if (on) R.drawable.ic_star_vector else R.drawable.ic_star_outline_vector) @@ -1515,6 +1665,70 @@ class EditContactActivity : ContactActivity() { else -> StructuredPostal.TYPE_CUSTOM } + private fun getRelationTypeId(value: String) = when (value) { + getString(R.string.relation_assistant) -> Relation.TYPE_ASSISTANT + getString(R.string.relation_brother) -> Relation.TYPE_BROTHER + getString(R.string.relation_child) -> Relation.TYPE_CHILD + getString(R.string.relation_domestic_partner) -> Relation.TYPE_DOMESTIC_PARTNER + getString(R.string.relation_father) -> Relation.TYPE_FATHER + getString(R.string.relation_friend) -> Relation.TYPE_FRIEND + getString(R.string.relation_manager) -> Relation.TYPE_MANAGER + getString(R.string.relation_mother) -> Relation.TYPE_MOTHER + getString(R.string.relation_parent) -> Relation.TYPE_PARENT + getString(R.string.relation_partner) -> Relation.TYPE_PARTNER + getString(R.string.relation_referred_by) -> Relation.TYPE_REFERRED_BY + getString(R.string.relation_relative) -> Relation.TYPE_RELATIVE + getString(R.string.relation_sister) -> Relation.TYPE_SISTER + getString(R.string.relation_spouse) -> Relation.TYPE_SPOUSE + + // Relation types defined in vCard 4.0 + getString(R.string.relation_contact) -> ContactRelation.TYPE_CONTACT + getString(R.string.relation_acquaintance) -> ContactRelation.TYPE_ACQUAINTANCE + // getString(R.string.relation_friend) -> ContactRelation.TYPE_FRIEND + getString(R.string.relation_met) -> ContactRelation.TYPE_MET + getString(R.string.relation_co_worker) -> ContactRelation.TYPE_CO_WORKER + getString(R.string.relation_colleague) -> ContactRelation.TYPE_COLLEAGUE + getString(R.string.relation_co_resident) -> ContactRelation.TYPE_CO_RESIDENT + getString(R.string.relation_neighbor) -> ContactRelation.TYPE_NEIGHBOR + // getString(R.string.relation_child) -> ContactRelation.TYPE_CHILD + // getString(R.string.relation_parent) -> ContactRelation.TYPE_PARENT + getString(R.string.relation_sibling) -> ContactRelation.TYPE_SIBLING + // getString(R.string.relation_spouse) -> ContactRelation.TYPE_SPOUSE + getString(R.string.relation_kin) -> ContactRelation.TYPE_KIN + getString(R.string.relation_muse) -> ContactRelation.TYPE_MUSE + getString(R.string.relation_crush) -> ContactRelation.TYPE_CRUSH + getString(R.string.relation_date) -> ContactRelation.TYPE_DATE + getString(R.string.relation_sweetheart) -> ContactRelation.TYPE_SWEETHEART + getString(R.string.relation_me) -> ContactRelation.TYPE_ME + getString(R.string.relation_agent) -> ContactRelation.TYPE_AGENT + getString(R.string.relation_emergency) -> ContactRelation.TYPE_EMERGENCY + + getString(R.string.relation_superior) -> ContactRelation.TYPE_SUPERIOR + getString(R.string.relation_subordinate) -> ContactRelation.TYPE_SUBORDINATE + getString(R.string.relation_husband) -> ContactRelation.TYPE_HUSBAND + getString(R.string.relation_wife) -> ContactRelation.TYPE_WIFE + getString(R.string.relation_son) -> ContactRelation.TYPE_SON + getString(R.string.relation_daughter) -> ContactRelation.TYPE_DAUGHTER + getString(R.string.relation_grandparent) -> ContactRelation.TYPE_GRANDPARENT + getString(R.string.relation_grandfather) -> ContactRelation.TYPE_GRANDFATHER + getString(R.string.relation_grandmother) -> ContactRelation.TYPE_GRANDMOTHER + getString(R.string.relation_grandchild) -> ContactRelation.TYPE_GRANDCHILD + getString(R.string.relation_grandson) -> ContactRelation.TYPE_GRANDSON + getString(R.string.relation_granddaughter) -> ContactRelation.TYPE_GRANDDAUGHTER + getString(R.string.relation_uncle) -> ContactRelation.TYPE_UNCLE + getString(R.string.relation_aunt) -> ContactRelation.TYPE_AUNT + getString(R.string.relation_nephew) -> ContactRelation.TYPE_NEPHEW + getString(R.string.relation_niece) -> ContactRelation.TYPE_NIECE + getString(R.string.relation_father_in_law) -> ContactRelation.TYPE_FATHER_IN_LAW + getString(R.string.relation_mother_in_law) -> ContactRelation.TYPE_MOTHER_IN_LAW + getString(R.string.relation_son_in_law) -> ContactRelation.TYPE_SON_IN_LAW + getString(R.string.relation_daughter_in_law) -> ContactRelation.TYPE_DAUGHTER_IN_LAW + getString(R.string.relation_brother_in_law) -> ContactRelation.TYPE_BROTHER_IN_LAW + getString(R.string.relation_sister_in_law) -> ContactRelation.TYPE_SISTER_IN_LAW + + else -> Relation.TYPE_CUSTOM + } + private fun getIMTypeId(value: String) = when (value) { getString(R.string.aim) -> Im.PROTOCOL_AIM getString(R.string.windows_live) -> Im.PROTOCOL_MSN diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ViewContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ViewContactActivity.kt index 583e71681..63d1ce2a5 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ViewContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ViewContactActivity.kt @@ -36,6 +36,7 @@ import kotlinx.android.synthetic.main.item_view_event.view.* import kotlinx.android.synthetic.main.item_view_group.view.* import kotlinx.android.synthetic.main.item_view_im.view.* import kotlinx.android.synthetic.main.item_view_phone_number.view.* +import kotlinx.android.synthetic.main.item_view_relation.view.* import kotlinx.android.synthetic.main.item_website.view.* class ViewContactActivity : ContactActivity() { @@ -229,8 +230,11 @@ class ViewContactActivity : ContactActivity() { val textColor = getProperTextColor() arrayOf( - contact_name_image, contact_numbers_image, contact_emails_image, contact_addresses_image, contact_ims_image, contact_events_image, - contact_source_image, contact_notes_image, contact_ringtone_image, contact_organization_image, contact_websites_image, contact_groups_image + contact_name_image, contact_numbers_image, contact_emails_image, + contact_addresses_image, contact_ims_image, contact_events_image, + contact_source_image, contact_notes_image, contact_ringtone_image, + contact_organization_image, contact_websites_image, contact_relations_image, + contact_groups_image ).forEach { it.applyColorFilter(textColor) } @@ -276,6 +280,7 @@ class ViewContactActivity : ContactActivity() { setupIMs() setupEvents() setupWebsites() + setupRelations() setupGroups() setupContactSources() setupNotes() @@ -570,6 +575,38 @@ class ViewContactActivity : ContactActivity() { } } + private fun setupRelations() { + var relations: ArrayList = contact!!.relations + + if (mergeDuplicate) { + duplicateContacts.forEach { + relations.addAll(it.relations) + } + } + + relations.sortBy { it.type } + fullContact!!.relations = relations + + contact_relations_holder.removeAllViews() + + if (relations.isNotEmpty() && ((showFields and SHOW_RELATIONS_FIELD) != 0)) { + relations.forEach { + val relation = it + layoutInflater.inflate(R.layout.item_view_relation, contact_relations_holder, false).apply { + contact_relations_holder.addView(this) + contact_relation.text = relation.name + contact_relation_type.text = getRelationTypeText(relation.type, relation.label) + copyOnLongClick(relation.name) + } + } + contact_relations_image.beVisible() + contact_relations_holder.beVisible() + } else { + contact_relations_image.beGone() + contact_relations_holder.beGone() + } + } + private fun setupGroups() { var groups = contact!!.groups.toMutableSet() as LinkedHashSet diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageVisibleFieldsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageVisibleFieldsDialog.kt index b0b161615..b43f9e8e3 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageVisibleFieldsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageVisibleFieldsDialog.kt @@ -28,6 +28,7 @@ class ManageVisibleFieldsDialog(val activity: BaseSimpleActivity, val callback: put(SHOW_NOTES_FIELD, R.id.manage_visible_fields_notes) put(SHOW_ORGANIZATION_FIELD, R.id.manage_visible_fields_organization) put(SHOW_WEBSITES_FIELD, R.id.manage_visible_fields_websites) + put(SHOW_RELATIONS_FIELD, R.id.manage_visible_fields_relations) put(SHOW_GROUPS_FIELD, R.id.manage_visible_fields_groups) put(SHOW_CONTACT_SOURCE_FIELD, R.id.manage_visible_fields_contact_source) put(SHOW_RINGTONE_FIELD, R.id.manage_ringtone) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfExporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfExporter.kt index d586a0dfb..ba7136f91 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfExporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfExporter.kt @@ -13,12 +13,14 @@ import com.simplemobiletools.commons.extensions.getDateTimeFromDateString import com.simplemobiletools.commons.extensions.showErrorToast import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.models.contacts.Contact +import com.simplemobiletools.commons.models.contacts.ContactRelation import com.simplemobiletools.contacts.pro.R import com.simplemobiletools.contacts.pro.helpers.VcfExporter.ExportResult.EXPORT_FAIL import ezvcard.Ezvcard import ezvcard.VCard import ezvcard.VCardVersion import ezvcard.parameter.ImageType +import ezvcard.parameter.RelatedType import ezvcard.property.* import java.io.OutputStream import java.util.* @@ -145,6 +147,78 @@ class VcfExporter { card.addUrl(it) } + contact.relations.forEach { + var name = it.name.trim() + if (name.isNotEmpty()) { + var related = ezvcard.property.Related() + related.text = name + related.types.add ( + when (it.type) { + // vCard 4.0 relation types are directly mapped to their related type + ContactRelation.TYPE_CONTACT -> RelatedType.CONTACT + ContactRelation.TYPE_ACQUAINTANCE -> RelatedType.ACQUAINTANCE + ContactRelation.TYPE_FRIEND -> RelatedType.FRIEND + ContactRelation.TYPE_MET -> RelatedType.MET + ContactRelation.TYPE_CO_WORKER -> RelatedType.CO_WORKER + ContactRelation.TYPE_COLLEAGUE -> RelatedType.COLLEAGUE + ContactRelation.TYPE_CO_RESIDENT -> RelatedType.CO_RESIDENT + ContactRelation.TYPE_NEIGHBOR -> RelatedType.NEIGHBOR + ContactRelation.TYPE_CHILD -> RelatedType.CHILD + ContactRelation.TYPE_PARENT -> RelatedType.PARENT + ContactRelation.TYPE_SIBLING -> RelatedType.SIBLING + ContactRelation.TYPE_SPOUSE -> RelatedType.SPOUSE + ContactRelation.TYPE_KIN -> RelatedType.KIN + ContactRelation.TYPE_MUSE -> RelatedType.MUSE + ContactRelation.TYPE_CRUSH -> RelatedType.CRUSH + ContactRelation.TYPE_DATE -> RelatedType.DATE + ContactRelation.TYPE_SWEETHEART -> RelatedType.SWEETHEART + ContactRelation.TYPE_ME -> RelatedType.ME + ContactRelation.TYPE_AGENT -> RelatedType.AGENT + ContactRelation.TYPE_EMERGENCY -> RelatedType.EMERGENCY + + // Android relation types are mapped to a suitable substitute (with loss of precision!) + ContactRelation.TYPE_ASSISTANT -> RelatedType.COLLEAGUE + ContactRelation.TYPE_BROTHER -> RelatedType.SIBLING + ContactRelation.TYPE_DOMESTIC_PARTNER -> RelatedType.FRIEND + ContactRelation.TYPE_FATHER -> RelatedType.PARENT + ContactRelation.TYPE_MANAGER -> RelatedType.COLLEAGUE + ContactRelation.TYPE_MOTHER -> RelatedType.PARENT + ContactRelation.TYPE_PARTNER -> RelatedType.FRIEND + ContactRelation.TYPE_REFERRED_BY -> RelatedType.CONTACT + ContactRelation.TYPE_RELATIVE -> RelatedType.KIN + ContactRelation.TYPE_SISTER -> RelatedType.SIBLING + + // Custom relation types are mapped to a suitable substitute (with loss of precision!) + ContactRelation.TYPE_SUPERIOR -> RelatedType.COLLEAGUE + ContactRelation.TYPE_SUBORDINATE -> RelatedType.COLLEAGUE + + ContactRelation.TYPE_HUSBAND -> RelatedType.SPOUSE + ContactRelation.TYPE_WIFE -> RelatedType.SPOUSE + ContactRelation.TYPE_SON -> RelatedType.CHILD + ContactRelation.TYPE_DAUGHTER -> RelatedType.CHILD + ContactRelation.TYPE_GRANDPARENT -> RelatedType.KIN + ContactRelation.TYPE_GRANDFATHER -> RelatedType.KIN + ContactRelation.TYPE_GRANDMOTHER -> RelatedType.KIN + ContactRelation.TYPE_GRANDCHILD -> RelatedType.KIN + ContactRelation.TYPE_GRANDSON -> RelatedType.KIN + ContactRelation.TYPE_GRANDDAUGHTER -> RelatedType.KIN + ContactRelation.TYPE_UNCLE -> RelatedType.KIN + ContactRelation.TYPE_AUNT -> RelatedType.KIN + ContactRelation.TYPE_NEPHEW -> RelatedType.KIN + ContactRelation.TYPE_NIECE -> RelatedType.KIN + ContactRelation.TYPE_FATHER_IN_LAW -> RelatedType.KIN + ContactRelation.TYPE_MOTHER_IN_LAW -> RelatedType.KIN + ContactRelation.TYPE_SON_IN_LAW -> RelatedType.KIN + ContactRelation.TYPE_DAUGHTER_IN_LAW -> RelatedType.KIN + ContactRelation.TYPE_BROTHER_IN_LAW -> RelatedType.KIN + ContactRelation.TYPE_SISTER_IN_LAW -> RelatedType.KIN + else -> RelatedType.CONTACT + } + ) + card.addRelated(related) + } + } + if (contact.thumbnailUri.isNotEmpty()) { val photoByteArray = MediaStore.Images.Media.getBitmap(activity.contentResolver, Uri.parse(contact.thumbnailUri)).getByteArray() val photo = Photo(photoByteArray, ImageType.JPEG) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfImporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfImporter.kt index a21c1952a..940850a73 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfImporter.kt @@ -22,6 +22,7 @@ import com.simplemobiletools.contacts.pro.helpers.VcfImporter.ImportResult.IMPOR import com.simplemobiletools.contacts.pro.helpers.VcfImporter.ImportResult.IMPORT_PARTIAL import ezvcard.Ezvcard import ezvcard.VCard +import ezvcard.parameter.RelatedType import ezvcard.util.PartialDate import java.io.File import java.io.FileOutputStream @@ -161,6 +162,15 @@ class VcfImporter(val activity: SimpleActivity) { val ringtone = null + val relations = ArrayList() + ezContact.relations.forEach { + val name = it.text + val type = getRelationTypeId(it.types.firstOrNull()) + if (name.isNotEmpty()) { + relations.add(ContactRelation(name, type, "")) + } + } + val IMs = ArrayList() ezContact.impps.forEach { val typeString = it.uri.scheme @@ -184,7 +194,7 @@ class VcfImporter(val activity: SimpleActivity) { val contact = Contact( 0, prefix, firstName, middleName, surname, suffix, nickname, photoUri, phoneNumbers, emails, addresses, events, - targetContactSource, starred, contactId, thumbnailUri, photo, notes, groups, organization, websites, IMs, DEFAULT_MIMETYPE, ringtone + targetContactSource, starred, contactId, thumbnailUri, photo, notes, groups, organization, websites, relations, IMs, DEFAULT_MIMETYPE, ringtone ) // if there is no N and ORG fields at the given contact, only FN, treat it as an organization @@ -285,13 +295,43 @@ class VcfImporter(val activity: SimpleActivity) { else -> CommonDataKinds.Email.TYPE_CUSTOM } - private fun getAddressTypeId(type: String) = when (type.toUpperCase()) { + private fun getAddressTypeId(type: String): Int = when (type.toUpperCase()) { HOME -> StructuredPostal.TYPE_HOME WORK -> StructuredPostal.TYPE_WORK OTHER -> StructuredPostal.TYPE_OTHER else -> StructuredPostal.TYPE_CUSTOM } + private fun getRelationTypeId(type: RelatedType?): Int { + if (type == null) { + return (ContactRelation.TYPE_CONTACT) + } else { + return when (type) { + RelatedType.ACQUAINTANCE -> ContactRelation.TYPE_ACQUAINTANCE + RelatedType.AGENT -> ContactRelation.TYPE_AGENT + RelatedType.CHILD -> ContactRelation.TYPE_CHILD + RelatedType.CO_RESIDENT -> ContactRelation.TYPE_CO_RESIDENT + RelatedType.CO_WORKER -> ContactRelation.TYPE_CO_WORKER + RelatedType.COLLEAGUE -> ContactRelation.TYPE_COLLEAGUE + RelatedType.CONTACT -> ContactRelation.TYPE_CONTACT + RelatedType.CRUSH -> ContactRelation.TYPE_CRUSH + RelatedType.DATE -> ContactRelation.TYPE_DATE + RelatedType.EMERGENCY -> ContactRelation.TYPE_EMERGENCY + RelatedType.FRIEND -> ContactRelation.TYPE_FRIEND + RelatedType.ME -> ContactRelation.TYPE_ME + RelatedType.MET -> ContactRelation.TYPE_MET + RelatedType.MUSE -> ContactRelation.TYPE_MUSE + RelatedType.NEIGHBOR -> ContactRelation.TYPE_NEIGHBOR + RelatedType.PARENT -> ContactRelation.TYPE_PARENT + RelatedType.SIBLING -> ContactRelation.TYPE_SIBLING + RelatedType.SPOUSE -> ContactRelation.TYPE_SPOUSE + RelatedType.SWEETHEART -> ContactRelation.TYPE_SWEETHEART + RelatedType.PARENT -> ContactRelation.TYPE_PARENT + else -> ContactRelation.TYPE_CONTACT + } + } + } + private fun savePhoto(byteArray: ByteArray?): String { if (byteArray == null) { return "" diff --git a/app/src/main/res/drawable/ic_relation_vector.xml b/app/src/main/res/drawable/ic_relation_vector.xml new file mode 100644 index 000000000..cb5558d11 --- /dev/null +++ b/app/src/main/res/drawable/ic_relation_vector.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/app/src/main/res/layout/activity_edit_contact.xml b/app/src/main/res/layout/activity_edit_contact.xml index b6f575687..50a6336c0 100644 --- a/app/src/main/res/layout/activity_edit_contact.xml +++ b/app/src/main/res/layout/activity_edit_contact.xml @@ -504,6 +504,44 @@ android:paddingBottom="@dimen/medium_margin" android:src="@drawable/ic_plus_vector" /> + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_view_contact.xml b/app/src/main/res/layout/activity_view_contact.xml index 0a324e9ae..241c68e4e 100644 --- a/app/src/main/res/layout/activity_view_contact.xml +++ b/app/src/main/res/layout/activity_view_contact.xml @@ -243,6 +243,19 @@ android:src="@drawable/ic_link_vector" android:visibility="gone" /> + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_view_relation.xml b/app/src/main/res/layout/item_view_relation.xml new file mode 100644 index 000000000..618d8c046 --- /dev/null +++ b/app/src/main/res/layout/item_view_relation.xml @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/graphics/ic_relation.svg b/graphics/ic_relation.svg new file mode 100644 index 000000000..104d3c7b6 --- /dev/null +++ b/graphics/ic_relation.svg @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + +