Merge pull request #11 from SimpleMobileTools/master

upd
This commit is contained in:
solokot
2018-04-13 14:33:49 +03:00
committed by GitHub
52 changed files with 1822 additions and 555 deletions

View File

@ -1,6 +1,21 @@
Changelog Changelog
========== ==========
Version 3.5.1 *(2018-04-10)*
----------------------------
* Show the organization name as the contact name in case only that is filled
* Fix "Start name with surname"
Version 3.5.0 *(2018-04-08)*
----------------------------
* Added name prefix/suffix and contact organizations (hidden by default)
* Added a settings item "Manage shown contact fields" for customizing visible contact details, with some fields disabled by default
* Allow using the app without granting Contacts permission, rely on local secret storage only
* Dial the selected contact if Call permission is not granted
* Many performance improvements and smaller bugfixes
Version 3.4.0 *(2018-03-21)* Version 3.4.0 *(2018-03-21)*
---------------------------- ----------------------------

View File

@ -10,8 +10,8 @@ android {
applicationId "com.simplemobiletools.contacts" applicationId "com.simplemobiletools.contacts"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 27 targetSdkVersion 27
versionCode 15 versionCode 17
versionName "3.4.0" versionName "3.5.1"
setProperty("archivesBaseName", "contacts") setProperty("archivesBaseName", "contacts")
} }
@ -45,10 +45,9 @@ ext {
} }
dependencies { dependencies {
implementation 'com.simplemobiletools:commons:3.16.12' implementation 'com.simplemobiletools:commons:3.18.23'
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.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"

View File

@ -33,8 +33,9 @@ import java.text.SimpleDateFormat
import java.util.* import java.util.*
abstract class ContactActivity : SimpleActivity() { abstract class ContactActivity : SimpleActivity() {
var contact: Contact? = null protected var contact: Contact? = null
var currentContactPhotoPath = "" protected var currentContactPhotoPath = ""
protected var showFields = 0
fun showPhotoPlaceholder(photoView: ImageView) { fun showPhotoPlaceholder(photoView: ImageView) {
val placeholder = resources.getColoredBitmap(R.drawable.ic_person, config.primaryColor.getContrastColor()) val placeholder = resources.getColoredBitmap(R.drawable.ic_person, config.primaryColor.getContrastColor())

View File

@ -49,30 +49,39 @@ class EditContactActivity : ContactActivity() {
private val REMOVE_PHOTO = 3 private val REMOVE_PHOTO = 3
private val KEY_PHONE = "phone" private val KEY_PHONE = "phone"
private val KEY_NAME = "name"
private var wasActivityInitialized = false private var wasActivityInitialized = false
private var lastPhotoIntentUri: Uri? = null private var lastPhotoIntentUri: Uri? = null
private var isSaving = false private var isSaving = false
private var isThirdPartyIntent = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_edit_contact) setContentView(R.layout.activity_edit_contact)
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_cross) supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_cross)
showFields = config.showContactFields
handlePermission(PERMISSION_READ_CONTACTS) { val action = intent.action
if (it) { isThirdPartyIntent = action == Intent.ACTION_EDIT || action == Intent.ACTION_INSERT_OR_EDIT || action == Intent.ACTION_INSERT
handlePermission(PERMISSION_WRITE_CONTACTS) { if (isThirdPartyIntent) {
if (it) { handlePermission(PERMISSION_READ_CONTACTS) {
initContact() if (it) {
} else { handlePermission(PERMISSION_WRITE_CONTACTS) {
toast(R.string.no_contacts_permission) if (it) {
finish() initContact()
} else {
toast(R.string.no_contacts_permission)
finish()
}
} }
} else {
toast(R.string.no_contacts_permission)
finish()
} }
} else {
toast(R.string.no_contacts_permission)
finish()
} }
} else {
initContact()
} }
} }
@ -138,10 +147,13 @@ class EditContactActivity : ContactActivity() {
setupEditContact() setupEditContact()
} }
if (contact!!.id == 0 && intent.extras?.containsKey(KEY_PHONE) == true && (intent.action == Intent.ACTION_INSERT_OR_EDIT || intent.action == Intent.ACTION_INSERT)) { if (contact!!.id == 0 && intent.extras?.containsKey(KEY_PHONE) == true && (action == Intent.ACTION_INSERT_OR_EDIT || action == Intent.ACTION_INSERT)) {
val phoneNumber = intent.getStringExtra(KEY_PHONE) val phoneNumber = intent.extras.get(KEY_PHONE).toString() ?: ""
contact!!.phoneNumbers.add(PhoneNumber(phoneNumber, DEFAULT_PHONE_NUMBER_TYPE)) contact!!.phoneNumbers.add(PhoneNumber(phoneNumber, DEFAULT_PHONE_NUMBER_TYPE))
setupPhoneNumbers() setupPhoneNumbers()
val contactFullName = intent.extras.get(KEY_NAME)?.toString() ?: ""
contact_first_name.setText(contactFullName)
} }
setupTypePickers() setupTypePickers()
@ -162,23 +174,24 @@ class EditContactActivity : ContactActivity() {
contact_start_call.applyColorFilter(textColor) contact_start_call.applyColorFilter(textColor)
contact_send_email.applyColorFilter(textColor) contact_send_email.applyColorFilter(textColor)
contact_name_image.applyColorFilter(textColor) contact_name_image.applyColorFilter(textColor)
contact_number_image.applyColorFilter(textColor) contact_numbers_image.applyColorFilter(textColor)
contact_email_image.applyColorFilter(textColor) contact_emails_image.applyColorFilter(textColor)
contact_address_image.applyColorFilter(textColor) contact_addresses_image.applyColorFilter(textColor)
contact_event_image.applyColorFilter(textColor) contact_events_image.applyColorFilter(textColor)
contact_notes_image.applyColorFilter(textColor) contact_notes_image.applyColorFilter(textColor)
contact_source_image.applyColorFilter(textColor) contact_source_image.applyColorFilter(textColor)
contact_groups_image.applyColorFilter(textColor) contact_groups_image.applyColorFilter(textColor)
contact_organization_image.applyColorFilter(textColor)
val adjustedPrimaryColor = getAdjustedPrimaryColor() val adjustedPrimaryColor = getAdjustedPrimaryColor()
contact_number_add_new.applyColorFilter(adjustedPrimaryColor) contact_numbers_add_new.applyColorFilter(adjustedPrimaryColor)
contact_number_add_new.background.applyColorFilter(textColor) contact_numbers_add_new.background.applyColorFilter(textColor)
contact_email_add_new.applyColorFilter(adjustedPrimaryColor) contact_emails_add_new.applyColorFilter(adjustedPrimaryColor)
contact_email_add_new.background.applyColorFilter(textColor) contact_emails_add_new.background.applyColorFilter(textColor)
contact_address_add_new.applyColorFilter(adjustedPrimaryColor) contact_addresses_add_new.applyColorFilter(adjustedPrimaryColor)
contact_address_add_new.background.applyColorFilter(textColor) contact_addresses_add_new.background.applyColorFilter(textColor)
contact_event_add_new.applyColorFilter(adjustedPrimaryColor) contact_events_add_new.applyColorFilter(adjustedPrimaryColor)
contact_event_add_new.background.applyColorFilter(textColor) contact_events_add_new.background.applyColorFilter(textColor)
contact_groups_add_new.applyColorFilter(adjustedPrimaryColor) contact_groups_add_new.applyColorFilter(adjustedPrimaryColor)
contact_groups_add_new.background.applyColorFilter(textColor) contact_groups_add_new.background.applyColorFilter(textColor)
@ -187,12 +200,14 @@ class EditContactActivity : ContactActivity() {
contact_send_sms.setOnClickListener { trySendSMS() } contact_send_sms.setOnClickListener { trySendSMS() }
contact_start_call.setOnClickListener { tryStartCall(contact!!) } contact_start_call.setOnClickListener { tryStartCall(contact!!) }
contact_send_email.setOnClickListener { trySendEmail() } contact_send_email.setOnClickListener { trySendEmail() }
contact_number_add_new.setOnClickListener { addNewPhoneNumberField() } contact_numbers_add_new.setOnClickListener { addNewPhoneNumberField() }
contact_email_add_new.setOnClickListener { addNewEmailField() } contact_emails_add_new.setOnClickListener { addNewEmailField() }
contact_address_add_new.setOnClickListener { addNewAddressField() } contact_addresses_add_new.setOnClickListener { addNewAddressField() }
contact_event_add_new.setOnClickListener { addNewEventField() } contact_events_add_new.setOnClickListener { addNewEventField() }
contact_groups_add_new.setOnClickListener { showSelectGroupsDialog() } contact_groups_add_new.setOnClickListener { showSelectGroupsDialog() }
setupFieldVisibility()
contact_toggle_favorite.apply { contact_toggle_favorite.apply {
setImageDrawable(getStarDrawable(contact!!.starred == 1)) setImageDrawable(getStarDrawable(contact!!.starred == 1))
tag = contact!!.starred tag = contact!!.starred
@ -231,94 +246,164 @@ class EditContactActivity : ContactActivity() {
} }
} }
private fun setupFieldVisibility() {
if (showFields and (SHOW_PREFIX_FIELD or SHOW_FIRST_NAME_FIELD or SHOW_MIDDLE_NAME_FIELD or SHOW_SURNAME_FIELD or SHOW_SUFFIX_FIELD) == 0) {
contact_name_image.beInvisible()
}
contact_prefix.beVisibleIf(showFields and SHOW_PREFIX_FIELD != 0)
contact_first_name.beVisibleIf(showFields and SHOW_FIRST_NAME_FIELD != 0)
contact_middle_name.beVisibleIf(showFields and SHOW_MIDDLE_NAME_FIELD != 0)
contact_surname.beVisibleIf(showFields and SHOW_SURNAME_FIELD != 0)
contact_suffix.beVisibleIf(showFields and SHOW_SUFFIX_FIELD != 0)
contact_source.beVisibleIf(showFields and SHOW_CONTACT_SOURCE_FIELD != 0)
contact_source_image.beVisibleIf(showFields and SHOW_CONTACT_SOURCE_FIELD != 0)
val arePhoneNumbersVisible = showFields and SHOW_PHONE_NUMBERS_FIELD != 0
contact_numbers_image.beVisibleIf(arePhoneNumbersVisible)
contact_numbers_holder.beVisibleIf(arePhoneNumbersVisible)
contact_numbers_add_new.beVisibleIf(arePhoneNumbersVisible)
val areEmailsVisible = showFields and SHOW_EMAILS_FIELD != 0
contact_emails_image.beVisibleIf(areEmailsVisible)
contact_emails_holder.beVisibleIf(areEmailsVisible)
contact_emails_add_new.beVisibleIf(areEmailsVisible)
val areAddressesVisible = showFields and SHOW_ADDRESSES_FIELD != 0
contact_addresses_image.beVisibleIf(areAddressesVisible)
contact_addresses_holder.beVisibleIf(areAddressesVisible)
contact_addresses_add_new.beVisibleIf(areAddressesVisible)
val isOrganizationVisible = showFields and SHOW_ORGANIZATION_FIELD != 0
contact_organization_company.beVisibleIf(isOrganizationVisible)
contact_organization_job_position.beVisibleIf(isOrganizationVisible)
contact_organization_image.beVisibleIf(isOrganizationVisible)
val areEventsVisible = showFields and SHOW_EVENTS_FIELD != 0
contact_events_image.beVisibleIf(areEventsVisible)
contact_events_holder.beVisibleIf(areEventsVisible)
contact_events_add_new.beVisibleIf(areEventsVisible)
val areGroupsVisible = showFields and SHOW_GROUPS_FIELD != 0
contact_groups_image.beVisibleIf(areGroupsVisible)
contact_groups_holder.beVisibleIf(areGroupsVisible)
contact_groups_add_new.beVisibleIf(areGroupsVisible)
val areNotesVisible = showFields and SHOW_NOTES_FIELD != 0
contact_notes.beVisibleIf(areNotesVisible)
contact_notes_image.beVisibleIf(areNotesVisible)
}
private fun setupEditContact() { private fun setupEditContact() {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
supportActionBar?.title = resources.getString(R.string.edit_contact) supportActionBar?.title = resources.getString(R.string.edit_contact)
contact_prefix.setText(contact!!.prefix)
contact_first_name.setText(contact!!.firstName) contact_first_name.setText(contact!!.firstName)
contact_middle_name.setText(contact!!.middleName) contact_middle_name.setText(contact!!.middleName)
contact_surname.setText(contact!!.surname) contact_surname.setText(contact!!.surname)
contact_suffix.setText(contact!!.suffix)
contact_source.text = getPublicContactSource(contact!!.source) contact_source.text = getPublicContactSource(contact!!.source)
setupPhoneNumbers() setupPhoneNumbers()
setupEmails() setupEmails()
setupAddresses() setupAddresses()
setupNotes() setupNotes()
setupOrganization()
setupEvents() setupEvents()
setupGroups() setupGroups()
} }
private fun setupPhoneNumbers() { private fun setupPhoneNumbers() {
contact!!.phoneNumbers.forEachIndexed { index, number -> if (showFields and SHOW_PHONE_NUMBERS_FIELD != 0) {
var numberHolder = contact_numbers_holder.getChildAt(index) contact!!.phoneNumbers.forEachIndexed { index, number ->
if (numberHolder == null) { var numberHolder = contact_numbers_holder.getChildAt(index)
numberHolder = layoutInflater.inflate(R.layout.item_edit_phone_number, contact_numbers_holder, false) if (numberHolder == null) {
contact_numbers_holder.addView(numberHolder) numberHolder = layoutInflater.inflate(R.layout.item_edit_phone_number, contact_numbers_holder, false)
} contact_numbers_holder.addView(numberHolder)
}
numberHolder!!.apply { numberHolder!!.apply {
contact_number.setText(number.value) contact_number.setText(number.value)
setupPhoneNumberTypePicker(contact_number_type, number.type) setupPhoneNumberTypePicker(contact_number_type, number.type)
}
} }
} }
} }
private fun setupEmails() { private fun setupEmails() {
contact!!.emails.forEachIndexed { index, email -> if (showFields and SHOW_EMAILS_FIELD != 0) {
var emailHolder = contact_emails_holder.getChildAt(index) contact!!.emails.forEachIndexed { index, email ->
if (emailHolder == null) { var emailHolder = contact_emails_holder.getChildAt(index)
emailHolder = layoutInflater.inflate(R.layout.item_edit_email, contact_emails_holder, false) if (emailHolder == null) {
contact_emails_holder.addView(emailHolder) emailHolder = layoutInflater.inflate(R.layout.item_edit_email, contact_emails_holder, false)
} contact_emails_holder.addView(emailHolder)
}
emailHolder!!.apply { emailHolder!!.apply {
contact_email.setText(email.value) contact_email.setText(email.value)
setupEmailTypePicker(contact_email_type, email.type) setupEmailTypePicker(contact_email_type, email.type)
}
} }
} }
} }
private fun setupAddresses() { private fun setupAddresses() {
contact!!.addresses.forEachIndexed { index, address -> if (showFields and SHOW_ADDRESSES_FIELD != 0) {
var addressHolder = contact_addresses_holder.getChildAt(index) contact!!.addresses.forEachIndexed { index, address ->
if (addressHolder == null) { var addressHolder = contact_addresses_holder.getChildAt(index)
addressHolder = layoutInflater.inflate(R.layout.item_edit_address, contact_addresses_holder, false) if (addressHolder == null) {
contact_addresses_holder.addView(addressHolder) addressHolder = layoutInflater.inflate(R.layout.item_edit_address, contact_addresses_holder, false)
} contact_addresses_holder.addView(addressHolder)
}
addressHolder!!.apply { addressHolder!!.apply {
contact_address.setText(address.value) contact_address.setText(address.value)
setupAddressTypePicker(contact_address_type, address.type) setupAddressTypePicker(contact_address_type, address.type)
}
} }
} }
} }
private fun setupNotes() { private fun setupNotes() {
contact_notes.setText(contact!!.notes) if (showFields and SHOW_NOTES_FIELD != 0) {
contact_notes.setText(contact!!.notes)
}
}
private fun setupOrganization() {
if (showFields and SHOW_ORGANIZATION_FIELD != 0) {
contact_organization_company.setText(contact!!.organization.company)
contact_organization_job_position.setText(contact!!.organization.jobPosition)
}
} }
private fun setupEvents() { private fun setupEvents() {
contact!!.events.forEachIndexed { index, event -> if (showFields and SHOW_EVENTS_FIELD != 0) {
var eventHolder = contact_events_holder.getChildAt(index) contact!!.events.forEachIndexed { index, event ->
if (eventHolder == null) { var eventHolder = contact_events_holder.getChildAt(index)
eventHolder = layoutInflater.inflate(R.layout.item_event, contact_events_holder, false) if (eventHolder == null) {
contact_events_holder.addView(eventHolder) eventHolder = layoutInflater.inflate(R.layout.item_event, contact_events_holder, false)
} contact_events_holder.addView(eventHolder)
(eventHolder as ViewGroup).apply {
val contactEvent = contact_event.apply {
getDateTime(event.value, this)
tag = event.value
alpha = 1f
} }
setupEventTypePicker(this, event.type) (eventHolder as ViewGroup).apply {
val contactEvent = contact_event.apply {
getDateTime(event.value, this)
tag = event.value
alpha = 1f
}
contact_event_remove.apply { setupEventTypePicker(this, event.type)
beVisible()
applyColorFilter(getAdjustedPrimaryColor()) contact_event_remove.apply {
background.applyColorFilter(config.textColor) beVisible()
setOnClickListener { applyColorFilter(getAdjustedPrimaryColor())
resetContactEvent(contactEvent, this) background.applyColorFilter(config.textColor)
setOnClickListener {
resetContactEvent(contactEvent, this)
}
} }
} }
} }
@ -326,59 +411,64 @@ class EditContactActivity : ContactActivity() {
} }
private fun setupGroups() { private fun setupGroups() {
contact_groups_holder.removeAllViews() if (showFields and SHOW_GROUPS_FIELD != 0) {
val groups = contact!!.groups contact_groups_holder.removeAllViews()
groups.forEachIndexed { index, group -> val groups = contact!!.groups
var groupHolder = contact_groups_holder.getChildAt(index) groups.forEachIndexed { index, group ->
if (groupHolder == null) { var groupHolder = contact_groups_holder.getChildAt(index)
groupHolder = layoutInflater.inflate(R.layout.item_edit_group, contact_groups_holder, false) if (groupHolder == null) {
contact_groups_holder.addView(groupHolder) groupHolder = layoutInflater.inflate(R.layout.item_edit_group, contact_groups_holder, false)
} contact_groups_holder.addView(groupHolder)
(groupHolder as ViewGroup).apply {
contact_group.apply {
text = group.title
setTextColor(config.textColor)
tag = group.id
alpha = 1f
} }
setOnClickListener { (groupHolder as ViewGroup).apply {
showSelectGroupsDialog() contact_group.apply {
} text = group.title
setTextColor(config.textColor)
tag = group.id
alpha = 1f
}
contact_group_remove.apply {
beVisible()
applyColorFilter(getAdjustedPrimaryColor())
background.applyColorFilter(config.textColor)
setOnClickListener { setOnClickListener {
removeGroup(group.id) showSelectGroupsDialog()
}
contact_group_remove.apply {
beVisible()
applyColorFilter(getAdjustedPrimaryColor())
background.applyColorFilter(config.textColor)
setOnClickListener {
removeGroup(group.id)
}
} }
} }
} }
}
if (groups.isEmpty()) { if (groups.isEmpty()) {
layoutInflater.inflate(R.layout.item_edit_group, contact_groups_holder, false).apply { layoutInflater.inflate(R.layout.item_edit_group, contact_groups_holder, false).apply {
contact_group.apply { contact_group.apply {
alpha = 0.5f alpha = 0.5f
text = getString(R.string.no_groups) text = getString(R.string.no_groups)
setTextColor(config.textColor) setTextColor(config.textColor)
} }
contact_groups_holder.addView(this) contact_groups_holder.addView(this)
contact_group_remove.beGone() contact_group_remove.beGone()
setOnClickListener { setOnClickListener {
showSelectGroupsDialog() showSelectGroupsDialog()
}
} }
} }
} }
} }
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(), ArrayList(), config.lastUsedContactSource, 0, 0, "", null, "", ArrayList()) val contactSource = if (hasContactPermissions()) config.lastUsedContactSource else SMT_PRIVATE
val organization = Organization("", "")
contact = Contact(0, "", "", "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), contactSource, 0, 0, "", null, "",
ArrayList(), organization, ArrayList())
contact_source.text = getPublicContactSource(contact!!.source) contact_source.text = getPublicContactSource(contact!!.source)
contact_source.setOnClickListener { contact_source.setOnClickListener {
showContactSourcePicker(contact!!.source) { showContactSourcePicker(contact!!.source) {
@ -583,9 +673,11 @@ class EditContactActivity : ContactActivity() {
contact!!.apply { contact!!.apply {
val oldPhotoUri = photoUri val oldPhotoUri = photoUri
prefix = contact_prefix.value
firstName = contact_first_name.value firstName = contact_first_name.value
middleName = contact_middle_name.value middleName = contact_middle_name.value
surname = contact_surname.value surname = contact_surname.value
suffix = contact_suffix.value
photoUri = currentContactPhotoPath photoUri = currentContactPhotoPath
phoneNumbers = getFilledPhoneNumbers() phoneNumbers = getFilledPhoneNumbers()
emails = getFilledEmails() emails = getFilledEmails()
@ -595,6 +687,10 @@ class EditContactActivity : ContactActivity() {
starred = if (isContactStarred()) 1 else 0 starred = if (isContactStarred()) 1 else 0
notes = contact_notes.value notes = contact_notes.value
val company = contact_organization_company.value
val jobPosition = contact_organization_job_position.value
organization = Organization(company, jobPosition)
Thread { Thread {
config.lastUsedContactSource = source config.lastUsedContactSource = source
if (id == 0) { if (id == 0) {

View File

@ -67,6 +67,7 @@ class GroupContactsActivity : SimpleActivity(), RemoveFromGroupListener, Refresh
group_contacts_list.beVisibleIf(groupContacts.isNotEmpty()) group_contacts_list.beVisibleIf(groupContacts.isNotEmpty())
Contact.sorting = config.sorting Contact.sorting = config.sorting
Contact.startWithSurname = config.startNameWithSurname
groupContacts.sort() groupContacts.sort()
updateContacts(groupContacts) updateContacts(groupContacts)
@ -90,7 +91,6 @@ class GroupContactsActivity : SimpleActivity(), RemoveFromGroupListener, Refresh
ON_CLICK_EDIT_CONTACT -> editContact(it as Contact) ON_CLICK_EDIT_CONTACT -> editContact(it as Contact)
} }
}.apply { }.apply {
setupDragListener(true)
addVerticalDividers(true) addVerticalDividers(true)
group_contacts_list.adapter = this group_contacts_list.adapter = this
} }
@ -110,9 +110,11 @@ class GroupContactsActivity : SimpleActivity(), RemoveFromGroupListener, Refresh
} }
override fun removeFromGroup(contacts: ArrayList<Contact>) { override fun removeFromGroup(contacts: ArrayList<Contact>) {
ContactsHelper(this).removeContactsFromGroup(contacts, group.id) Thread {
if (groupContacts.size == 0) { removeContactsFromGroup(contacts, group.id)
refreshContacts() if (groupContacts.size == 0) {
} refreshContacts()
}
}.start()
} }
} }

View File

@ -36,11 +36,12 @@ import kotlinx.android.synthetic.main.fragment_groups.*
import java.io.FileOutputStream import java.io.FileOutputStream
class MainActivity : SimpleActivity(), RefreshContactsListener { class MainActivity : SimpleActivity(), RefreshContactsListener {
private var isFirstResume = true
private var isSearchOpen = false private var isSearchOpen = false
private var searchMenuItem: MenuItem? = null private var searchMenuItem: MenuItem? = null
private var werePermissionsHandled = false
private var isFirstResume = true
private var isGettingContacts = false
private var storedUseEnglish = false
private var storedTextColor = 0 private var storedTextColor = 0
private var storedBackgroundColor = 0 private var storedBackgroundColor = 0
private var storedPrimaryColor = 0 private var storedPrimaryColor = 0
@ -58,19 +59,15 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
dbHelper dbHelper
handlePermission(PERMISSION_READ_CONTACTS) { handlePermission(PERMISSION_READ_CONTACTS) {
werePermissionsHandled = true
if (it) { if (it) {
handlePermission(PERMISSION_WRITE_CONTACTS) { handlePermission(PERMISSION_WRITE_CONTACTS) {
if (it) { storeLocalAccountData()
storeLocalAccountData() initFragments()
initFragments()
} else {
toast(R.string.no_contacts_permission)
finish()
}
} }
} else { } else {
toast(R.string.no_contacts_permission) storeLocalAccountData()
finish() initFragments()
} }
} }
storeStateVariables() storeStateVariables()
@ -79,13 +76,8 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if (storedUseEnglish != config.useEnglish) {
restartActivity()
return
}
if (storedShowPhoneNumbers != config.showPhoneNumbers) { if (storedShowPhoneNumbers != config.showPhoneNumbers) {
restartActivity() System.exit(0)
return return
} }
@ -126,20 +118,18 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
favorites_fragment?.startNameWithSurnameChanged(configStartNameWithSurname) favorites_fragment?.startNameWithSurnameChanged(configStartNameWithSurname)
} }
if (!isFirstResume) { if (werePermissionsHandled && !isFirstResume) {
if (viewpager.adapter == null) { if (viewpager.adapter == null) {
initFragments() initFragments()
} else {
refreshContacts(ALL_TABS_MASK)
} }
getAllFragments().forEach { getAllFragments().forEach {
it?.onActivityResume() it?.onActivityResume()
} }
refreshContacts(ALL_TABS_MASK)
}
if (hasPermission(PERMISSION_WRITE_CONTACTS)) {
isFirstResume = false
} }
isFirstResume = false
} }
override fun onPause() { override fun onPause() {
@ -179,7 +169,6 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
private fun storeStateVariables() { private fun storeStateVariables() {
config.apply { config.apply {
storedUseEnglish = useEnglish
storedTextColor = textColor storedTextColor = textColor
storedBackgroundColor = backgroundColor storedBackgroundColor = backgroundColor
storedPrimaryColor = primaryColor storedPrimaryColor = primaryColor
@ -308,6 +297,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
if (intent?.action == Intent.ACTION_VIEW && intent.data != null) { if (intent?.action == Intent.ACTION_VIEW && intent.data != null) {
tryImportContactsFromFile(intent.data) tryImportContactsFromFile(intent.data)
intent.data = null
} }
} }
@ -400,17 +390,23 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
} }
private fun launchAbout() { private fun launchAbout() {
val faqItems = arrayListOf(FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons)) val faqItems = arrayListOf(
FAQItem(R.string.faq_1_title, R.string.faq_1_text),
FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons)
)
startAboutActivity(R.string.app_name, LICENSE_MULTISELECT or LICENSE_JODA or LICENSE_GLIDE or LICENSE_GSON or LICENSE_STETHO, startAboutActivity(R.string.app_name, LICENSE_MULTISELECT or LICENSE_JODA or LICENSE_GLIDE or LICENSE_GSON or LICENSE_STETHO,
BuildConfig.VERSION_NAME, faqItems) BuildConfig.VERSION_NAME, faqItems)
} }
override fun refreshContacts(refreshTabsMask: Int) { override fun refreshContacts(refreshTabsMask: Int) {
if (isActivityDestroyed()) { if (isActivityDestroyed() || isGettingContacts) {
return return
} }
isGettingContacts = true
ContactsHelper(this).getContacts { ContactsHelper(this).getContacts {
isGettingContacts = false
if (isActivityDestroyed()) { if (isActivityDestroyed()) {
return@getContacts return@getContacts
} }
@ -443,6 +439,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
arrayListOf<Release>().apply { arrayListOf<Release>().apply {
add(Release(10, R.string.release_10)) add(Release(10, R.string.release_10))
add(Release(11, R.string.release_11)) add(Release(11, R.string.release_11))
add(Release(16, R.string.release_16))
checkWhatsNew(this, BuildConfig.VERSION_CODE) checkWhatsNew(this, BuildConfig.VERSION_CODE)
} }
} }

View File

@ -103,6 +103,7 @@ class SelectContactActivity : SimpleActivity() {
} }
Contact.sorting = config.sorting Contact.sorting = config.sorting
Contact.startWithSurname = config.startNameWithSurname
contacts.sort() contacts.sort()
runOnUiThread { runOnUiThread {

View File

@ -4,9 +4,9 @@ import android.os.Bundle
import com.simplemobiletools.commons.dialogs.RadioGroupDialog import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.updateTextColors import com.simplemobiletools.commons.extensions.updateTextColors
import com.simplemobiletools.commons.extensions.useEnglishToggled
import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.dialogs.ManageVisibleFieldsDialog
import com.simplemobiletools.contacts.extensions.config import com.simplemobiletools.contacts.extensions.config
import com.simplemobiletools.contacts.helpers.ON_CLICK_CALL_CONTACT import com.simplemobiletools.contacts.helpers.ON_CLICK_CALL_CONTACT
import com.simplemobiletools.contacts.helpers.ON_CLICK_EDIT_CONTACT import com.simplemobiletools.contacts.helpers.ON_CLICK_EDIT_CONTACT
@ -24,6 +24,7 @@ class SettingsActivity : SimpleActivity() {
super.onResume() super.onResume()
setupCustomizeColors() setupCustomizeColors()
setupManageShownContactFields()
setupUseEnglish() setupUseEnglish()
setupAvoidWhatsNew() setupAvoidWhatsNew()
setupShowInfoBubble() setupShowInfoBubble()
@ -40,13 +41,19 @@ class SettingsActivity : SimpleActivity() {
} }
} }
private fun setupManageShownContactFields() {
settings_manage_contact_fields_holder.setOnClickListener {
ManageVisibleFieldsDialog(this)
}
}
private fun setupUseEnglish() { private fun setupUseEnglish() {
settings_use_english_holder.beVisibleIf(config.wasUseEnglishToggled || Locale.getDefault().language != "en") settings_use_english_holder.beVisibleIf(config.wasUseEnglishToggled || Locale.getDefault().language != "en")
settings_use_english.isChecked = config.useEnglish settings_use_english.isChecked = config.useEnglish
settings_use_english_holder.setOnClickListener { settings_use_english_holder.setOnClickListener {
settings_use_english.toggle() settings_use_english.toggle()
config.useEnglish = settings_use_english.isChecked config.useEnglish = settings_use_english.isChecked
useEnglishToggled() System.exit(0)
} }
} }

View File

@ -12,25 +12,39 @@ 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.CONTACT_ID import com.simplemobiletools.contacts.helpers.*
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_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_group.view.* import kotlinx.android.synthetic.main.item_view_group.view.*
import kotlinx.android.synthetic.main.item_view_phone_number.view.* import kotlinx.android.synthetic.main.item_view_phone_number.view.*
import kotlinx.android.synthetic.main.item_website.view.*
class ViewContactActivity : ContactActivity() { class ViewContactActivity : ContactActivity() {
private var isViewIntent = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_contact) setContentView(R.layout.activity_view_contact)
showFields = config.showContactFields
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
tryInitContact() isViewIntent = intent.action == ContactsContract.QuickContact.ACTION_QUICK_CONTACT || intent.action == Intent.ACTION_VIEW
if (isViewIntent) {
handlePermission(PERMISSION_READ_CONTACTS) {
if (it) {
initContact()
} else {
toast(R.string.no_contacts_permission)
finish()
}
}
} else {
initContact()
}
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@ -48,22 +62,10 @@ class ViewContactActivity : ContactActivity() {
return true return true
} }
private fun tryInitContact() {
handlePermission(PERMISSION_READ_CONTACTS) {
if (it) {
initContact()
} else {
toast(R.string.no_contacts_permission)
finish()
}
}
}
private fun initContact() { private fun initContact() {
var wasLookupKeyUsed = false var wasLookupKeyUsed = false
var contactId = intent.getIntExtra(CONTACT_ID, 0) var contactId = intent.getIntExtra(CONTACT_ID, 0)
val action = intent.action if (contactId == 0 && isViewIntent) {
if (contactId == 0 && (action == ContactsContract.QuickContact.ACTION_QUICK_CONTACT || action == Intent.ACTION_VIEW)) {
val data = intent.data val data = intent.data
if (data != null) { if (data != null) {
val rawId = if (data.path.contains("lookup")) { val rawId = if (data.path.contains("lookup")) {
@ -117,11 +119,13 @@ class ViewContactActivity : ContactActivity() {
contact_start_call.applyColorFilter(textColor) contact_start_call.applyColorFilter(textColor)
contact_send_email.applyColorFilter(textColor) contact_send_email.applyColorFilter(textColor)
contact_name_image.applyColorFilter(textColor) contact_name_image.applyColorFilter(textColor)
contact_number_image.applyColorFilter(textColor) contact_numbers_image.applyColorFilter(textColor)
contact_email_image.applyColorFilter(textColor) contact_emails_image.applyColorFilter(textColor)
contact_event_image.applyColorFilter(textColor) contact_events_image.applyColorFilter(textColor)
contact_source_image.applyColorFilter(textColor) contact_source_image.applyColorFilter(textColor)
contact_notes_image.applyColorFilter(textColor) contact_notes_image.applyColorFilter(textColor)
contact_organization_image.applyColorFilter(textColor)
contact_websites_image.applyColorFilter(textColor)
contact_groups_image.applyColorFilter(textColor) contact_groups_image.applyColorFilter(textColor)
contact_send_sms.setOnClickListener { trySendSMS() } contact_send_sms.setOnClickListener { trySendSMS() }
@ -134,135 +138,223 @@ class ViewContactActivity : ContactActivity() {
private fun setupViewContact() { private fun setupViewContact() {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
contact!!.apply { setupFavorite()
contact_first_name.text = firstName setupNames()
contact_first_name.beVisibleIf(firstName.isNotEmpty()) setupPhoneNumbers()
setupEmails()
contact_middle_name.text = middleName setupAddresses()
contact_middle_name.beVisibleIf(middleName.isNotEmpty()) setupEvents()
setupNotes()
contact_surname.text = surname setupOrganization()
contact_surname.beVisibleIf(surname.isNotEmpty()) setupWebsites()
setupGroups()
if (firstName.isEmpty() && middleName.isEmpty() && surname.isEmpty()) { setupContactSource()
contact_name_image.beInvisible() }
(contact_photo.layoutParams as RelativeLayout.LayoutParams).bottomMargin = resources.getDimension(R.dimen.medium_margin).toInt()
}
contact_source.text = getPublicContactSource(source)
}
private fun setupFavorite() {
contact_toggle_favorite.apply { contact_toggle_favorite.apply {
beVisible() beVisible()
setImageDrawable(getStarDrawable(contact!!.starred == 1)) setImageDrawable(getStarDrawable(contact!!.starred == 1))
tag = contact!!.starred tag = contact!!.starred
applyColorFilter(config.textColor) applyColorFilter(config.textColor)
} }
}
setupPhoneNumbers() private fun setupNames() {
setupEmails() contact!!.apply {
setupAddresses() contact_prefix.text = prefix
setupEvents() contact_prefix.beVisibleIf(prefix.isNotEmpty() && showFields and SHOW_PREFIX_FIELD != 0)
setupNotes()
setupGroups() contact_first_name.text = firstName
contact_first_name.beVisibleIf(firstName.isNotEmpty() && showFields and SHOW_FIRST_NAME_FIELD != 0)
contact_middle_name.text = middleName
contact_middle_name.beVisibleIf(middleName.isNotEmpty() && showFields and SHOW_MIDDLE_NAME_FIELD != 0)
contact_surname.text = surname
contact_surname.beVisibleIf(surname.isNotEmpty() && showFields and SHOW_SURNAME_FIELD != 0)
contact_suffix.text = suffix
contact_suffix.beVisibleIf(suffix.isNotEmpty() && showFields and SHOW_SUFFIX_FIELD != 0)
if (contact_prefix.isGone() && contact_first_name.isGone() && contact_middle_name.isGone() && contact_surname.isGone() && contact_suffix.isGone()) {
contact_name_image.beInvisible()
(contact_photo.layoutParams as RelativeLayout.LayoutParams).bottomMargin = resources.getDimension(R.dimen.medium_margin).toInt()
}
}
} }
private fun setupPhoneNumbers() { private fun setupPhoneNumbers() {
contact_numbers_holder.removeAllViews() contact_numbers_holder.removeAllViews()
val phoneNumbers = contact!!.phoneNumbers val phoneNumbers = contact!!.phoneNumbers
phoneNumbers.forEach { if (phoneNumbers.isNotEmpty() && showFields and SHOW_PHONE_NUMBERS_FIELD != 0) {
layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false).apply { phoneNumbers.forEach {
val phoneNumber = it layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false).apply {
contact_numbers_holder.addView(this) val phoneNumber = it
contact_number.text = phoneNumber.value contact_numbers_holder.addView(this)
contact_number_type.setText(getPhoneNumberTextId(phoneNumber.type)) contact_number.text = phoneNumber.value
contact_number_type.setText(getPhoneNumberTextId(phoneNumber.type))
setOnClickListener { setOnClickListener {
startCallIntent(phoneNumber.value) startCallIntent(phoneNumber.value)
}
} }
} }
contact_numbers_image.beVisible()
contact_numbers_holder.beVisible()
} else {
contact_numbers_image.beGone()
contact_numbers_holder.beGone()
} }
contact_number_image.beVisibleIf(phoneNumbers.isNotEmpty())
contact_numbers_holder.beVisibleIf(phoneNumbers.isNotEmpty())
} }
private fun setupEmails() { private fun setupEmails() {
contact_emails_holder.removeAllViews() contact_emails_holder.removeAllViews()
val emails = contact!!.emails val emails = contact!!.emails
emails.forEach { if (emails.isNotEmpty() && showFields and SHOW_EMAILS_FIELD != 0) {
layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false).apply { emails.forEach {
val email = it layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false).apply {
contact_emails_holder.addView(this) val email = it
contact_email.text = email.value contact_emails_holder.addView(this)
contact_email_type.setText(getEmailTextId(email.type)) contact_email.text = email.value
contact_email_type.setText(getEmailTextId(email.type))
setOnClickListener { setOnClickListener {
sendEmailIntent(email.value) sendEmailIntent(email.value)
}
} }
} }
contact_emails_image.beVisible()
contact_emails_holder.beVisible()
} else {
contact_emails_image.beGone()
contact_emails_holder.beGone()
} }
contact_email_image.beVisibleIf(emails.isNotEmpty())
contact_emails_holder.beVisibleIf(emails.isNotEmpty())
} }
private fun setupAddresses() { private fun setupAddresses() {
contact_addresses_holder.removeAllViews() contact_addresses_holder.removeAllViews()
val addresses = contact!!.addresses val addresses = contact!!.addresses
addresses.forEach { if (addresses.isNotEmpty() && showFields and SHOW_ADDRESSES_FIELD != 0) {
layoutInflater.inflate(R.layout.item_view_address, contact_addresses_holder, false).apply { addresses.forEach {
val address = it layoutInflater.inflate(R.layout.item_view_address, contact_addresses_holder, false).apply {
contact_addresses_holder.addView(this) val address = it
contact_address.text = address.value contact_addresses_holder.addView(this)
contact_address_type.setText(getAddressTextId(address.type)) contact_address.text = address.value
contact_address_type.setText(getAddressTextId(address.type))
setOnClickListener { setOnClickListener {
sendAddressIntent(address.value) sendAddressIntent(address.value)
}
} }
} }
contact_addresses_image.beVisible()
contact_addresses_holder.beVisible()
} else {
contact_addresses_image.beGone()
contact_addresses_holder.beGone()
} }
contact_address_image.beVisibleIf(addresses.isNotEmpty())
contact_addresses_holder.beVisibleIf(addresses.isNotEmpty())
} }
private fun setupEvents() { private fun setupEvents() {
contact_events_holder.removeAllViews() contact_events_holder.removeAllViews()
val events = contact!!.events val events = contact!!.events
events.forEach { if (events.isNotEmpty() && showFields and SHOW_EVENTS_FIELD != 0) {
layoutInflater.inflate(R.layout.item_event, contact_events_holder, false).apply { events.forEach {
contact_events_holder.addView(this) layoutInflater.inflate(R.layout.item_event, contact_events_holder, false).apply {
contact_event.alpha = 1f contact_events_holder.addView(this)
getDateTime(it.value, contact_event) contact_event.alpha = 1f
contact_event_type.setText(getEventTextId(it.type)) getDateTime(it.value, contact_event)
contact_event_remove.beGone() contact_event_type.setText(getEventTextId(it.type))
contact_event_remove.beGone()
}
} }
contact_events_image.beVisible()
contact_events_holder.beVisible()
} else {
contact_events_image.beGone()
contact_events_holder.beGone()
} }
contact_event_image.beVisibleIf(events.isNotEmpty())
contact_events_holder.beVisibleIf(events.isNotEmpty())
} }
private fun setupNotes() { private fun setupNotes() {
val notes = contact!!.notes val notes = contact!!.notes
contact_notes.text = notes if (notes.isNotEmpty() && showFields and SHOW_NOTES_FIELD != 0) {
contact_notes_image.beVisibleIf(notes.isNotEmpty()) contact_notes.text = notes
contact_notes.beVisibleIf(notes.isNotEmpty()) contact_notes_image.beVisible()
contact_notes.beVisible()
} else {
contact_notes_image.beGone()
contact_notes.beGone()
}
}
private fun setupOrganization() {
val organization = contact!!.organization
if (!organization.isEmpty() && showFields and SHOW_ORGANIZATION_FIELD != 0) {
contact_organization_company.text = organization.company
contact_organization_job_position.text = organization.jobPosition
contact_organization_image.beGoneIf(organization.isEmpty())
contact_organization_company.beGoneIf(organization.company.isEmpty())
contact_organization_job_position.beGoneIf(organization.jobPosition.isEmpty())
} else {
contact_organization_image.beGone()
contact_organization_company.beGone()
contact_organization_job_position.beGone()
}
}
private fun setupWebsites() {
contact_websites_holder.removeAllViews()
val websites = contact!!.websites
if (websites.isNotEmpty() && showFields and SHOW_WEBSITES_FIELD != 0) {
websites.forEach {
val url = it
layoutInflater.inflate(R.layout.item_website, contact_websites_holder, false).apply {
contact_websites_holder.addView(this)
contact_website.text = url
setOnClickListener {
openWebsiteIntent(url)
}
}
}
contact_websites_image.beVisible()
contact_websites_holder.beVisible()
} else {
contact_websites_image.beGone()
contact_websites_holder.beGone()
}
} }
private fun setupGroups() { private fun setupGroups() {
contact_groups_holder.removeAllViews() contact_groups_holder.removeAllViews()
val groups = contact!!.groups val groups = contact!!.groups
groups.forEach { if (groups.isNotEmpty() && showFields and SHOW_GROUPS_FIELD != 0) {
layoutInflater.inflate(R.layout.item_view_group, contact_groups_holder, false).apply { groups.forEach {
val group = it layoutInflater.inflate(R.layout.item_view_group, contact_groups_holder, false).apply {
contact_groups_holder.addView(this) val group = it
contact_group.text = group.title contact_groups_holder.addView(this)
contact_group.text = group.title
}
} }
contact_groups_image.beVisible()
contact_groups_holder.beVisible()
} else {
contact_groups_image.beGone()
contact_groups_holder.beGone()
} }
}
contact_groups_image.beVisibleIf(groups.isNotEmpty()) private fun setupContactSource() {
contact_groups_holder.beVisibleIf(groups.isNotEmpty()) if (showFields and SHOW_CONTACT_SOURCE_FIELD != 0) {
contact_source.text = getPublicContactSource(contact!!.source)
contact_source_image.beVisible()
contact_source.beVisible()
} else {
contact_source_image.beGone()
contact_source.beGone()
}
} }
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)

View File

@ -47,6 +47,7 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
private var bigPadding = activity.resources.getDimension(R.dimen.normal_margin).toInt() private var bigPadding = activity.resources.getDimension(R.dimen.normal_margin).toInt()
init { init {
setupDragListener(true)
initDrawables() initDrawables()
showContactThumbnails = config.showContactThumbnails showContactThumbnails = config.showContactThumbnails
showPhoneNumbers = config.showPhoneNumbers showPhoneNumbers = config.showPhoneNumbers
@ -220,10 +221,8 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
contactsIDs.add(contactItems[it].id) contactsIDs.add(contactItems[it].id)
} }
ContactsHelper(activity).getContacts { val filtered = contactItems.filter { contactsIDs.contains(it.id) } as ArrayList<Contact>
val filtered = it.filter { contactsIDs.contains(it.id) } as ArrayList<Contact> activity.shareContacts(filtered)
activity.shareContacts(filtered)
}
} }
override fun onViewRecycled(holder: ViewHolder) { override fun onViewRecycled(holder: ViewHolder) {
@ -235,7 +234,7 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
private fun setupView(view: View, contact: Contact) { private fun setupView(view: View, contact: Contact) {
view.apply { view.apply {
contact_name.text = contact.getFullName(startNameWithSurname) contact_name.text = contact.getFullName()
contact_name.setTextColor(textColor) contact_name.setTextColor(textColor)
contact_name.setPadding(if (showContactThumbnails) smallPadding else bigPadding, smallPadding, smallPadding, 0) contact_name.setPadding(if (showContactThumbnails) smallPadding else bigPadding, smallPadding, smallPadding, 0)

View File

@ -24,11 +24,14 @@ import java.util.*
class GroupsAdapter(activity: SimpleActivity, var groups: ArrayList<Group>, val refreshListener: RefreshContactsListener?, recyclerView: MyRecyclerView, class GroupsAdapter(activity: SimpleActivity, var groups: ArrayList<Group>, val refreshListener: RefreshContactsListener?, recyclerView: MyRecyclerView,
fastScroller: FastScroller, itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) { fastScroller: FastScroller, itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
private var config = activity.config
private var smallPadding = activity.resources.getDimension(R.dimen.small_margin).toInt() private var smallPadding = activity.resources.getDimension(R.dimen.small_margin).toInt()
private var bigPadding = activity.resources.getDimension(R.dimen.normal_margin).toInt() private var bigPadding = activity.resources.getDimension(R.dimen.normal_margin).toInt()
var showContactThumbnails = config.showContactThumbnails var showContactThumbnails = activity.config.showContactThumbnails
init {
setupDragListener(true)
}
override fun getActionMenuId() = R.menu.cab_groups override fun getActionMenuId() = R.menu.cab_groups

View File

@ -30,7 +30,6 @@ class SelectContactsAdapter(val activity: SimpleActivity, val contacts: List<Con
private val config = activity.config private val config = activity.config
private val textColor = config.textColor private val textColor = config.textColor
private val contactDrawable = activity.resources.getColoredDrawableWithColor(R.drawable.ic_person, textColor) private val contactDrawable = activity.resources.getColoredDrawableWithColor(R.drawable.ic_person, textColor)
private val startNameWithSurname = config.startNameWithSurname
private val showContactThumbnails = config.showContactThumbnails private val showContactThumbnails = config.showContactThumbnails
private val itemLayout = if (config.showPhoneNumbers) R.layout.item_add_favorite_with_number else R.layout.item_add_favorite_without_number private val itemLayout = if (config.showPhoneNumbers) R.layout.item_add_favorite_with_number else R.layout.item_add_favorite_without_number
@ -80,7 +79,7 @@ class SelectContactsAdapter(val activity: SimpleActivity, val contacts: List<Con
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val eventType = contacts[position] val eventType = contacts[position]
itemViews.put(position, holder.bindView(eventType, startNameWithSurname, contactDrawable, config, showContactThumbnails, smallPadding, bigPadding)) itemViews.put(position, holder.bindView(eventType, contactDrawable, config, showContactThumbnails, smallPadding, bigPadding))
toggleItemSelection(selectedPositions.contains(position), position) toggleItemSelection(selectedPositions.contains(position), position)
} }
@ -88,14 +87,14 @@ class SelectContactsAdapter(val activity: SimpleActivity, val contacts: List<Con
class ViewHolder(view: View, private val adapterListener: MyAdapterListener, val activity: SimpleActivity, private val showCheckbox: Boolean, class ViewHolder(view: View, private val adapterListener: MyAdapterListener, val activity: SimpleActivity, private val showCheckbox: Boolean,
private val itemClick: ((Contact) -> Unit)?) : RecyclerView.ViewHolder(view) { private val itemClick: ((Contact) -> Unit)?) : RecyclerView.ViewHolder(view) {
fun bindView(contact: Contact, startNameWithSurname: Boolean, contactDrawable: Drawable, config: Config, showContactThumbnails: Boolean, fun bindView(contact: Contact, contactDrawable: Drawable, config: Config, showContactThumbnails: Boolean,
smallPadding: Int, bigPadding: Int): View { smallPadding: Int, bigPadding: Int): View {
itemView.apply { itemView.apply {
contact_checkbox.beVisibleIf(showCheckbox) contact_checkbox.beVisibleIf(showCheckbox)
contact_checkbox.setColors(config.textColor, context.getAdjustedPrimaryColor(), config.backgroundColor) contact_checkbox.setColors(config.textColor, context.getAdjustedPrimaryColor(), config.backgroundColor)
val textColor = config.textColor val textColor = config.textColor
contact_name.text = contact.getFullName(startNameWithSurname) contact_name.text = contact.getFullName()
contact_name.setTextColor(textColor) contact_name.setTextColor(textColor)
contact_name.setPadding(if (showContactThumbnails) smallPadding else bigPadding, smallPadding, smallPadding, 0) contact_name.setPadding(if (showContactThumbnails) smallPadding else bigPadding, smallPadding, smallPadding, 0)

View File

@ -0,0 +1,56 @@
package com.simplemobiletools.contacts.dialogs
import android.support.v7.app.AlertDialog
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.views.MyAppCompatCheckbox
import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.extensions.config
import com.simplemobiletools.contacts.helpers.*
class ManageVisibleFieldsDialog(val activity: BaseSimpleActivity) {
private var view = activity.layoutInflater.inflate(R.layout.dialog_manage_visible_fields, null)
private val fields = LinkedHashMap<Int, Int>()
init {
fields.apply {
put(SHOW_PREFIX_FIELD, R.id.manage_visible_fields_prefix)
put(SHOW_FIRST_NAME_FIELD, R.id.manage_visible_fields_first_name)
put(SHOW_MIDDLE_NAME_FIELD, R.id.manage_visible_fields_middle_name)
put(SHOW_SURNAME_FIELD, R.id.manage_visible_fields_surname)
put(SHOW_SUFFIX_FIELD, R.id.manage_visible_fields_suffix)
put(SHOW_PHONE_NUMBERS_FIELD, R.id.manage_visible_fields_phone_numbers)
put(SHOW_EMAILS_FIELD, R.id.manage_visible_fields_emails)
put(SHOW_ADDRESSES_FIELD, R.id.manage_visible_fields_addresses)
put(SHOW_EVENTS_FIELD, R.id.manage_visible_fields_events)
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_GROUPS_FIELD, R.id.manage_visible_fields_groups)
put(SHOW_CONTACT_SOURCE_FIELD, R.id.manage_visible_fields_contact_source)
}
val showContactFields = activity.config.showContactFields
for ((key, value) in fields) {
view.findViewById<MyAppCompatCheckbox>(value).isChecked = showContactFields and key != 0
}
AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, { dialog, which -> dialogConfirmed() })
.setNegativeButton(R.string.cancel, null)
.create().apply {
activity.setupDialogStuff(view, this)
}
}
private fun dialogConfirmed() {
var result = 0
for ((key, value) in fields) {
if (view.findViewById<MyAppCompatCheckbox>(value).isChecked) {
result += key
}
}
activity.config.showContactFields = result
}
}

View File

@ -29,6 +29,7 @@ class SelectContactsDialog(val activity: SimpleActivity, initialContacts: ArrayL
} }
Contact.sorting = activity.config.sorting Contact.sorting = activity.config.sorting
Contact.startWithSurname = activity.config.startNameWithSurname
allContacts.sort() allContacts.sort()
activity.runOnUiThread { activity.runOnUiThread {

View File

@ -20,14 +20,13 @@ import java.io.File
fun SimpleActivity.startCallIntent(recipient: String) { fun SimpleActivity.startCallIntent(recipient: String) {
handlePermission(PERMISSION_CALL_PHONE) { handlePermission(PERMISSION_CALL_PHONE) {
if (it) { val action = if (it) Intent.ACTION_CALL else Intent.ACTION_DIAL
Intent(Intent.ACTION_CALL).apply { Intent(action).apply {
data = Uri.fromParts("tel", recipient, null) data = Uri.fromParts("tel", recipient, null)
if (resolveActivity(packageManager) != null) { if (resolveActivity(packageManager) != null) {
startActivity(this) startActivity(this)
} else { } else {
toast(R.string.no_app_found) toast(R.string.no_app_found)
}
} }
} }
} }
@ -127,7 +126,7 @@ fun BaseSimpleActivity.addContactsToGroup(contacts: ArrayList<Contact>, groupId:
fun BaseSimpleActivity.removeContactsFromGroup(contacts: ArrayList<Contact>, groupId: Long) { fun BaseSimpleActivity.removeContactsFromGroup(contacts: ArrayList<Contact>, groupId: Long) {
val publicContacts = contacts.filter { it.source != SMT_PRIVATE } val publicContacts = contacts.filter { it.source != SMT_PRIVATE }
val privateContacts = contacts.filter { it.source == SMT_PRIVATE } val privateContacts = contacts.filter { it.source == SMT_PRIVATE }
if (publicContacts.isNotEmpty()) { if (publicContacts.isNotEmpty() && hasContactPermissions()) {
ContactsHelper(this).removeContactsFromGroup(contacts, groupId) ContactsHelper(this).removeContactsFromGroup(contacts, groupId)
} }

View File

@ -9,7 +9,10 @@ import android.os.Build
import android.provider.ContactsContract import android.provider.ContactsContract
import android.support.v4.content.FileProvider import android.support.v4.content.FileProvider
import com.simplemobiletools.commons.extensions.getIntValue import com.simplemobiletools.commons.extensions.getIntValue
import com.simplemobiletools.commons.extensions.hasPermission
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CONTACTS
import com.simplemobiletools.commons.helpers.isLollipopPlus import com.simplemobiletools.commons.helpers.isLollipopPlus
import com.simplemobiletools.contacts.BuildConfig import com.simplemobiletools.contacts.BuildConfig
import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.R
@ -65,11 +68,23 @@ fun Context.sendAddressIntent(address: String) {
val location = Uri.encode(address) val location = Uri.encode(address)
val uri = Uri.parse("geo:0,0?q=$location") val uri = Uri.parse("geo:0,0?q=$location")
val intent = Intent(Intent.ACTION_VIEW, uri) Intent(Intent.ACTION_VIEW, uri).apply {
if (intent.resolveActivity(packageManager) != null) { if (resolveActivity(packageManager) != null) {
startActivity(intent) startActivity(this)
} else { } else {
toast(R.string.no_app_found) toast(R.string.no_app_found)
}
}
}
fun Context.openWebsiteIntent(url: String) {
Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(url)
if (resolveActivity(packageManager) != null) {
startActivity(this)
} else {
toast(R.string.no_app_found)
}
} }
} }
@ -150,8 +165,11 @@ fun Context.getPhotoThumbnailSize(): Int {
if (cursor?.moveToFirst() == true) { if (cursor?.moveToFirst() == true) {
return cursor.getIntValue(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM) return cursor.getIntValue(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM)
} }
} catch (ignored: Exception) {
} finally { } finally {
cursor?.close() cursor?.close()
} }
return 0 return 0
} }
fun Context.hasContactPermissions() = hasPermission(PERMISSION_READ_CONTACTS) && hasPermission(PERMISSION_WRITE_CONTACTS)

View File

@ -92,6 +92,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
} }
Contact.sorting = config.sorting Contact.sorting = config.sorting
Contact.startWithSurname = config.startNameWithSurname
contacts.sort() contacts.sort()
allContacts = contacts allContacts = contacts
@ -149,7 +150,6 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
activity!!.startActivity(this) activity!!.startActivity(this)
} }
}.apply { }.apply {
setupDragListener(true)
addVerticalDividers(true) addVerticalDividers(true)
fragment_list.adapter = this fragment_list.adapter = this
} }
@ -190,7 +190,6 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
ON_CLICK_EDIT_CONTACT -> context!!.editContact(it as Contact) ON_CLICK_EDIT_CONTACT -> context!!.editContact(it as Contact)
} }
}.apply { }.apply {
setupDragListener(true)
addVerticalDividers(true) addVerticalDividers(true)
fragment_list.adapter = this fragment_list.adapter = this
} }
@ -235,16 +234,20 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
fun onSearchQueryChanged(text: String) { fun onSearchQueryChanged(text: String) {
(fragment_list.adapter as? ContactsAdapter)?.apply { (fragment_list.adapter as? ContactsAdapter)?.apply {
val filtered = contactsIgnoringSearch.filter { val filtered = contactsIgnoringSearch.filter {
it.getFullName(startNameWithSurname).contains(text, true) || it.getFullName().contains(text, true) ||
it.phoneNumbers.any { it.value.contains(text, true) } || it.phoneNumbers.any { it.value.contains(text, true) } ||
it.emails.any { it.value.contains(text, true) } || it.emails.any { it.value.contains(text, true) } ||
it.addresses.any { it.value.contains(text, true) } || it.addresses.any { it.value.contains(text, true) } ||
it.notes.contains(text, true) it.notes.contains(text, true) ||
it.organization.company.contains(text, true) ||
it.organization.jobPosition.contains(text, true) ||
it.websites.any { it.contains(text, true) }
} as ArrayList } as ArrayList
Contact.sorting = config.sorting Contact.sorting = config.sorting
Contact.startWithSurname = config.startNameWithSurname
filtered.sort() filtered.sort()
filtered.sortBy { !it.getFullName(startNameWithSurname).startsWith(text, true) } filtered.sortBy { !it.getFullName().startsWith(text, true) }
if (filtered.isEmpty() && this@MyViewPagerFragment is FavoritesFragment) { if (filtered.isEmpty() && this@MyViewPagerFragment is FavoritesFragment) {
fragment_placeholder.text = activity.getString(R.string.no_items_found) fragment_placeholder.text = activity.getString(R.string.no_items_found)

View File

@ -41,4 +41,9 @@ class Config(context: Context) : BaseConfig(context) {
var onContactClick: Int var onContactClick: Int
get() = prefs.getInt(ON_CONTACT_CLICK, ON_CLICK_VIEW_CONTACT) get() = prefs.getInt(ON_CONTACT_CLICK, ON_CLICK_VIEW_CONTACT)
set(onContactClick) = prefs.edit().putInt(ON_CONTACT_CLICK, onContactClick).apply() set(onContactClick) = prefs.edit().putInt(ON_CONTACT_CLICK, onContactClick).apply()
var showContactFields: Int
get() = prefs.getInt(SHOW_CONTACT_FIELDS, SHOW_FIRST_NAME_FIELD or SHOW_SURNAME_FIELD or SHOW_PHONE_NUMBERS_FIELD or SHOW_EMAILS_FIELD or
SHOW_ADDRESSES_FIELD or SHOW_EVENTS_FIELD or SHOW_NOTES_FIELD or SHOW_GROUPS_FIELD or SHOW_CONTACT_SOURCE_FIELD)
set(showContactFields) = prefs.edit().putInt(SHOW_CONTACT_FIELDS, showContactFields).apply()
} }

View File

@ -9,6 +9,7 @@ const val LAST_USED_CONTACT_SOURCE = "last_used_contact_source"
const val LOCAL_ACCOUNT_NAME = "local_account_name" const val LOCAL_ACCOUNT_NAME = "local_account_name"
const val LOCAL_ACCOUNT_TYPE = "local_account_type" 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 SHOW_CONTACT_FIELDS = "show_contact_fields"
const val CONTACT_ID = "contact_id" const val CONTACT_ID = "contact_id"
const val SMT_PRIVATE = "smt_private" // used at the contact source of local contacts hidden from other apps const val SMT_PRIVATE = "smt_private" // used at the contact source of local contacts hidden from other apps
@ -43,6 +44,8 @@ const val PHOTO = "PHOTO"
const val EMAIL = "EMAIL" const val EMAIL = "EMAIL"
const val ADR = "ADR" const val ADR = "ADR"
const val NOTE = "NOTE:" const val NOTE = "NOTE:"
const val ORG = "ORG:"
const val TITLE = "TITLE:"
const val ENCODING = "ENCODING" const val ENCODING = "ENCODING"
const val BASE64 = "BASE64" const val BASE64 = "BASE64"
const val JPEG = "JPEG" const val JPEG = "JPEG"
@ -64,3 +67,19 @@ const val VOICE = "VOICE"
const val ON_CLICK_CALL_CONTACT = 1 const val ON_CLICK_CALL_CONTACT = 1
const val ON_CLICK_VIEW_CONTACT = 2 const val ON_CLICK_VIEW_CONTACT = 2
const val ON_CLICK_EDIT_CONTACT = 3 const val ON_CLICK_EDIT_CONTACT = 3
// visible fields filtering
const val SHOW_PREFIX_FIELD = 1
const val SHOW_FIRST_NAME_FIELD = 2
const val SHOW_MIDDLE_NAME_FIELD = 4
const val SHOW_SURNAME_FIELD = 8
const val SHOW_SUFFIX_FIELD = 16
const val SHOW_PHONE_NUMBERS_FIELD = 32
const val SHOW_EMAILS_FIELD = 64
const val SHOW_ADDRESSES_FIELD = 128
const val SHOW_EVENTS_FIELD = 256
const val SHOW_NOTES_FIELD = 512
const val SHOW_ORGANIZATION_FIELD = 1024
const val SHOW_GROUPS_FIELD = 2048
const val SHOW_CONTACT_SOURCE_FIELD = 4096
const val SHOW_WEBSITES_FIELD = 8192

View File

@ -20,87 +20,15 @@ import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME
import com.simplemobiletools.commons.helpers.SORT_BY_SURNAME 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.*
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.*
class ContactsHelper(val activity: BaseSimpleActivity) { class ContactsHelper(val activity: BaseSimpleActivity) {
private val BATCH_SIZE = 100
fun getContacts(callback: (ArrayList<Contact>) -> Unit) { fun getContacts(callback: (ArrayList<Contact>) -> Unit) {
val contacts = SparseArray<Contact>()
Thread { Thread {
val uri = ContactsContract.Data.CONTENT_URI val contacts = SparseArray<Contact>()
val projection = getContactProjection() getDeviceContacts(contacts)
val selection = "${ContactsContract.Data.MIMETYPE} = ?"
val selectionArgs = arrayOf(CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
val sortOrder = getSortString()
var cursor: Cursor? = null
try {
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
if (cursor?.moveToFirst() == true) {
do {
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
val firstName = cursor.getStringValue(CommonDataKinds.StructuredName.GIVEN_NAME) ?: ""
val middleName = cursor.getStringValue(CommonDataKinds.StructuredName.MIDDLE_NAME) ?: ""
val surname = cursor.getStringValue(CommonDataKinds.StructuredName.FAMILY_NAME) ?: ""
val photoUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_URI) ?: ""
val number = ArrayList<PhoneNumber>() // proper value is obtained below
val emails = ArrayList<Email>()
val addresses = ArrayList<Address>()
val events = ArrayList<Event>()
val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: ""
val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED)
val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
val notes = ""
val groups = ArrayList<Group>()
val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName,
starred, contactId, thumbnailUri, null, notes, groups)
contacts.put(id, contact)
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity.showErrorToast(e)
} finally {
cursor?.close()
}
val phoneNumbers = getPhoneNumbers()
var size = phoneNumbers.size()
for (i in 0 until size) {
val key = phoneNumbers.keyAt(i)
contacts[key]?.phoneNumbers = phoneNumbers.valueAt(i)
}
val emails = getEmails()
size = emails.size()
for (i in 0 until size) {
val key = emails.keyAt(i)
contacts[key]?.emails = emails.valueAt(i)
}
val addresses = getAddresses()
size = addresses.size()
for (i in 0 until size) {
val key = addresses.keyAt(i)
contacts[key]?.addresses = addresses.valueAt(i)
}
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(activity).forEach { activity.dbHelper.getContacts(activity).forEach {
contacts.put(it.id, it) contacts.put(it.id, it)
@ -113,7 +41,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
// groups are obtained with contactID, not rawID, so assign them to proper contacts like this // groups are obtained with contactID, not rawID, so assign them to proper contacts like this
val groups = getContactGroups(getStoredGroups()) val groups = getContactGroups(getStoredGroups())
size = groups.size() val size = groups.size()
for (i in 0 until size) { for (i in 0 until size) {
val key = groups.keyAt(i) val key = groups.keyAt(i)
resultContacts.firstOrNull { it.contactId == key }?.groups = groups.valueAt(i) resultContacts.firstOrNull { it.contactId == key }?.groups = groups.valueAt(i)
@ -125,6 +53,102 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
}.start() }.start()
} }
private fun getDeviceContacts(contacts: SparseArray<Contact>) {
if (!activity.hasContactPermissions()) {
return
}
val uri = ContactsContract.Data.CONTENT_URI
val projection = getContactProjection()
val selection = "${ContactsContract.Data.MIMETYPE} = ?"
val selectionArgs = arrayOf(CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
val sortOrder = getSortString()
var cursor: Cursor? = null
try {
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
if (cursor?.moveToFirst() == true) {
do {
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
val prefix = cursor.getStringValue(CommonDataKinds.StructuredName.PREFIX) ?: ""
val firstName = cursor.getStringValue(CommonDataKinds.StructuredName.GIVEN_NAME) ?: ""
val middleName = cursor.getStringValue(CommonDataKinds.StructuredName.MIDDLE_NAME) ?: ""
val surname = cursor.getStringValue(CommonDataKinds.StructuredName.FAMILY_NAME) ?: ""
val suffix = cursor.getStringValue(CommonDataKinds.StructuredName.SUFFIX) ?: ""
val photoUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_URI) ?: ""
val number = ArrayList<PhoneNumber>() // proper value is obtained below
val emails = ArrayList<Email>()
val addresses = ArrayList<Address>()
val events = ArrayList<Event>()
val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: ""
val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED)
val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
val notes = ""
val groups = ArrayList<Group>()
val organization = Organization("", "")
val websites = ArrayList<String>()
val contact = Contact(id, prefix, firstName, middleName, surname, suffix, photoUri, number, emails, addresses, events,
accountName, starred, contactId, thumbnailUri, null, notes, groups, organization, websites)
contacts.put(id, contact)
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity.showErrorToast(e)
} finally {
cursor?.close()
}
val phoneNumbers = getPhoneNumbers()
var size = phoneNumbers.size()
for (i in 0 until size) {
val key = phoneNumbers.keyAt(i)
contacts[key]?.phoneNumbers = phoneNumbers.valueAt(i)
}
val emails = getEmails()
size = emails.size()
for (i in 0 until size) {
val key = emails.keyAt(i)
contacts[key]?.emails = emails.valueAt(i)
}
val addresses = getAddresses()
size = addresses.size()
for (i in 0 until size) {
val key = addresses.keyAt(i)
contacts[key]?.addresses = addresses.valueAt(i)
}
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)
}
val organizations = getOrganizations()
size = organizations.size()
for (i in 0 until size) {
val key = organizations.keyAt(i)
contacts[key]?.organization = organizations.valueAt(i)
}
val websites = getWebsites()
size = websites.size()
for (i in 0 until size) {
val key = websites.keyAt(i)
contacts[key]?.websites = websites.valueAt(i)
}
}
private fun getPhoneNumbers(contactId: Int? = null): SparseArray<ArrayList<PhoneNumber>> { private fun getPhoneNumbers(contactId: Int? = null): SparseArray<ArrayList<PhoneNumber>> {
val phoneNumbers = SparseArray<ArrayList<PhoneNumber>>() val phoneNumbers = SparseArray<ArrayList<PhoneNumber>>()
val uri = CommonDataKinds.Phone.CONTENT_URI val uri = CommonDataKinds.Phone.CONTENT_URI
@ -218,7 +242,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
if (cursor?.moveToFirst() == true) { if (cursor?.moveToFirst() == true) {
do { do {
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID) val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
val address = cursor.getStringValue(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS) val address = cursor.getStringValue(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS) ?: ""
val type = cursor.getIntValue(CommonDataKinds.StructuredPostal.TYPE) val type = cursor.getIntValue(CommonDataKinds.StructuredPostal.TYPE)
if (addresses[id] == null) { if (addresses[id] == null) {
@ -315,8 +339,90 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
return notes return notes
} }
private fun getOrganizations(contactId: Int? = null): SparseArray<Organization> {
val organizations = SparseArray<Organization>()
val uri = ContactsContract.Data.CONTENT_URI
val projection = arrayOf(
ContactsContract.Data.RAW_CONTACT_ID,
CommonDataKinds.Organization.COMPANY,
CommonDataKinds.Organization.TITLE
)
var selection = "${ContactsContract.Data.MIMETYPE} = ?"
var selectionArgs = arrayOf(CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
if (contactId != null) {
selection += " AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
selectionArgs = arrayOf(CommonDataKinds.Organization.CONTENT_ITEM_TYPE, contactId.toString())
}
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 company = cursor.getStringValue(CommonDataKinds.Organization.COMPANY) ?: continue
val title = cursor.getStringValue(CommonDataKinds.Organization.TITLE) ?: continue
val organization = Organization(company, title)
organizations.put(id, organization)
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity.showErrorToast(e)
} finally {
cursor?.close()
}
return organizations
}
private fun getWebsites(contactId: Int? = null): SparseArray<ArrayList<String>> {
val websites = SparseArray<ArrayList<String>>()
val uri = ContactsContract.Data.CONTENT_URI
val projection = arrayOf(
ContactsContract.Data.RAW_CONTACT_ID,
CommonDataKinds.Website.URL
)
var selection = "${ContactsContract.Data.MIMETYPE} = ?"
var selectionArgs = arrayOf(CommonDataKinds.Website.CONTENT_ITEM_TYPE)
if (contactId != null) {
selection += " AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
selectionArgs = arrayOf(CommonDataKinds.Website.CONTENT_ITEM_TYPE, contactId.toString())
}
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 url = cursor.getStringValue(CommonDataKinds.Website.URL) ?: continue
if (websites[id] == null) {
websites.put(id, ArrayList())
}
websites[id]!!.add(url)
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity.showErrorToast(e)
} finally {
cursor?.close()
}
return websites
}
private fun getContactGroups(storedGroups: ArrayList<Group>, contactId: Int? = null): SparseArray<ArrayList<Group>> { private fun getContactGroups(storedGroups: ArrayList<Group>, contactId: Int? = null): SparseArray<ArrayList<Group>> {
val groups = SparseArray<ArrayList<Group>>() val groups = SparseArray<ArrayList<Group>>()
if (!activity.hasContactPermissions()) {
return groups
}
val uri = ContactsContract.Data.CONTENT_URI val uri = ContactsContract.Data.CONTENT_URI
val projection = arrayOf( val projection = arrayOf(
ContactsContract.Data.CONTACT_ID, ContactsContract.Data.CONTACT_ID,
@ -357,7 +463,17 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
} }
fun getStoredGroups(): ArrayList<Group> { fun getStoredGroups(): ArrayList<Group> {
val groups = getDeviceStoredGroups()
groups.addAll(activity.dbHelper.getGroups())
return groups
}
fun getDeviceStoredGroups(): ArrayList<Group> {
val groups = ArrayList<Group>() val groups = ArrayList<Group>()
if (!activity.hasContactPermissions()) {
return groups
}
val uri = ContactsContract.Groups.CONTENT_URI val uri = ContactsContract.Groups.CONTENT_URI
val projection = arrayOf( val projection = arrayOf(
ContactsContract.Groups._ID, ContactsContract.Groups._ID,
@ -374,7 +490,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
if (cursor?.moveToFirst() == true) { if (cursor?.moveToFirst() == true) {
do { do {
val id = cursor.getLongValue(ContactsContract.Groups._ID) val id = cursor.getLongValue(ContactsContract.Groups._ID)
val title = cursor.getStringValue(ContactsContract.Groups.TITLE) val title = cursor.getStringValue(ContactsContract.Groups.TITLE) ?: continue
val systemId = cursor.getStringValue(ContactsContract.Groups.SYSTEM_ID) val systemId = cursor.getStringValue(ContactsContract.Groups.SYSTEM_ID)
if (groups.map { it.title }.contains(title) && systemId != null) { if (groups.map { it.title }.contains(title) && systemId != null) {
@ -389,8 +505,6 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
} finally { } finally {
cursor?.close() cursor?.close()
} }
groups.addAll(activity.dbHelper.getGroups())
return groups return groups
} }
@ -477,9 +591,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
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) {
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID) val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
val prefix = cursor.getStringValue(CommonDataKinds.StructuredName.PREFIX) ?: ""
val firstName = cursor.getStringValue(CommonDataKinds.StructuredName.GIVEN_NAME) ?: "" val firstName = cursor.getStringValue(CommonDataKinds.StructuredName.GIVEN_NAME) ?: ""
val middleName = cursor.getStringValue(CommonDataKinds.StructuredName.MIDDLE_NAME) ?: "" val middleName = cursor.getStringValue(CommonDataKinds.StructuredName.MIDDLE_NAME) ?: ""
val surname = cursor.getStringValue(CommonDataKinds.StructuredName.FAMILY_NAME) ?: "" val surname = cursor.getStringValue(CommonDataKinds.StructuredName.FAMILY_NAME) ?: ""
val suffix = cursor.getStringValue(CommonDataKinds.StructuredName.SUFFIX) ?: ""
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()
@ -491,8 +607,10 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
val groups = getContactGroups(storedGroups, contactId)[contactId] ?: ArrayList() val groups = getContactGroups(storedGroups, contactId)[contactId] ?: ArrayList()
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, addresses, events, accountName, starred, contactId, val organization = getOrganizations(id)[id] ?: Organization("", "")
thumbnailUri, null, notes, groups) val websites = getWebsites(id)[id] ?: ArrayList()
return Contact(id, prefix, firstName, middleName, surname, suffix, photoUri, number, emails, addresses, events, accountName,
starred, contactId, thumbnailUri, null, notes, groups, organization, websites)
} }
} finally { } finally {
cursor?.close() cursor?.close()
@ -502,37 +620,44 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
} }
fun getContactSources(callback: (ArrayList<ContactSource>) -> Unit) { fun getContactSources(callback: (ArrayList<ContactSource>) -> Unit) {
val sources = LinkedHashSet<ContactSource>()
Thread { Thread {
val uri = ContactsContract.RawContacts.CONTENT_URI val sources = LinkedHashSet<ContactSource>()
val projection = arrayOf(ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE) getDeviceContactSources(sources)
var cursor: Cursor? = null
try {
cursor = activity.contentResolver.query(uri, projection, null, null, null)
if (cursor?.moveToFirst() == true) {
do {
val name = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: continue
val type = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_TYPE) ?: continue
val contactSource = ContactSource(name, type)
sources.add(contactSource)
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity.showErrorToast(e)
} finally {
cursor?.close()
}
if (sources.isEmpty() && activity.config.localAccountName.isEmpty() && activity.config.localAccountType.isEmpty()) {
sources.add(ContactSource("", ""))
}
sources.add(ContactSource(activity.getString(R.string.phone_storage_hidden), SMT_PRIVATE)) sources.add(ContactSource(activity.getString(R.string.phone_storage_hidden), SMT_PRIVATE))
callback(ArrayList(sources)) callback(ArrayList(sources))
}.start() }.start()
} }
private fun getDeviceContactSources(sources: LinkedHashSet<ContactSource>) {
if (!activity.hasContactPermissions()) {
return
}
val uri = ContactsContract.RawContacts.CONTENT_URI
val projection = arrayOf(ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE)
var cursor: Cursor? = null
try {
cursor = activity.contentResolver.query(uri, projection, null, null, null)
if (cursor?.moveToFirst() == true) {
do {
val name = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: continue
val type = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_TYPE) ?: continue
val contactSource = ContactSource(name, type)
sources.add(contactSource)
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity.showErrorToast(e)
} finally {
cursor?.close()
}
if (sources.isEmpty() && activity.config.localAccountName.isEmpty() && activity.config.localAccountType.isEmpty()) {
sources.add(ContactSource("", ""))
}
}
private fun getContactSourceType(accountName: String): String { private fun getContactSourceType(accountName: String): String {
if (accountName.isEmpty()) { if (accountName.isEmpty()) {
return "" return ""
@ -558,9 +683,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
private fun getContactProjection() = arrayOf( private fun getContactProjection() = arrayOf(
ContactsContract.Data.CONTACT_ID, ContactsContract.Data.CONTACT_ID,
ContactsContract.Data.RAW_CONTACT_ID, ContactsContract.Data.RAW_CONTACT_ID,
CommonDataKinds.StructuredName.PREFIX,
CommonDataKinds.StructuredName.GIVEN_NAME, CommonDataKinds.StructuredName.GIVEN_NAME,
CommonDataKinds.StructuredName.MIDDLE_NAME, CommonDataKinds.StructuredName.MIDDLE_NAME,
CommonDataKinds.StructuredName.FAMILY_NAME, CommonDataKinds.StructuredName.FAMILY_NAME,
CommonDataKinds.StructuredName.SUFFIX,
CommonDataKinds.StructuredName.PHOTO_URI, CommonDataKinds.StructuredName.PHOTO_URI,
CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI, CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI,
CommonDataKinds.StructuredName.STARRED, CommonDataKinds.StructuredName.STARRED,
@ -613,9 +740,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?" val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?"
val selectionArgs = arrayOf(contact.id.toString(), CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) val selectionArgs = arrayOf(contact.id.toString(), CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
withSelection(selection, selectionArgs) withSelection(selection, selectionArgs)
withValue(CommonDataKinds.StructuredName.PREFIX, contact.prefix)
withValue(CommonDataKinds.StructuredName.GIVEN_NAME, contact.firstName) withValue(CommonDataKinds.StructuredName.GIVEN_NAME, contact.firstName)
withValue(CommonDataKinds.StructuredName.MIDDLE_NAME, contact.middleName) withValue(CommonDataKinds.StructuredName.MIDDLE_NAME, contact.middleName)
withValue(CommonDataKinds.StructuredName.FAMILY_NAME, contact.surname) withValue(CommonDataKinds.StructuredName.FAMILY_NAME, contact.surname)
withValue(CommonDataKinds.StructuredName.SUFFIX, contact.suffix)
operations.add(build()) operations.add(build())
} }
@ -704,6 +833,18 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
operations.add(build()) operations.add(build())
} }
// organization
ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI).apply {
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?"
val selectionArgs = arrayOf(contact.id.toString(), CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
withSelection(selection, selectionArgs)
withValue(CommonDataKinds.Organization.COMPANY, contact.organization.company)
withValue(CommonDataKinds.Organization.TYPE, CommonDataKinds.Organization.TYPE_WORK)
withValue(CommonDataKinds.Organization.TITLE, contact.organization.jobPosition)
withValue(CommonDataKinds.Organization.TYPE, CommonDataKinds.Organization.TYPE_WORK)
operations.add(build())
}
// delete groups // delete groups
val relevantGroupIDs = getStoredGroups().map { it.id } val relevantGroupIDs = getStoredGroups().map { it.id }
if (relevantGroupIDs.isNotEmpty()) { if (relevantGroupIDs.isNotEmpty()) {
@ -795,6 +936,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
withValue(CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId) withValue(CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId)
operations.add(build()) operations.add(build())
} }
if (operations.size % BATCH_SIZE == 0) {
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
operations.clear()
}
} }
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations) activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
} }
@ -808,6 +954,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
withSelection(selection, selectionArgs) withSelection(selection, selectionArgs)
operations.add(build()) operations.add(build())
} }
if (operations.size % BATCH_SIZE == 0) {
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
operations.clear()
}
} }
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations) activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
} }
@ -829,9 +980,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply { ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
withValue(CommonDataKinds.StructuredName.PREFIX, contact.prefix)
withValue(CommonDataKinds.StructuredName.GIVEN_NAME, contact.firstName) withValue(CommonDataKinds.StructuredName.GIVEN_NAME, contact.firstName)
withValue(CommonDataKinds.StructuredName.MIDDLE_NAME, contact.middleName) withValue(CommonDataKinds.StructuredName.MIDDLE_NAME, contact.middleName)
withValue(CommonDataKinds.StructuredName.FAMILY_NAME, contact.surname) withValue(CommonDataKinds.StructuredName.FAMILY_NAME, contact.surname)
withValue(CommonDataKinds.StructuredName.SUFFIX, contact.suffix)
operations.add(build()) operations.add(build())
} }
@ -887,6 +1040,17 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
operations.add(build()) operations.add(build())
} }
// organization
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
withValue(CommonDataKinds.Organization.COMPANY, contact.organization.company)
withValue(CommonDataKinds.Organization.TYPE, CommonDataKinds.Organization.TYPE_WORK)
withValue(CommonDataKinds.Organization.TITLE, contact.organization.jobPosition)
withValue(CommonDataKinds.Organization.TYPE, CommonDataKinds.Organization.TYPE_WORK)
operations.add(build())
}
// groups // groups
contact.groups.forEach { contact.groups.forEach {
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply { ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
@ -1000,16 +1164,19 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
fun addFavorites(contacts: ArrayList<Contact>) { fun addFavorites(contacts: ArrayList<Contact>) {
toggleLocalFavorites(contacts, true) toggleLocalFavorites(contacts, true)
toggleFavorites(contacts, true) if (activity.hasContactPermissions()) {
toggleFavorites(contacts, true)
}
} }
fun removeFavorites(contacts: ArrayList<Contact>) { fun removeFavorites(contacts: ArrayList<Contact>) {
toggleLocalFavorites(contacts, false) toggleLocalFavorites(contacts, false)
toggleFavorites(contacts, false) if (activity.hasContactPermissions()) {
toggleFavorites(contacts, false)
}
} }
private fun toggleFavorites(contacts: ArrayList<Contact>, addToFavorites: Boolean) { private fun toggleFavorites(contacts: ArrayList<Contact>, addToFavorites: Boolean) {
val applyBatchSize = 100
try { try {
val operations = ArrayList<ContentProviderOperation>() val operations = ArrayList<ContentProviderOperation>()
contacts.filter { it.source != SMT_PRIVATE }.map { it.contactId.toString() }.forEach { contacts.filter { it.source != SMT_PRIVATE }.map { it.contactId.toString() }.forEach {
@ -1019,7 +1186,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
operations.add(build()) operations.add(build())
} }
if (operations.size % applyBatchSize == 0) { if (operations.size % BATCH_SIZE == 0) {
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations) activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
operations.clear() operations.clear()
} }
@ -1044,25 +1211,27 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
} }
fun deleteContacts(contacts: ArrayList<Contact>) { fun deleteContacts(contacts: ArrayList<Contact>) {
val localContacts = contacts.filter { it.source == SMT_PRIVATE }.map { it.id.toString() }.toTypedArray() Thread {
activity.dbHelper.deleteContacts(localContacts) 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.CONTACT_ID} = ?" val selection = "${ContactsContract.Data.CONTACT_ID} = ?"
contacts.filter { it.source != SMT_PRIVATE }.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.contactId.toString()) val selectionArgs = arrayOf(it.contactId.toString())
withSelection(selection, selectionArgs) withSelection(selection, selectionArgs)
operations.add(this.build()) operations.add(this.build())
}
contactIDs.add(it.id.toString())
} }
contactIDs.add(it.id.toString())
}
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations) activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
} catch (e: Exception) { } catch (e: Exception) {
activity.showErrorToast(e) activity.showErrorToast(e)
} }
}.start()
} }
} }

View File

@ -23,9 +23,11 @@ import com.simplemobiletools.contacts.models.*
class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
private val CONTACTS_TABLE_NAME = "contacts" private val CONTACTS_TABLE_NAME = "contacts"
private val COL_ID = "id" private val COL_ID = "id"
private val COL_PREFIX = "prefix"
private val COL_FIRST_NAME = "first_name" private val COL_FIRST_NAME = "first_name"
private val COL_MIDDLE_NAME = "middle_name" private val COL_MIDDLE_NAME = "middle_name"
private val COL_SURNAME = "surname" private val COL_SURNAME = "surname"
private val COL_SUFFIX = "suffix"
private val COL_PHOTO = "photo" private val COL_PHOTO = "photo"
private val COL_PHONE_NUMBERS = "phone_numbers" private val COL_PHONE_NUMBERS = "phone_numbers"
private val COL_EMAILS = "emails" private val COL_EMAILS = "emails"
@ -33,6 +35,8 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
private val COL_STARRED = "starred" private val COL_STARRED = "starred"
private val COL_ADDRESSES = "addresses" private val COL_ADDRESSES = "addresses"
private val COL_NOTES = "notes" private val COL_NOTES = "notes"
private val COL_COMPANY = "company"
private val COL_JOB_POSITION = "job_position"
private val COL_GROUPS = "groups" private val COL_GROUPS = "groups"
private val GROUPS_TABLE_NAME = "groups" private val GROUPS_TABLE_NAME = "groups"
@ -43,9 +47,10 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
private val mDb = writableDatabase private val mDb = writableDatabase
companion object { companion object {
private const val DB_VERSION = 3 private const val DB_VERSION = 4
const val DB_NAME = "contacts.db" const val DB_NAME = "contacts.db"
var dbInstance: DBHelper? = null var dbInstance: DBHelper? = null
var gson = Gson()
fun newInstance(context: Context): DBHelper { fun newInstance(context: Context): DBHelper {
if (dbInstance == null) if (dbInstance == null)
@ -58,7 +63,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
override fun onCreate(db: SQLiteDatabase) { 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, " + db.execSQL("CREATE TABLE $CONTACTS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_FIRST_NAME TEXT, $COL_MIDDLE_NAME TEXT, " +
"$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER, " + "$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER, " +
"$COL_ADDRESSES TEXT, $COL_NOTES TEXT, $COL_GROUPS TEXT)") "$COL_ADDRESSES TEXT, $COL_NOTES TEXT, $COL_GROUPS TEXT, $COL_PREFIX TEXT, $COL_SUFFIX TEXT, $COL_COMPANY TEXT, $COL_JOB_POSITION TEXT)")
// start autoincrement ID from FIRST_CONTACT_ID to avoid conflicts // 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)") db.execSQL("REPLACE INTO sqlite_sequence (name, seq) VALUES ('$CONTACTS_TABLE_NAME', $FIRST_CONTACT_ID)")
@ -76,6 +81,13 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
createGroupsTable(db) createGroupsTable(db)
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_GROUPS TEXT DEFAULT ''") db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_GROUPS TEXT DEFAULT ''")
} }
if (oldVersion < 4) {
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_PREFIX TEXT DEFAULT ''")
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_SUFFIX TEXT DEFAULT ''")
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_COMPANY TEXT DEFAULT ''")
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_JOB_POSITION TEXT DEFAULT ''")
}
} }
private fun createGroupsTable(db: SQLiteDatabase) { private fun createGroupsTable(db: SQLiteDatabase) {
@ -108,16 +120,20 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
private fun fillContactValues(contact: Contact): ContentValues { private fun fillContactValues(contact: Contact): ContentValues {
return ContentValues().apply { return ContentValues().apply {
put(COL_PREFIX, contact.prefix)
put(COL_FIRST_NAME, contact.firstName) put(COL_FIRST_NAME, contact.firstName)
put(COL_MIDDLE_NAME, contact.middleName) put(COL_MIDDLE_NAME, contact.middleName)
put(COL_SURNAME, contact.surname) put(COL_SURNAME, contact.surname)
put(COL_PHONE_NUMBERS, Gson().toJson(contact.phoneNumbers)) put(COL_SUFFIX, contact.suffix)
put(COL_EMAILS, Gson().toJson(contact.emails)) put(COL_PHONE_NUMBERS, gson.toJson(contact.phoneNumbers))
put(COL_ADDRESSES, Gson().toJson(contact.addresses)) put(COL_EMAILS, gson.toJson(contact.emails))
put(COL_EVENTS, Gson().toJson(contact.events)) put(COL_ADDRESSES, gson.toJson(contact.addresses))
put(COL_EVENTS, gson.toJson(contact.events))
put(COL_STARRED, contact.starred) put(COL_STARRED, contact.starred)
put(COL_NOTES, contact.notes) put(COL_NOTES, contact.notes)
put(COL_GROUPS, Gson().toJson(contact.groups.map { it.id })) put(COL_GROUPS, gson.toJson(contact.groups.map { it.id }))
put(COL_COMPANY, contact.organization.company)
put(COL_JOB_POSITION, contact.organization.jobPosition)
if (contact.photoUri.isNotEmpty()) { if (contact.photoUri.isNotEmpty()) {
put(COL_PHOTO, getPhotoByteArray(contact.photoUri)) put(COL_PHOTO, getPhotoByteArray(contact.photoUri))
@ -166,7 +182,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
fun deleteGroup(id: Long) = deleteGroups(arrayOf(id.toString())) fun deleteGroup(id: Long) = deleteGroups(arrayOf(id.toString()))
fun deleteGroups(ids: Array<String>) { private fun deleteGroups(ids: Array<String>) {
val args = TextUtils.join(", ", ids) val args = TextUtils.join(", ", ids)
val selection = "$GROUPS_TABLE_NAME.$COL_ID IN ($args)" val selection = "$GROUPS_TABLE_NAME.$COL_ID IN ($args)"
mDb.delete(GROUPS_TABLE_NAME, selection, null) mDb.delete(GROUPS_TABLE_NAME, selection, null)
@ -209,7 +225,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
} }
} }
fun updateContactGroups(contact: Contact, groupIds: ArrayList<Long>) { private fun updateContactGroups(contact: Contact, groupIds: ArrayList<Long>) {
val contactValues = fillContactGroupValues(groupIds) val contactValues = fillContactGroupValues(groupIds)
val selection = "$COL_ID = ?" val selection = "$COL_ID = ?"
val selectionArgs = arrayOf(contact.id.toString()) val selectionArgs = arrayOf(contact.id.toString())
@ -218,39 +234,47 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
private fun fillContactGroupValues(groupIds: ArrayList<Long>): ContentValues { private fun fillContactGroupValues(groupIds: ArrayList<Long>): ContentValues {
return ContentValues().apply { return ContentValues().apply {
put(COL_GROUPS, Gson().toJson(groupIds)) put(COL_GROUPS, gson.toJson(groupIds))
} }
} }
fun getContacts(activity: BaseSimpleActivity, selection: String? = null, selectionArgs: Array<String>? = null): ArrayList<Contact> { fun getContacts(activity: BaseSimpleActivity, selection: String? = null, selectionArgs: Array<String>? = null): ArrayList<Contact> {
val storedGroups = ContactsHelper(activity).getStoredGroups() val storedGroups = ContactsHelper(activity).getStoredGroups()
val contacts = 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, val projection = arrayOf(COL_ID, COL_PREFIX, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_SUFFIX, COL_PHONE_NUMBERS, COL_EMAILS,
COL_PHOTO, COL_ADDRESSES, COL_NOTES, COL_GROUPS) COL_EVENTS, COL_STARRED, COL_PHOTO, COL_ADDRESSES, COL_NOTES, COL_GROUPS, COL_COMPANY, COL_JOB_POSITION)
val phoneNumbersToken = object : TypeToken<List<PhoneNumber>>() {}.type
val emailsToken = object : TypeToken<List<Email>>() {}.type
val addressesToken = object : TypeToken<List<Address>>() {}.type
val eventsToken = object : TypeToken<List<Event>>() {}.type
val groupIdsToken = object : TypeToken<List<Long>>() {}.type
val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, selection, selectionArgs, null, null, null) val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, selection, selectionArgs, null, null, null)
cursor.use { cursor.use {
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
val id = cursor.getIntValue(COL_ID) val id = cursor.getIntValue(COL_ID)
val prefix = cursor.getStringValue(COL_PREFIX)
val firstName = cursor.getStringValue(COL_FIRST_NAME) val firstName = cursor.getStringValue(COL_FIRST_NAME)
val middleName = cursor.getStringValue(COL_MIDDLE_NAME) val middleName = cursor.getStringValue(COL_MIDDLE_NAME)
val surname = cursor.getStringValue(COL_SURNAME) val surname = cursor.getStringValue(COL_SURNAME)
val suffix = cursor.getStringValue(COL_SUFFIX)
val phoneNumbersJson = cursor.getStringValue(COL_PHONE_NUMBERS) val phoneNumbersJson = cursor.getStringValue(COL_PHONE_NUMBERS)
val phoneNumbersToken = object : TypeToken<List<PhoneNumber>>() {}.type val phoneNumbers = if (phoneNumbersJson == "[]") ArrayList() else gson.fromJson<ArrayList<PhoneNumber>>(phoneNumbersJson, phoneNumbersToken)
val phoneNumbers = Gson().fromJson<ArrayList<PhoneNumber>>(phoneNumbersJson, phoneNumbersToken) ?: ArrayList(1) ?: ArrayList(1)
val emailsJson = cursor.getStringValue(COL_EMAILS) val emailsJson = cursor.getStringValue(COL_EMAILS)
val emailsToken = object : TypeToken<List<Email>>() {}.type val emails = if (emailsJson == "[]") ArrayList() else gson.fromJson<ArrayList<Email>>(emailsJson, emailsToken)
val emails = Gson().fromJson<ArrayList<Email>>(emailsJson, emailsToken) ?: ArrayList(1) ?: ArrayList(1)
val addressesJson = cursor.getStringValue(COL_ADDRESSES) val addressesJson = cursor.getStringValue(COL_ADDRESSES)
val addressesToken = object : TypeToken<List<Address>>() {}.type val addresses = if (addressesJson == "[]") ArrayList() else gson.fromJson<ArrayList<Address>>(addressesJson, addressesToken)
val addresses = Gson().fromJson<ArrayList<Address>>(addressesJson, addressesToken) ?: ArrayList(1) ?: ArrayList(1)
val eventsJson = cursor.getStringValue(COL_EVENTS) val eventsJson = cursor.getStringValue(COL_EVENTS)
val eventsToken = object : TypeToken<List<Event>>() {}.type val events = if (eventsJson == "[]") ArrayList() else gson.fromJson<ArrayList<Event>>(eventsJson, eventsToken)
val events = Gson().fromJson<ArrayList<Event>>(eventsJson, eventsToken) ?: ArrayList(1) ?: ArrayList(1)
val photoByteArray = cursor.getBlobValue(COL_PHOTO) ?: null val photoByteArray = cursor.getBlobValue(COL_PHOTO) ?: null
val photo = if (photoByteArray?.isNotEmpty() == true) { val photo = if (photoByteArray?.isNotEmpty() == true) {
@ -263,11 +287,18 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
val starred = cursor.getIntValue(COL_STARRED) val starred = cursor.getIntValue(COL_STARRED)
val groupIdsJson = cursor.getStringValue(COL_GROUPS) val groupIdsJson = cursor.getStringValue(COL_GROUPS)
val groupIdsToken = object : TypeToken<List<Long>>() {}.type val groupIds = if (groupIdsJson == "[]") ArrayList() else gson.fromJson<ArrayList<Long>>(groupIdsJson, groupIdsToken)
val groupIds = Gson().fromJson<ArrayList<Long>>(groupIdsJson, groupIdsToken) ?: ArrayList(1) ?: ArrayList(1)
val groups = storedGroups.filter { groupIds.contains(it.id) } as ArrayList<Group> val groups = storedGroups.filter { groupIds.contains(it.id) } as ArrayList<Group>
val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, addresses, events, SMT_PRIVATE, starred, id, "", photo, notes, groups) val company = cursor.getStringValue(COL_COMPANY)
val jobPosition = cursor.getStringValue(COL_JOB_POSITION)
val organization = Organization(company, jobPosition)
val websites = ArrayList<String>()
val contact = Contact(id, prefix, firstName, middleName, surname, suffix, "", phoneNumbers, emails, addresses, events,
SMT_PRIVATE, starred, id, "", photo, notes, groups, organization, websites)
contacts.add(contact) contacts.add(contact)
} }
} }

View File

@ -66,6 +66,11 @@ class VcfExporter {
out.writeLn("$NOTE${contact.notes.replace("\n", "\\n")}") out.writeLn("$NOTE${contact.notes.replace("\n", "\\n")}")
} }
if (!contact.organization.isEmpty()) {
out.writeLn("$ORG${contact.organization.company.replace("\n", "\\n")}")
out.writeLn("$TITLE${contact.organization.jobPosition.replace("\n", "\\n")}")
}
if (contact.thumbnailUri.isNotEmpty()) { if (contact.thumbnailUri.isNotEmpty()) {
val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, Uri.parse(contact.thumbnailUri)) val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, Uri.parse(contact.thumbnailUri))
addBitmap(bitmap, out) addBitmap(bitmap, out)
@ -116,17 +121,23 @@ class VcfExporter {
var firstName = contact.firstName var firstName = contact.firstName
var surName = contact.surname var surName = contact.surname
var middleName = contact.middleName var middleName = contact.middleName
var prefix = contact.prefix
var suffix = contact.suffix
if (QuotedPrintable.urlEncode(firstName) != firstName if (QuotedPrintable.urlEncode(firstName) != firstName
|| QuotedPrintable.urlEncode(surName) != surName || QuotedPrintable.urlEncode(surName) != surName
|| QuotedPrintable.urlEncode(middleName) != middleName) { || QuotedPrintable.urlEncode(middleName) != middleName
|| QuotedPrintable.urlEncode(prefix) != prefix
|| QuotedPrintable.urlEncode(suffix) != suffix) {
firstName = QuotedPrintable.encode(firstName) firstName = QuotedPrintable.encode(firstName)
surName = QuotedPrintable.encode(surName) surName = QuotedPrintable.encode(surName)
middleName = QuotedPrintable.encode(middleName) middleName = QuotedPrintable.encode(middleName)
prefix = QuotedPrintable.encode(prefix)
suffix = QuotedPrintable.encode(suffix)
result += ";CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE" result += ";CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE"
} }
return "$result:$surName;$firstName;$middleName;;" return "$result:$surName;$firstName;$middleName;$prefix;$suffix"
} }
private fun getPhoneNumberLabel(type: Int) = when (type) { private fun getPhoneNumberLabel(type: Int) = when (type) {

View File

@ -19,16 +19,21 @@ class VcfImporter(val activity: SimpleActivity) {
IMPORT_FAIL, IMPORT_OK, IMPORT_PARTIAL IMPORT_FAIL, IMPORT_OK, IMPORT_PARTIAL
} }
private var curPrefix = ""
private var curFirstName = "" private var curFirstName = ""
private var curMiddleName = "" private var curMiddleName = ""
private var curSurname = "" private var curSurname = ""
private var curSuffix = ""
private var curPhotoUri = "" private var curPhotoUri = ""
private var curNotes = "" private var curNotes = ""
private var curCompany = ""
private var curJobPosition = ""
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 curAddresses = ArrayList<Address>()
private var curGroups = ArrayList<Group>() private var curGroups = ArrayList<Group>()
private var curWebsites = ArrayList<String>()
private var isGettingPhoto = false private var isGettingPhoto = false
private var currentPhotoString = StringBuilder() private var currentPhotoString = StringBuilder()
@ -84,6 +89,8 @@ class VcfImporter(val activity: SimpleActivity) {
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))
line.toUpperCase().startsWith(ORG) -> addCompany(line.substring(ORG.length))
line.toUpperCase().startsWith(TITLE) -> addJobPosition(line.substring(TITLE.length))
line.toUpperCase() == END_VCARD -> saveContact(targetContactSource) line.toUpperCase() == END_VCARD -> saveContact(targetContactSource)
isGettingPhoto -> currentPhotoString.append(line.trim()) isGettingPhoto -> currentPhotoString.append(line.trim())
} }
@ -118,6 +125,8 @@ class VcfImporter(val activity: SimpleActivity) {
curFirstName = if (currentNameIsANSI) QuotedPrintable.decode(nameParts[1]) else nameParts[1] curFirstName = if (currentNameIsANSI) QuotedPrintable.decode(nameParts[1]) else nameParts[1]
if (nameParts.size > 2) { if (nameParts.size > 2) {
curMiddleName = if (currentNameIsANSI) QuotedPrintable.decode(nameParts[2]) else nameParts[2] curMiddleName = if (currentNameIsANSI) QuotedPrintable.decode(nameParts[2]) else nameParts[2]
curPrefix = if (currentNameIsANSI) QuotedPrintable.decode(nameParts[3]) else nameParts[3]
curSuffix = if (currentNameIsANSI) QuotedPrintable.decode(nameParts[4]) else nameParts[4]
} }
} }
@ -234,25 +243,39 @@ class VcfImporter(val activity: SimpleActivity) {
isGettingNotes = true isGettingNotes = true
} }
private fun addCompany(company: String) {
curCompany = company
}
private fun addJobPosition(jobPosition: String) {
curJobPosition = jobPosition
}
private fun saveContact(source: String) { private fun saveContact(source: String) {
val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curAddresses, curEvents, val organization = Organization(curCompany, curJobPosition)
source, 0, 0, "", null, curNotes, curGroups) val contact = Contact(0, curPrefix, curFirstName, curMiddleName, curSurname, curSuffix, curPhotoUri, curPhoneNumbers, curEmails, curAddresses, curEvents,
source, 0, 0, "", null, curNotes, curGroups, organization, curWebsites)
if (ContactsHelper(activity).insertContact(contact)) { if (ContactsHelper(activity).insertContact(contact)) {
contactsImported++ contactsImported++
} }
} }
private fun resetValues() { private fun resetValues() {
curPrefix = ""
curFirstName = "" curFirstName = ""
curMiddleName = "" curMiddleName = ""
curSurname = "" curSurname = ""
curSuffix = ""
curPhotoUri = "" curPhotoUri = ""
curNotes = "" curNotes = ""
curCompany = ""
curJobPosition = ""
curPhoneNumbers = ArrayList() curPhoneNumbers = ArrayList()
curEmails = ArrayList() curEmails = ArrayList()
curEvents = ArrayList() curEvents = ArrayList()
curAddresses = ArrayList() curAddresses = ArrayList()
curGroups = ArrayList() curGroups = ArrayList()
curWebsites = ArrayList()
isGettingPhoto = false isGettingPhoto = false
currentPhotoString = StringBuilder() currentPhotoString = StringBuilder()

View File

@ -5,19 +5,50 @@ 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 prefix: String, var firstName: String, var middleName: String, var surname: String, var suffix: String, var photoUri: String,
var phoneNumbers: ArrayList<PhoneNumber>, var emails: ArrayList<Email>, var addresses: ArrayList<Address>, var events: ArrayList<Event>, var phoneNumbers: ArrayList<PhoneNumber>, var emails: ArrayList<Email>, var addresses: ArrayList<Address>, var events: ArrayList<Event>,
var source: String, var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?, var notes: String, var source: String, var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?, var notes: String,
var groups: ArrayList<Group>) : Comparable<Contact> { var groups: ArrayList<Group>, var organization: Organization, var websites: ArrayList<String>) : Comparable<Contact> {
companion object { companion object {
var sorting = 0 var sorting = 0
var startWithSurname = false
} }
override fun compareTo(other: Contact): Int { override fun compareTo(other: Contact): Int {
var result = when { val firstString: String
sorting and SORT_BY_FIRST_NAME != 0 -> compareStrings(firstName, other.firstName) val secondString: String
sorting and SORT_BY_MIDDLE_NAME != 0 -> compareStrings(middleName, other.middleName)
else -> compareStrings(surname, other.surname) when {
sorting and SORT_BY_FIRST_NAME != 0 -> {
firstString = firstName
secondString = other.firstName
}
sorting and SORT_BY_MIDDLE_NAME != 0 -> {
firstString = middleName
secondString = other.middleName
}
else -> {
firstString = surname
secondString = other.surname
}
}
var result = if (firstString.firstOrNull()?.isLetter() == true && secondString.firstOrNull()?.isLetter() == false) {
-1
} else if (firstString.firstOrNull()?.isLetter() == false && secondString.firstOrNull()?.isLetter() == true) {
1
} else {
if (firstString.isEmpty() && secondString.isNotEmpty()) {
1
} else if (firstString.isNotEmpty() && secondString.isEmpty()) {
-1
} else {
if (firstString.toLowerCase() == secondString.toLowerCase()) {
getFullName().compareTo(other.getFullName())
} else {
firstString.toLowerCase().compareTo(secondString.toLowerCase())
}
}
} }
if (sorting and SORT_DESCENDING != 0) { if (sorting and SORT_DESCENDING != 0) {
@ -33,28 +64,21 @@ data class Contact(val id: Int, var firstName: String, var middleName: String, v
else -> surname else -> surname
} }
fun getFullName(startWithSurname: Boolean): String { fun getFullName(): String {
var firstPart = if (startWithSurname) surname else firstName var firstPart = if (startWithSurname) surname else firstName
if (middleName.isNotEmpty()) { if (middleName.isNotEmpty()) {
firstPart += " $middleName" firstPart += " $middleName"
} }
val lastPart = if (startWithSurname) firstName else surname
return "$firstPart $lastPart".trim()
}
private fun compareStrings(first: String, second: String): Int { val lastPart = if (startWithSurname) firstName else surname
return if (first.firstOrNull()?.isLetter() == true && second.firstOrNull()?.isLetter() == false) { val suffixComma = if (suffix.isEmpty()) "" else ", $suffix"
-1 val fullName = "$prefix $firstPart $lastPart$suffixComma".trim()
} else if (first.firstOrNull()?.isLetter() == false && second.firstOrNull()?.isLetter() == true) { return if (fullName.isEmpty()) {
1 var fullOrganization = if (organization.jobPosition.isEmpty()) "" else "${organization.jobPosition}, "
fullOrganization += organization.company
fullOrganization.trim().trimEnd(',')
} else { } else {
if (first.isEmpty() && second.isNotEmpty()) { fullName
1
} else if (first.isNotEmpty() && second.isEmpty()) {
-1
} else {
first.toLowerCase().compareTo(second.toLowerCase())
}
} }
} }
} }

View File

@ -0,0 +1,5 @@
package com.simplemobiletools.contacts.models
data class Organization(var company: String, var jobPosition: String) {
fun isEmpty() = company.isEmpty() && jobPosition.isEmpty()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

View File

@ -18,7 +18,8 @@
<ImageView <ImageView
android:id="@+id/contact_photo" android:id="@+id/contact_photo"
android:layout_width="@dimen/contact_photo_size" android:layout_width="@dimen/contact_photo_size"
android:layout_height="@dimen/contact_photo_size"/> android:layout_height="@dimen/contact_photo_size"
android:layout_marginBottom="@dimen/normal_margin"/>
<ImageView <ImageView
android:id="@+id/contact_toggle_favorite" android:id="@+id/contact_toggle_favorite"
@ -82,7 +83,7 @@
android:id="@+id/contact_name_image" android:id="@+id/contact_name_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size" android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_first_name" android:layout_below="@+id/contact_photo"
android:paddingBottom="@dimen/small_margin" android:paddingBottom="@dimen/small_margin"
android:paddingEnd="@dimen/small_margin" android:paddingEnd="@dimen/small_margin"
android:paddingRight="@dimen/small_margin" android:paddingRight="@dimen/small_margin"
@ -90,12 +91,28 @@
android:src="@drawable/ic_person"/> android:src="@drawable/ic_person"/>
<com.simplemobiletools.commons.views.MyEditText <com.simplemobiletools.commons.views.MyEditText
android:id="@+id/contact_first_name" android:id="@+id/contact_prefix"
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_photo" android:layout_below="@+id/contact_photo"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginTop="@dimen/normal_margin" android:layout_marginBottom="@dimen/normal_margin"
android:layout_toRightOf="@+id/contact_name_image"
android:hint="@string/prefix"
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.MyEditText
android:id="@+id/contact_first_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_prefix"
android:layout_centerVertical="true"
android:layout_marginBottom="@dimen/normal_margin"
android:layout_toRightOf="@+id/contact_name_image" android:layout_toRightOf="@+id/contact_name_image"
android:hint="@string/first_name" android:hint="@string/first_name"
android:inputType="textCapWords" android:inputType="textCapWords"
@ -111,7 +128,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/contact_first_name" android:layout_below="@+id/contact_first_name"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginTop="@dimen/normal_margin" android:layout_marginBottom="@dimen/normal_margin"
android:layout_toRightOf="@+id/contact_name_image" android:layout_toRightOf="@+id/contact_name_image"
android:hint="@string/middle_name" android:hint="@string/middle_name"
android:inputType="textCapWords" android:inputType="textCapWords"
@ -127,7 +144,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/contact_middle_name" android:layout_below="@+id/contact_middle_name"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginTop="@dimen/normal_margin" android:layout_marginBottom="@dimen/normal_margin"
android:layout_toRightOf="@+id/contact_name_image" android:layout_toRightOf="@+id/contact_name_image"
android:hint="@string/surname" android:hint="@string/surname"
android:inputType="textCapWords" android:inputType="textCapWords"
@ -137,8 +154,24 @@
android:textCursorDrawable="@null" android:textCursorDrawable="@null"
android:textSize="@dimen/bigger_text_size"/> android:textSize="@dimen/bigger_text_size"/>
<com.simplemobiletools.commons.views.MyEditText
android:id="@+id/contact_suffix"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_surname"
android:layout_centerVertical="true"
android:layout_marginBottom="@dimen/medium_margin"
android:layout_toRightOf="@+id/contact_name_image"
android:hint="@string/suffix"
android:inputType="textCapWords"
android:lines="1"
android:maxLines="1"
android:singleLine="true"
android:textCursorDrawable="@null"
android:textSize="@dimen/bigger_text_size"/>
<ImageView <ImageView
android:id="@+id/contact_number_image" android:id="@+id/contact_numbers_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size" android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_numbers_holder" android:layout_alignTop="@+id/contact_numbers_holder"
@ -152,9 +185,9 @@
android:id="@+id/contact_numbers_holder" android:id="@+id/contact_numbers_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_surname" android:layout_below="@+id/contact_suffix"
android:layout_marginTop="@dimen/medium_margin" android:layout_marginBottom="@dimen/small_margin"
android:layout_toRightOf="@+id/contact_number_image" android:layout_toRightOf="@+id/contact_numbers_image"
android:orientation="vertical"> android:orientation="vertical">
<include layout="@layout/item_edit_phone_number"/> <include layout="@layout/item_edit_phone_number"/>
@ -162,21 +195,21 @@
</LinearLayout> </LinearLayout>
<ImageView <ImageView
android:id="@+id/contact_number_add_new" android:id="@+id/contact_numbers_add_new"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/contact_numbers_holder" android:layout_below="@+id/contact_numbers_holder"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/small_margin"
android:background="@drawable/button_background" android:background="@drawable/button_background"
android:paddingBottom="@dimen/medium_margin" android:paddingBottom="@dimen/medium_margin"
android:layout_marginBottom="@dimen/medium_margin"
android:paddingLeft="@dimen/activity_margin" android:paddingLeft="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin" android:paddingRight="@dimen/activity_margin"
android:paddingTop="@dimen/medium_margin" android:paddingTop="@dimen/medium_margin"
android:src="@drawable/ic_plus"/> android:src="@drawable/ic_plus"/>
<ImageView <ImageView
android:id="@+id/contact_email_image" android:id="@+id/contact_emails_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size" android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_emails_holder" android:layout_alignTop="@+id/contact_emails_holder"
@ -190,8 +223,7 @@
android:id="@+id/contact_emails_holder" android:id="@+id/contact_emails_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_number_add_new" android:layout_below="@+id/contact_numbers_add_new"
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">
@ -200,7 +232,7 @@
</LinearLayout> </LinearLayout>
<ImageView <ImageView
android:id="@+id/contact_email_add_new" android:id="@+id/contact_emails_add_new"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/contact_emails_holder" android:layout_below="@+id/contact_emails_holder"
@ -214,7 +246,7 @@
android:src="@drawable/ic_plus"/> android:src="@drawable/ic_plus"/>
<ImageView <ImageView
android:id="@+id/contact_address_image" android:id="@+id/contact_addresses_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size" android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_addresses_holder" android:layout_alignTop="@+id/contact_addresses_holder"
@ -228,7 +260,7 @@
android:id="@+id/contact_addresses_holder" android:id="@+id/contact_addresses_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_emails_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">
@ -238,7 +270,7 @@
</LinearLayout> </LinearLayout>
<ImageView <ImageView
android:id="@+id/contact_address_add_new" android:id="@+id/contact_addresses_add_new"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/contact_addresses_holder" android:layout_below="@+id/contact_addresses_holder"
@ -252,7 +284,7 @@
android:src="@drawable/ic_plus"/> android:src="@drawable/ic_plus"/>
<ImageView <ImageView
android:id="@+id/contact_event_image" android:id="@+id/contact_events_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size" android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_events_holder" android:layout_alignTop="@+id/contact_events_holder"
@ -266,7 +298,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_address_add_new" android:layout_below="@+id/contact_addresses_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">
@ -276,7 +308,7 @@
</LinearLayout> </LinearLayout>
<ImageView <ImageView
android:id="@+id/contact_event_add_new" android:id="@+id/contact_events_add_new"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/contact_events_holder" android:layout_below="@+id/contact_events_holder"
@ -304,7 +336,7 @@
android:id="@+id/contact_notes" android:id="@+id/contact_notes"
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_events_add_new"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginTop="@dimen/normal_margin" android:layout_marginTop="@dimen/normal_margin"
android:layout_toRightOf="@+id/contact_notes_image" android:layout_toRightOf="@+id/contact_notes_image"
@ -313,6 +345,47 @@
android:textCursorDrawable="@null" android:textCursorDrawable="@null"
android:textSize="@dimen/bigger_text_size"/> android:textSize="@dimen/bigger_text_size"/>
<ImageView
android:id="@+id/contact_organization_image"
android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_organization_company"
android:paddingBottom="@dimen/small_margin"
android:paddingEnd="@dimen/small_margin"
android:paddingRight="@dimen/small_margin"
android:paddingTop="@dimen/medium_margin"
android:src="@drawable/ic_business"/>
<com.simplemobiletools.commons.views.MyEditText
android:id="@+id/contact_organization_company"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_notes"
android:layout_centerVertical="true"
android:layout_marginTop="@dimen/normal_margin"
android:layout_toRightOf="@+id/contact_organization_image"
android:hint="@string/company"
android:inputType="textCapWords"
android:maxLines="1"
android:singleLine="true"
android:textCursorDrawable="@null"
android:textSize="@dimen/bigger_text_size"/>
<com.simplemobiletools.commons.views.MyEditText
android:id="@+id/contact_organization_job_position"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_organization_company"
android:layout_centerVertical="true"
android:layout_marginTop="@dimen/normal_margin"
android:layout_toRightOf="@+id/contact_organization_image"
android:hint="@string/job_position"
android:inputType="textCapWords"
android:maxLines="1"
android:singleLine="true"
android:textCursorDrawable="@null"
android:textSize="@dimen/bigger_text_size"/>
<ImageView <ImageView
android:id="@+id/contact_groups_image" android:id="@+id/contact_groups_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
@ -328,7 +401,7 @@
android:id="@+id/contact_groups_holder" android:id="@+id/contact_groups_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_notes" android:layout_below="@+id/contact_organization_job_position"
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">

View File

@ -33,6 +33,28 @@
</RelativeLayout> </RelativeLayout>
<RelativeLayout
android:id="@+id/settings_manage_contact_fields_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_manage_contact_fields"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:text="@string/manage_shown_contact_fields"/>
</RelativeLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/settings_use_english_holder" android:id="@+id/settings_use_english_holder"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -18,7 +18,8 @@
<ImageView <ImageView
android:id="@+id/contact_photo" android:id="@+id/contact_photo"
android:layout_width="@dimen/contact_photo_size" android:layout_width="@dimen/contact_photo_size"
android:layout_height="@dimen/contact_photo_size"/> android:layout_height="@dimen/contact_photo_size"
android:layout_marginBottom="@dimen/normal_margin"/>
<ImageView <ImageView
android:id="@+id/contact_toggle_favorite" android:id="@+id/contact_toggle_favorite"
@ -83,7 +84,7 @@
android:id="@+id/contact_name_image" android:id="@+id/contact_name_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size" android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_first_name" android:layout_below="@+id/contact_photo"
android:paddingBottom="@dimen/small_margin" android:paddingBottom="@dimen/small_margin"
android:paddingEnd="@dimen/small_margin" android:paddingEnd="@dimen/small_margin"
android:paddingRight="@dimen/small_margin" android:paddingRight="@dimen/small_margin"
@ -91,12 +92,26 @@
android:src="@drawable/ic_person"/> android:src="@drawable/ic_person"/>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/contact_first_name" android:id="@+id/contact_prefix"
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_photo" android:layout_below="@+id/contact_photo"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginTop="@dimen/normal_margin" android:layout_toRightOf="@+id/contact_name_image"
android:lines="1"
android:maxLines="1"
android:paddingBottom="@dimen/normal_margin"
android:paddingLeft="@dimen/small_margin"
android:paddingTop="@dimen/normal_margin"
android:singleLine="true"
android:textSize="@dimen/bigger_text_size"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/contact_first_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_prefix"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/contact_name_image" android:layout_toRightOf="@+id/contact_name_image"
android:lines="1" android:lines="1"
android:maxLines="1" android:maxLines="1"
@ -136,8 +151,23 @@
android:singleLine="true" android:singleLine="true"
android:textSize="@dimen/bigger_text_size"/> android:textSize="@dimen/bigger_text_size"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/contact_suffix"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_surname"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/contact_name_image"
android:lines="1"
android:maxLines="1"
android:paddingBottom="@dimen/normal_margin"
android:paddingLeft="@dimen/small_margin"
android:paddingTop="@dimen/normal_margin"
android:singleLine="true"
android:textSize="@dimen/bigger_text_size"/>
<ImageView <ImageView
android:id="@+id/contact_number_image" android:id="@+id/contact_numbers_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size" android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_numbers_holder" android:layout_alignTop="@+id/contact_numbers_holder"
@ -151,13 +181,13 @@
android:id="@+id/contact_numbers_holder" android:id="@+id/contact_numbers_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_surname" android:layout_below="@+id/contact_suffix"
android:layout_toRightOf="@+id/contact_number_image" android:layout_toRightOf="@+id/contact_numbers_image"
android:orientation="vertical" android:orientation="vertical"
android:paddingLeft="@dimen/small_margin"/> android:paddingLeft="@dimen/small_margin"/>
<ImageView <ImageView
android:id="@+id/contact_email_image" android:id="@+id/contact_emails_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size" android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_emails_holder" android:layout_alignTop="@+id/contact_emails_holder"
@ -177,7 +207,7 @@
android:paddingLeft="@dimen/small_margin"/> android:paddingLeft="@dimen/small_margin"/>
<ImageView <ImageView
android:id="@+id/contact_address_image" android:id="@+id/contact_addresses_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size" android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_addresses_holder" android:layout_alignTop="@+id/contact_addresses_holder"
@ -197,7 +227,7 @@
android:paddingLeft="@dimen/small_margin"/> android:paddingLeft="@dimen/small_margin"/>
<ImageView <ImageView
android:id="@+id/contact_event_image" android:id="@+id/contact_events_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size" android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_events_holder" android:layout_alignTop="@+id/contact_events_holder"
@ -239,6 +269,62 @@
android:paddingTop="@dimen/normal_margin" android:paddingTop="@dimen/normal_margin"
android:textSize="@dimen/bigger_text_size"/> android:textSize="@dimen/bigger_text_size"/>
<ImageView
android:id="@+id/contact_organization_image"
android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_organization_company"
android:paddingBottom="@dimen/small_margin"
android:paddingEnd="@dimen/small_margin"
android:paddingRight="@dimen/small_margin"
android:paddingTop="@dimen/medium_margin"
android:src="@drawable/ic_business"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/contact_organization_company"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_notes"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/contact_organization_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"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/contact_organization_job_position"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_organization_company"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/contact_organization_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
android:id="@+id/contact_websites_image"
android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_websites_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_link"/>
<LinearLayout
android:id="@+id/contact_websites_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_organization_job_position"
android:layout_toRightOf="@+id/contact_name_image"
android:orientation="vertical"/>
<ImageView <ImageView
android:id="@+id/contact_groups_image" android:id="@+id/contact_groups_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
@ -254,7 +340,7 @@
android:id="@+id/contact_groups_holder" android:id="@+id/contact_groups_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_notes" android:layout_below="@+id/contact_websites_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"/>

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/manage_visible_fields_scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/manage_visible_fields_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_prefix"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/prefix"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_first_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/first_name"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_middle_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/middle_name"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_surname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/surname"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_suffix"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/suffix"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_phone_numbers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/phone_numbers"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_emails"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/emails"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_addresses"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/addresses"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_events"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/events"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_notes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/notes"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_organization"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/organization"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_websites"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/websites"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_groups"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/groups"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_visible_fields_contact_source"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/contact_source"/>
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<com.simplemobiletools.commons.views.MyTextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contact_website"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/normal_margin"
android:paddingLeft="@dimen/small_margin"
android:paddingRight="@dimen/small_margin"
android:paddingTop="@dimen/normal_margin"
android:text="@string/unknown"
android:textSize="@dimen/bigger_text_size"/>

View File

@ -6,6 +6,9 @@
<string name="updating">Aktualisiere…</string> <string name="updating">Aktualisiere…</string>
<string name="phone_storage">Gerätespeicher</string> <string name="phone_storage">Gerätespeicher</string>
<string name="phone_storage_hidden">Gerätespeicher (nicht sichtbar für andere Apps)</string> <string name="phone_storage_hidden">Gerätespeicher (nicht sichtbar für andere Apps)</string>
<string name="company">Company</string>
<string name="job_position">Job position</string>
<string name="website">Website</string>
<string name="new_contact">Neuer Kontakt</string> <string name="new_contact">Neuer Kontakt</string>
<string name="edit_contact">Kontakt bearbeiten</string> <string name="edit_contact">Kontakt bearbeiten</string>
@ -16,15 +19,15 @@
<string name="surname">Familienname</string> <string name="surname">Familienname</string>
<!-- Groups --> <!-- Groups -->
<string name="no_groups">No groups</string> <string name="no_groups">Keine Gruppen</string>
<string name="create_new_group">Create a new group</string> <string name="create_new_group">Eine neue Gruppe erstellen</string>
<string name="remove_from_group">Remove from group</string> <string name="remove_from_group">Von Gruppe entfernen</string>
<string name="no_group_participants">This group is empty</string> <string name="no_group_participants">Diese Gruppe ist leer</string>
<string name="add_contacts">Add contacts</string> <string name="add_contacts">Kontakte hinzufügen</string>
<string name="no_group_created">There are no contact groups on the device</string> <string name="no_group_created">Es sind keine Kontaktgruppen auf diesem Gerät vorhanden</string>
<string name="create_group">Create group</string> <string name="create_group">Erstelle Gruppe</string>
<string name="add_to_group">Add to group</string> <string name="add_to_group">Zu Gruppe hinzufügen</string>
<string name="create_group_under_account">Create group under account</string> <string name="create_group_under_account">Gruppe in diesem Konto erstellen</string>
<!-- Photo --> <!-- Photo -->
<string name="take_photo">Foto machen</string> <string name="take_photo">Foto machen</string>
@ -40,6 +43,7 @@
<string name="view_contact">Kontaktdetails ansehen</string> <string name="view_contact">Kontaktdetails ansehen</string>
<string name="show_favorites_tab">Show favorites tab</string> <string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string> <string name="show_groups_tab">Show groups tab</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails --> <!-- Emails -->
<string name="email">Email</string> <string name="email">Email</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Kontaktquellen einschließen</string> <string name="include_contact_sources">Kontaktquellen einschließen</string>
<string name="filename_without_vcf">Dateiname (ohne .vcf)</string> <string name="filename_without_vcf">Dateiname (ohne .vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Select fields to show</string>
<string name="prefix">Prefix</string>
<string name="suffix">Suffix</string>
<string name="phone_numbers">Phone numbers</string>
<string name="emails">Emails</string>
<string name="addresses">Addresses</string>
<string name="events">Events (birthdays, anniversaries)</string>
<string name="notes">Notes</string>
<string name="organization">Organization</string>
<string name="websites">Websites</string>
<string name="groups">Groups</string>
<string name="contact_source">Contact source</string>
<!-- FAQ -->
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Eine App zum Verwalten von Kontakten, ganz ohne Werbung.</string> <string name="app_short_description">Eine App zum Verwalten von Kontakten, ganz ohne Werbung.</string>

View File

@ -2,10 +2,13 @@
<string name="app_name">Απλές Επαφές</string> <string name="app_name">Απλές Επαφές</string>
<string name="app_launcher_name">Επαφές</string> <string name="app_launcher_name">Επαφές</string>
<string name="address">Διεύθυνση</string> <string name="address">Διεύθυνση</string>
<string name="inserting">Εισαγωγή...</string> <string name="inserting">Εισαγωγή</string>
<string name="updating">Ενημέρωση...</string> <string name="updating">Ενημέρωση</string>
<string name="phone_storage">Μνήμη τηλεφώνου</string> <string name="phone_storage">Μνήμη τηλεφώνου</string>
<string name="phone_storage_hidden">Μνήμη τηλεφώνου (δεν είναι ορατή από άλλες εφαρμογές)</string> <string name="phone_storage_hidden">Μνήμη τηλεφώνου (δεν είναι ορατή από άλλες εφαρμογές)</string>
<string name="company">Company</string>
<string name="job_position">Job position</string>
<string name="website">Website</string>
<string name="new_contact">Νέα επαφή</string> <string name="new_contact">Νέα επαφή</string>
<string name="edit_contact">Επεξεργασία επαφής</string> <string name="edit_contact">Επεξεργασία επαφής</string>
@ -40,6 +43,7 @@
<string name="view_contact">Εμφάνιση λεπτομερειών επαφής</string> <string name="view_contact">Εμφάνιση λεπτομερειών επαφής</string>
<string name="show_favorites_tab">Εμφάνιση καρτέλας αγαπημένων</string> <string name="show_favorites_tab">Εμφάνιση καρτέλας αγαπημένων</string>
<string name="show_groups_tab">Εμφάνιση καρτέλας ομάδων</string> <string name="show_groups_tab">Εμφάνιση καρτέλας ομάδων</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails --> <!-- Emails -->
<string name="email">Email</string> <string name="email">Email</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Συμπερίληψη πηγών επαφών</string> <string name="include_contact_sources">Συμπερίληψη πηγών επαφών</string>
<string name="filename_without_vcf">Όνομα αρχείου (χωρίς .vcf)</string> <string name="filename_without_vcf">Όνομα αρχείου (χωρίς .vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Select fields to show</string>
<string name="prefix">Prefix</string>
<string name="suffix">Suffix</string>
<string name="phone_numbers">Phone numbers</string>
<string name="emails">Emails</string>
<string name="addresses">Addresses</string>
<string name="events">Events (birthdays, anniversaries)</string>
<string name="notes">Notes</string>
<string name="organization">Organization</string>
<string name="websites">Websites</string>
<string name="groups">Groups</string>
<string name="contact_source">Contact source</string>
<!-- FAQ -->
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Μια εφαρμογή επαφών για να διαχειρίζεσαι τις επαφές σου χωρίς διαφημίσεις.</string> <string name="app_short_description">Μια εφαρμογή επαφών για να διαχειρίζεσαι τις επαφές σου χωρίς διαφημίσεις.</string>

View File

@ -6,25 +6,28 @@
<string name="updating">Mise à jour…</string> <string name="updating">Mise à jour…</string>
<string name="phone_storage">Stockage du téléphone</string> <string name="phone_storage">Stockage du téléphone</string>
<string name="phone_storage_hidden">Stockage du téléphone (non visible par d\'autres applis)</string> <string name="phone_storage_hidden">Stockage du téléphone (non visible par d\'autres applis)</string>
<string name="company">Société</string>
<string name="job_position">Poste</string>
<string name="website">Website</string>
<string name="new_contact">Nouveau contact</string> <string name="new_contact">Nouveau contact</string>
<string name="edit_contact">Modifier contact</string> <string name="edit_contact">Modifier contact</string>
<string name="select_contact">Sélectionner un contact</string> <string name="select_contact">Sélectionner un contact</string>
<string name="select_contacts">Sélectionner des contacts</string> <string name="select_contacts">Sélectionner des contacts</string>
<string name="first_name">Prénom</string> <string name="first_name">Prénom</string>
<string name="middle_name">Nom</string> <string name="middle_name">Deuxième prénom</string>
<string name="surname">Surnom</string> <string name="surname">Nom</string>
<!-- Groups --> <!-- Groups -->
<string name="no_groups">No groups</string> <string name="no_groups">Pas de groupe</string>
<string name="create_new_group">Create a new group</string> <string name="create_new_group">Créer un nouveau groupe</string>
<string name="remove_from_group">Remove from group</string> <string name="remove_from_group">Enlever du groupe</string>
<string name="no_group_participants">This group is empty</string> <string name="no_group_participants">Ce groupe est vide</string>
<string name="add_contacts">Add contacts</string> <string name="add_contacts">Ajout contacts</string>
<string name="no_group_created">There are no contact groups on the device</string> <string name="no_group_created">Il n\'y a pas de groupes de contacts sur l\'appareil</string>
<string name="create_group">Create group</string> <string name="create_group">Créer un groupe</string>
<string name="add_to_group">Add to group</string> <string name="add_to_group">Ajouter à un groupe</string>
<string name="create_group_under_account">Create group under account</string> <string name="create_group_under_account">Créer un groupe pris en compte</string>
<!-- Photo --> <!-- Photo -->
<string name="take_photo">Prendre une photo</string> <string name="take_photo">Prendre une photo</string>
@ -32,14 +35,15 @@
<string name="remove_photo">Supprimer la photo</string> <string name="remove_photo">Supprimer la photo</string>
<!-- Settings --> <!-- Settings -->
<string name="start_name_with_surname">Commencer le nom par le surnom</string> <string name="start_name_with_surname">Commencer le nom par le nom de famille</string>
<string name="show_phone_numbers">Afficher les numéros de téléphone sur l\'écran principal</string> <string name="show_phone_numbers">Afficher les numéros de téléphone sur l\'écran principal</string>
<string name="show_contact_thumbnails">Afficher les vignettes des contacts</string> <string name="show_contact_thumbnails">Afficher les vignettes des contacts</string>
<string name="on_contact_click">Sur appui du contact</string> <string name="on_contact_click">Sur appui du contact</string>
<string name="call_contact">Appeler le contact</string> <string name="call_contact">Appeler le contact</string>
<string name="view_contact">Voir les détails du contact</string> <string name="view_contact">Voir les détails du contact</string>
<string name="show_favorites_tab">Show favorites tab</string> <string name="show_favorites_tab">Afficher l\'onglet favoris</string>
<string name="show_groups_tab">Show groups tab</string> <string name="show_groups_tab">Afficher l\'onglet groupes</string>
<string name="manage_shown_contact_fields">Configurer l\'affichage des champs de contact</string>
<!-- Emails --> <!-- Emails -->
<string name="email">E-mail</string> <string name="email">E-mail</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Inclure les sources du contact</string> <string name="include_contact_sources">Inclure les sources du contact</string>
<string name="filename_without_vcf">Nom du fichier (sans .vcf)</string> <string name="filename_without_vcf">Nom du fichier (sans .vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Sélectionner les champs à afficher</string>
<string name="prefix">Préfixe</string>
<string name="suffix">Suffixe</string>
<string name="phone_numbers">Numéros de téléphone</string>
<string name="emails">E-mails</string>
<string name="addresses">Adresses</string>
<string name="events">Évènements (naissances, anniversaires)</string>
<string name="notes">Notes</string>
<string name="organization">Organisation</string>
<string name="websites">Websites</string>
<string name="groups">Groupe</string>
<string name="contact_source">Source du contact</string>
<!-- FAQ -->
<string name="faq_1_title">Je veux changer quelles champs sont visibles. Est-ce que je peux ?</string>
<string name="faq_1_text">Oui, tout ce que vous avez à faire c\'est d\'aller dans Paramètres -> Configurer l\'affichage des champs de contact. Ici vous pouvez sélectionner quelles champs vous voulez afficher. Certains sont désactivés par défaut, ainsi vous pourrez y trouver des nouveaux champs.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Une appli de contacts pour gérer vos contacts sans pubs.</string> <string name="app_short_description">Une appli de contacts pour gérer vos contacts sans pubs.</string>

View File

@ -0,0 +1,121 @@
<resources>
<string name="app_name">Jednostavni kontakti</string>
<string name="app_launcher_name">Kontakti</string>
<string name="address">Adresa</string>
<string name="inserting">Dodavanje…</string>
<string name="updating">Ažuriranje…</string>
<string name="phone_storage">Pohrana na telefonu</string>
<string name="phone_storage_hidden">Pohrana na telefonu (nije vidljiva drugim aplikacijama))</string>
<string name="company">Company</string>
<string name="job_position">Job position</string>
<string name="website">Website</string>
<string name="new_contact">Novi kontakt</string>
<string name="edit_contact">Uredi kontakt</string>
<string name="select_contact">Odaberi kontakt</string>
<string name="select_contacts">Odaberi kontakte</string>
<string name="first_name">Ime</string>
<string name="middle_name">Srednje ime</string>
<string name="surname">Prezime</string>
<!-- Groups -->
<string name="no_groups">Nema grupa</string>
<string name="create_new_group">Stvori novu grupu</string>
<string name="remove_from_group">Ukloni iz grupe</string>
<string name="no_group_participants">Ova grupa je prazna</string>
<string name="add_contacts">Dodaj kontakte</string>
<string name="no_group_created">Na uređaju nema grupa kontakata</string>
<string name="create_group">Stvori grupu</string>
<string name="add_to_group">Dodaj u grupu</string>
<string name="create_group_under_account">Stvorite grupu pod računom</string>
<!-- Photo -->
<string name="take_photo">Uslikaj</string>
<string name="choose_photo">Odaberi fotografiju</string>
<string name="remove_photo">Ukloni fotografiju</string>
<!-- Settings -->
<string name="start_name_with_surname">Započnite imena s prezimenima</string>
<string name="show_phone_numbers">Prikaži telefonske brojeve na glavnom zaslonu</string>
<string name="show_contact_thumbnails">Prikaži sličice kontakata</string>
<string name="on_contact_click">Prilikom dodira kontakta</string>
<string name="call_contact">Nazovi kontakt</string>
<string name="view_contact">Prikaži pojedinosti o kontaktu</string>
<string name="show_favorites_tab">Prikaži karticu favorita</string>
<string name="show_groups_tab">Prikaži karticu grupa</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails -->
<string name="email">E-pošta</string>
<string name="home">Kućni</string>
<string name="work">Posao</string>
<string name="other">Ostalo</string>
<!-- Phone numbers -->
<string name="number">Broj</string>
<string name="mobile">Mobilni</string>
<string name="main_number">Glavni</string>
<string name="work_fax">Poslovni fax</string>
<string name="home_fax">Kućni fax</string>
<string name="pager">Pager</string>
<string name="no_phone_number_found">Nije pronađen nijedan telefonski broj</string>
<!-- Events -->
<string name="birthday">Rođendan</string>
<string name="anniversary">Obljetnica</string>
<!-- Favorites -->
<string name="no_favorites">Čini se da još niste dodali nijedan kontakt u favorite.</string>
<string name="add_favorites">Dodaj favorite</string>
<string name="add_to_favorites">Dodaj u favorite</string>
<string name="remove_from_favorites">Ukloni iz favorita</string>
<!-- Search -->
<string name="search_contacts">Pretraži kontakte</string>
<string name="search_favorites">Pretraži favorite</string>
<!-- Export / Import -->
<string name="import_contacts">Uvezi kontakte</string>
<string name="export_contacts">Izvezi kontakte</string>
<string name="import_contacts_from_vcf">Uvoz kontakata iz .vcf datoteke</string>
<string name="export_contacts_to_vcf">Izvoz kontakata u .vcf datoteku</string>
<string name="target_contact_source">Ciljani izvor kontakta</string>
<string name="include_contact_sources">Uključi izvore kontakta</string>
<string name="filename_without_vcf">Naziv datoteke (bez .vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Select fields to show</string>
<string name="prefix">Prefix</string>
<string name="suffix">Suffix</string>
<string name="phone_numbers">Phone numbers</string>
<string name="emails">Emails</string>
<string name="addresses">Addresses</string>
<string name="events">Events (birthdays, anniversaries)</string>
<string name="notes">Notes</string>
<string name="organization">Organization</string>
<string name="websites">Websites</string>
<string name="groups">Groups</string>
<string name="contact_source">Contact source</string>
<!-- FAQ -->
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Aplikacija za upravljanje kontaktima bez oglasa.</string>
<string name="app_long_description">
Jednostavna aplikacija za izradu ili upravljanje kontaktima iz bilo kojeg izvora. Kontakti mogu biti pohranjeni samo na Vašem uređaju, ali i sinkronizirani putem Googlea ili drugih računa. Možete prikazati svoje omiljene kontakte na zasebnom popisu.
Možete ju koristiti za upravljanje e-poštom i događajima. Ima mogućnost sortirati/filtrirati višestrukim parametrima, po želji može prikazati prezime prvo, zatim ime.
Ne sadrži oglase ili nepotrebne dozvole. Aplikacije je otvorenog koda, pruža prilagodljive boje.
Ova je aplikacija samo dio većeg broja aplikacija. Možete pronaći ostatak na http://www.simplemobiletools.com
</string>
<!--
Haven't found some strings? There's more at
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
-->
</resources>

View File

@ -6,6 +6,9 @@
<string name="updating">수정중…</string> <string name="updating">수정중…</string>
<string name="phone_storage">Phone storage</string> <string name="phone_storage">Phone storage</string>
<string name="phone_storage_hidden">Phone storage (not visible by other apps)</string> <string name="phone_storage_hidden">Phone storage (not visible by other apps)</string>
<string name="company">Company</string>
<string name="job_position">Job position</string>
<string name="website">Website</string>
<string name="new_contact">새로운 연락처</string> <string name="new_contact">새로운 연락처</string>
<string name="edit_contact">연락처 수정</string> <string name="edit_contact">연락처 수정</string>
@ -40,6 +43,7 @@
<string name="view_contact">View contact details</string> <string name="view_contact">View contact details</string>
<string name="show_favorites_tab">Show favorites tab</string> <string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string> <string name="show_groups_tab">Show groups tab</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails --> <!-- Emails -->
<string name="email">이메일</string> <string name="email">이메일</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">가져오기 대상</string> <string name="include_contact_sources">가져오기 대상</string>
<string name="filename_without_vcf">파일이름 (.vcf 확장자 생략)</string> <string name="filename_without_vcf">파일이름 (.vcf 확장자 생략)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Select fields to show</string>
<string name="prefix">Prefix</string>
<string name="suffix">Suffix</string>
<string name="phone_numbers">Phone numbers</string>
<string name="emails">Emails</string>
<string name="addresses">Addresses</string>
<string name="events">Events (birthdays, anniversaries)</string>
<string name="notes">Notes</string>
<string name="organization">Organization</string>
<string name="websites">Websites</string>
<string name="groups">Groups</string>
<string name="contact_source">Contact source</string>
<!-- FAQ -->
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">광고가 없는 연락처 관리 애플리케이션입니다.</string> <string name="app_short_description">광고가 없는 연락처 관리 애플리케이션입니다.</string>

View File

@ -6,6 +6,9 @@
<string name="updating">Atnaujinama…</string> <string name="updating">Atnaujinama…</string>
<string name="phone_storage">Telefono atmintis</string> <string name="phone_storage">Telefono atmintis</string>
<string name="phone_storage_hidden">Telefono atmintis (nematoma kitų programėlių)</string> <string name="phone_storage_hidden">Telefono atmintis (nematoma kitų programėlių)</string>
<string name="company">Company</string>
<string name="job_position">Job position</string>
<string name="website">Website</string>
<string name="new_contact">Naujas kontaktas</string> <string name="new_contact">Naujas kontaktas</string>
<string name="edit_contact">Redaguoti kontaktą</string> <string name="edit_contact">Redaguoti kontaktą</string>
@ -18,13 +21,13 @@
<!-- Groups --> <!-- Groups -->
<string name="no_groups">Nėra grupių</string> <string name="no_groups">Nėra grupių</string>
<string name="create_new_group">Sukurti naują grupę</string> <string name="create_new_group">Sukurti naują grupę</string>
<string name="remove_from_group">Remove from group</string> <string name="remove_from_group">Pašalinti iš grupės</string>
<string name="no_group_participants">This group is empty</string> <string name="no_group_participants">Ši grupė tuščia</string>
<string name="add_contacts">Add contacts</string> <string name="add_contacts">Įtraukti kontaktus</string>
<string name="no_group_created">There are no contact groups on the device</string> <string name="no_group_created">Šiame įrenginyje nėra kontaktų grup</string>
<string name="create_group">Create group</string> <string name="create_group">Sukurti grupę</string>
<string name="add_to_group">Add to group</string> <string name="add_to_group">Įtraukti į grupę</string>
<string name="create_group_under_account">Create group under account</string> <string name="create_group_under_account">Sukurti grupę paskyroje</string>
<!-- Photo --> <!-- Photo -->
<string name="take_photo">Nufotografuoti</string> <string name="take_photo">Nufotografuoti</string>
@ -40,6 +43,7 @@
<string name="view_contact">Žiūrėti kontakto detales</string> <string name="view_contact">Žiūrėti kontakto detales</string>
<string name="show_favorites_tab">Rodyti mėgiamiausiųjų skirtuką</string> <string name="show_favorites_tab">Rodyti mėgiamiausiųjų skirtuką</string>
<string name="show_groups_tab">Rodyti grupių skirtuką</string> <string name="show_groups_tab">Rodyti grupių skirtuką</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails --> <!-- Emails -->
<string name="email">Elektroninis paštas</string> <string name="email">Elektroninis paštas</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Įtraukti kontaktų šaltinius</string> <string name="include_contact_sources">Įtraukti kontaktų šaltinius</string>
<string name="filename_without_vcf">Bylos vardas (be .vcf)</string> <string name="filename_without_vcf">Bylos vardas (be .vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Select fields to show</string>
<string name="prefix">Prefix</string>
<string name="suffix">Suffix</string>
<string name="phone_numbers">Phone numbers</string>
<string name="emails">Emails</string>
<string name="addresses">Addresses</string>
<string name="events">Events (birthdays, anniversaries)</string>
<string name="notes">Notes</string>
<string name="organization">Organization</string>
<string name="websites">Websites</string>
<string name="groups">Groups</string>
<string name="contact_source">Contact source</string>
<!-- FAQ -->
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Kontaktų programėlė įrenginio kontaktų tvarkymui, be reklamų.</string> <string name="app_short_description">Kontaktų programėlė įrenginio kontaktų tvarkymui, be reklamų.</string>

View File

@ -1,11 +1,14 @@
<resources> <resources>
<string name="app_name">Simple Contacts</string> <string name="app_name">Simple Contacts</string>
<string name="app_launcher_name">Contactos</string> <string name="app_launcher_name">Contactos</string>
<string name="address">Enederço</string> <string name="address">Endereço</string>
<string name="inserting">A inserir…</string> <string name="inserting">A inserir…</string>
<string name="updating">A atualizar…</string> <string name="updating">A atualizar…</string>
<string name="phone_storage">Armazenamento do telefone</string> <string name="phone_storage">Armazenamento do telefone</string>
<string name="phone_storage_hidden">Armazenamento do telefone (não visível por outras alicações)</string> <string name="phone_storage_hidden">Armazenamento do telefone (não visível por outras alicações)</string>
<string name="company">Organização</string>
<string name="job_position">Cargo</string>
<string name="website">Website</string>
<string name="new_contact">Novo contacto</string> <string name="new_contact">Novo contacto</string>
<string name="edit_contact">Editar contacto</string> <string name="edit_contact">Editar contacto</string>
@ -16,15 +19,15 @@
<string name="surname">Apelido</string> <string name="surname">Apelido</string>
<!-- Groups --> <!-- Groups -->
<string name="no_groups">No groups</string> <string name="no_groups">Não grupos</string>
<string name="create_new_group">Create a new group</string> <string name="create_new_group">Criar um novo grupo</string>
<string name="remove_from_group">Remove from group</string> <string name="remove_from_group">Remover do grupo</string>
<string name="no_group_participants">This group is empty</string> <string name="no_group_participants">Este grupo está vazio</string>
<string name="add_contacts">Add contacts</string> <string name="add_contacts">Adicionar contactos</string>
<string name="no_group_created">There are no contact groups on the device</string> <string name="no_group_created">Não existem grupos de contactos neste dispositivo</string>
<string name="create_group">Create group</string> <string name="create_group">Criar um grupo</string>
<string name="add_to_group">Add to group</string> <string name="add_to_group">Adicionar ao grupo</string>
<string name="create_group_under_account">Create group under account</string> <string name="create_group_under_account">Criar grupo para a conta</string>
<!-- Photo --> <!-- Photo -->
<string name="take_photo">Tirar foto</string> <string name="take_photo">Tirar foto</string>
@ -38,8 +41,9 @@
<string name="on_contact_click">Ao clicar no contacto</string> <string name="on_contact_click">Ao clicar no contacto</string>
<string name="call_contact">Ligar</string> <string name="call_contact">Ligar</string>
<string name="view_contact">Ver detalhes</string> <string name="view_contact">Ver detalhes</string>
<string name="show_favorites_tab">Show favorites tab</string> <string name="show_favorites_tab">Mostrar favoritos</string>
<string name="show_groups_tab">Show groups tab</string> <string name="show_groups_tab">Mostrar grupos</string>
<string name="manage_shown_contact_fields">Gerir campos a exibir</string>
<!-- Emails --> <!-- Emails -->
<string name="email">E-mail</string> <string name="email">E-mail</string>
@ -79,17 +83,35 @@
<string name="include_contact_sources">Incluir fontes dos contactos</string> <string name="include_contact_sources">Incluir fontes dos contactos</string>
<string name="filename_without_vcf">Nome do ficheiro (sem .vcf)</string> <string name="filename_without_vcf">Nome do ficheiro (sem .vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Selecione os campos a mostrar</string>
<string name="prefix">Prefixo</string>
<string name="suffix">Sufixo</string>
<string name="phone_numbers">Número de telefone</string>
<string name="emails">E-mail</string>
<string name="addresses">Endereço</string>
<string name="events">Eventos (data de nascimento, aniversário)</string>
<string name="notes">Notas</string>
<string name="organization">Organização</string>
<string name="websites">Websites</string>
<string name="groups">Grupos</string>
<string name="contact_source">Fonte do contacto</string>
<!-- FAQ -->
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">A contacts app for managing your contacts without ads.</string> <string name="app_short_description">Uma aplicação para gerir os seus contactos.</string>
<string name="app_long_description"> <string name="app_long_description">
A simple app for creating or managing your contacts from any source. The contacts can be stored on your device only, but also synchronized via Google, or other accounts. You can display your favorite contacts on a separate list. Uma aplicação básica para criar e gerir contactos. Pode utilizar a aplicação guardar os contactos localmente, na sua conta Google ou em outro tipo de contas. Pode mostrar os contactos favoritos numa lista distinta.
You can use it for managing user emails and events too. It has the ability to sort/filter by multiple parameters, optionally display surname as the first name. Também pode utilizar a aplicação para gerir endereços de e-mail e eventos. Tem a capacidade de ordenar/filtrar por diversos parâmetros e também a possibilidade de diversas formas de exibição dos contactos.
Contains no ads or unnecessary permissions. It is fully opensource, provides customizable colors. Não contém anúncios ou permissões desnecessárias. É totalmente open source e permite personalização de cores.
This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com Esta aplicação é apenas parte de um conjunto mais vasto de aplicações. Saiba mais em http://www.simplemobiletools.com
</string> </string>
<!-- <!--

View File

@ -6,6 +6,9 @@
<string name="updating">Обновление…</string> <string name="updating">Обновление…</string>
<string name="phone_storage">Память устройства</string> <string name="phone_storage">Память устройства</string>
<string name="phone_storage_hidden">Память устройства (не видна другим приложениям)</string> <string name="phone_storage_hidden">Память устройства (не видна другим приложениям)</string>
<string name="company">Company</string>
<string name="job_position">Job position</string>
<string name="website">Website</string>
<string name="new_contact">Новый контакт</string> <string name="new_contact">Новый контакт</string>
<string name="edit_contact">Редактировать контакт</string> <string name="edit_contact">Редактировать контакт</string>
@ -40,6 +43,7 @@
<string name="view_contact">Просмотреть подробности о контакте</string> <string name="view_contact">Просмотреть подробности о контакте</string>
<string name="show_favorites_tab">Показывать вкладку избранного</string> <string name="show_favorites_tab">Показывать вкладку избранного</string>
<string name="show_groups_tab">Показывать вкладку групп</string> <string name="show_groups_tab">Показывать вкладку групп</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails --> <!-- Emails -->
<string name="email">Эл. почта</string> <string name="email">Эл. почта</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Включить источники контактов</string> <string name="include_contact_sources">Включить источники контактов</string>
<string name="filename_without_vcf">Имя файла (без .vcf)</string> <string name="filename_without_vcf">Имя файла (без .vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Select fields to show</string>
<string name="prefix">Prefix</string>
<string name="suffix">Suffix</string>
<string name="phone_numbers">Phone numbers</string>
<string name="emails">Emails</string>
<string name="addresses">Addresses</string>
<string name="events">Events (birthdays, anniversaries)</string>
<string name="notes">Notes</string>
<string name="organization">Organization</string>
<string name="websites">Websites</string>
<string name="groups">Groups</string>
<string name="contact_source">Contact source</string>
<!-- FAQ -->
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Приложение для управления контактами без рекламы.</string> <string name="app_short_description">Приложение для управления контактами без рекламы.</string>

View File

@ -6,6 +6,9 @@
<string name="updating">Upravuje sa…</string> <string name="updating">Upravuje sa…</string>
<string name="phone_storage">Úložisko mobilu</string> <string name="phone_storage">Úložisko mobilu</string>
<string name="phone_storage_hidden">Úložisko mobilu (neviditeľné pre ostatné apky)</string> <string name="phone_storage_hidden">Úložisko mobilu (neviditeľné pre ostatné apky)</string>
<string name="company">Firma</string>
<string name="job_position">Pracovná pozícia</string>
<string name="website">Website</string>
<string name="new_contact">Nový kontakt</string> <string name="new_contact">Nový kontakt</string>
<string name="edit_contact">Upraviť kontakt</string> <string name="edit_contact">Upraviť kontakt</string>
@ -40,6 +43,7 @@
<string name="view_contact">Zobraziť údaje kontaktu</string> <string name="view_contact">Zobraziť údaje kontaktu</string>
<string name="show_favorites_tab">Zobraziť okno s obľúbenými</string> <string name="show_favorites_tab">Zobraziť okno s obľúbenými</string>
<string name="show_groups_tab">Zobraziť okno so skupinami</string> <string name="show_groups_tab">Zobraziť okno so skupinami</string>
<string name="manage_shown_contact_fields">Spravovať zobrazené polia kontaktov</string>
<!-- Emails --> <!-- Emails -->
<string name="email">Email</string> <string name="email">Email</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Zahrnúť zdroje kontaktov</string> <string name="include_contact_sources">Zahrnúť zdroje kontaktov</string>
<string name="filename_without_vcf">Názov súboru (bez .vcf)</string> <string name="filename_without_vcf">Názov súboru (bez .vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Zvoľte polia na zobrazenie</string>
<string name="prefix">Titul pred menom</string>
<string name="suffix">Titul za priezviskom</string>
<string name="phone_numbers">Telefónne čísla</string>
<string name="emails">Emaily</string>
<string name="addresses">Adresy</string>
<string name="events">Udalosti (narodeniny, výročia)</string>
<string name="notes">Poznámky</string>
<string name="organization">Firma</string>
<string name="websites">Webstránky</string>
<string name="groups">Skupiny</string>
<string name="contact_source">Zdroje kontaktov</string>
<!-- FAQ -->
<string name="faq_1_title">Chcem upraviť viditeľné polia kontaktov. Dá sa to?</string>
<string name="faq_1_text">Áno, stačí ísť do Nastavenia -> Spravovať zobrazené polia kontaktov. Tam si viete zvoliť, ktoré polia majú byť viditeľné. Niektoré sú v predvolenom stave vypnuté, čiže tam môžete objaviť aj nové.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Aplikácia pre správu vašich kontaktov bez reklám.</string> <string name="app_short_description">Aplikácia pre správu vašich kontaktov bez reklám.</string>

View File

@ -6,6 +6,9 @@
<string name="updating">Uppdaterar…</string> <string name="updating">Uppdaterar…</string>
<string name="phone_storage">Telefonens lagringsutrymme</string> <string name="phone_storage">Telefonens lagringsutrymme</string>
<string name="phone_storage_hidden">Telefonens lagringsutrymme (inte synligt för andra appar)</string> <string name="phone_storage_hidden">Telefonens lagringsutrymme (inte synligt för andra appar)</string>
<string name="company">Company</string>
<string name="job_position">Job position</string>
<string name="website">Website</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>
@ -16,15 +19,15 @@
<string name="surname">Efternamn</string> <string name="surname">Efternamn</string>
<!-- Groups --> <!-- Groups -->
<string name="no_groups">No groups</string> <string name="no_groups">Inga grupper</string>
<string name="create_new_group">Create a new group</string> <string name="create_new_group">Skapa en ny grupp</string>
<string name="remove_from_group">Remove from group</string> <string name="remove_from_group">Ta bort från grupp</string>
<string name="no_group_participants">This group is empty</string> <string name="no_group_participants">Denna grupp är tom</string>
<string name="add_contacts">Add contacts</string> <string name="add_contacts">Lägg till kontakter</string>
<string name="no_group_created">There are no contact groups on the device</string> <string name="no_group_created">Det finns inga kontaktgrupper på enheten</string>
<string name="create_group">Create group</string> <string name="create_group">Skapa grupp</string>
<string name="add_to_group">Add to group</string> <string name="add_to_group">Lägg till i grupp</string>
<string name="create_group_under_account">Create group under account</string> <string name="create_group_under_account">Skapa gruppen i kontot</string>
<!-- Photo --> <!-- Photo -->
<string name="take_photo">Ta foto</string> <string name="take_photo">Ta foto</string>
@ -38,8 +41,9 @@
<string name="on_contact_click">Vid kontakttryckning</string> <string name="on_contact_click">Vid kontakttryckning</string>
<string name="call_contact">Ring kontakt</string> <string name="call_contact">Ring kontakt</string>
<string name="view_contact">Visa kontaktuppgifter</string> <string name="view_contact">Visa kontaktuppgifter</string>
<string name="show_favorites_tab">Show favorites tab</string> <string name="show_favorites_tab">Visa fliken Favoriter</string>
<string name="show_groups_tab">Show groups tab</string> <string name="show_groups_tab">Visa fliken Grupper</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails --> <!-- Emails -->
<string name="email">E-post</string> <string name="email">E-post</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Inkludera kontaktkällor</string> <string name="include_contact_sources">Inkludera kontaktkällor</string>
<string name="filename_without_vcf">Filnamn (utan .vcf)</string> <string name="filename_without_vcf">Filnamn (utan .vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Select fields to show</string>
<string name="prefix">Prefix</string>
<string name="suffix">Suffix</string>
<string name="phone_numbers">Phone numbers</string>
<string name="emails">Emails</string>
<string name="addresses">Addresses</string>
<string name="events">Events (birthdays, anniversaries)</string>
<string name="notes">Notes</string>
<string name="organization">Organization</string>
<string name="websites">Websites</string>
<string name="groups">Groups</string>
<string name="contact_source">Contact source</string>
<!-- FAQ -->
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">En app för att hantera dina kontakter utan reklam.</string> <string name="app_short_description">En app för att hantera dina kontakter utan reklam.</string>

View File

@ -6,6 +6,9 @@
<string name="updating">更新中…</string> <string name="updating">更新中…</string>
<string name="phone_storage">手機空間</string> <string name="phone_storage">手機空間</string>
<string name="phone_storage_hidden">手機空間 (其他程式不可見)</string> <string name="phone_storage_hidden">手機空間 (其他程式不可見)</string>
<string name="company">公司</string>
<string name="job_position">職位</string>
<string name="website">Website</string>
<string name="new_contact">新聯絡人</string> <string name="new_contact">新聯絡人</string>
<string name="edit_contact">編輯聯絡人</string> <string name="edit_contact">編輯聯絡人</string>
@ -24,7 +27,7 @@
<string name="no_group_created">裝置內沒有聯絡人群組</string> <string name="no_group_created">裝置內沒有聯絡人群組</string>
<string name="create_group">建立群組</string> <string name="create_group">建立群組</string>
<string name="add_to_group">添加到群組</string> <string name="add_to_group">添加到群組</string>
<string name="create_group_under_account">Create group under account</string> <string name="create_group_under_account">在帳號下建立群組</string>
<!-- Photo --> <!-- Photo -->
<string name="take_photo">拍照</string> <string name="take_photo">拍照</string>
@ -40,9 +43,10 @@
<string name="view_contact">顯示聯絡人資料</string> <string name="view_contact">顯示聯絡人資料</string>
<string name="show_favorites_tab">顯示我的最愛頁面</string> <string name="show_favorites_tab">顯示我的最愛頁面</string>
<string name="show_groups_tab">顯示群組頁面</string> <string name="show_groups_tab">顯示群組頁面</string>
<string name="manage_shown_contact_fields">管理顯示的聯絡人欄位</string>
<!-- Emails --> <!-- Emails -->
<string name="email">信箱</string> <string name="email">電子信箱</string>
<string name="home">住家</string> <string name="home">住家</string>
<string name="work">工作</string> <string name="work">工作</string>
<string name="other">其它</string> <string name="other">其它</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">包含聯絡人來源</string> <string name="include_contact_sources">包含聯絡人來源</string>
<string name="filename_without_vcf">檔案名稱 (不含.vcf)</string> <string name="filename_without_vcf">檔案名稱 (不含.vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">選擇要顯示的欄位</string>
<string name="prefix">前缀</string>
<string name="suffix">後綴</string>
<string name="phone_numbers">電話號碼</string>
<string name="emails">電子信箱</string>
<string name="addresses">地址</string>
<string name="events">活動 (生日、紀念日)</string>
<string name="notes">筆記</string>
<string name="organization">組織</string>
<string name="websites">Websites</string>
<string name="groups">群組</string>
<string name="contact_source">聯絡人來源</string>
<!-- FAQ -->
<string name="faq_1_title">我想要更改在通訊錄會看到哪些欄位。我能這麼做嗎?</string>
<string name="faq_1_text">可以,你要做的是到[設定] -> [管理顯示的聯絡人欄位]。在那裡,你可以選擇應該看到什麼欄位。其中有些甚至預設是關閉的,所以你可能會在那裡發現一些新的。</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">一個用來管理聯絡人,且沒有廣告的通訊錄應用程式。</string> <string name="app_short_description">一個用來管理聯絡人,且沒有廣告的通訊錄應用程式。</string>

View File

@ -2,6 +2,10 @@
<resources> <resources>
<!-- Release notes --> <!-- Release notes -->
<string name="release_16">
Added name prefix/suffix and contact organizations\n
Added a settings item \"Manage shown contact fields\" for customizing visible contact details, with some fields disabled by default
</string>
<string name="release_11">Added Address and Notes fields</string> <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> <string name="release_10">Allow storing contacts in a local database, hidden from other apps</string>

View File

@ -6,6 +6,9 @@
<string name="updating">Updating…</string> <string name="updating">Updating…</string>
<string name="phone_storage">Phone storage</string> <string name="phone_storage">Phone storage</string>
<string name="phone_storage_hidden">Phone storage (not visible by other apps)</string> <string name="phone_storage_hidden">Phone storage (not visible by other apps)</string>
<string name="company">Company</string>
<string name="job_position">Job position</string>
<string name="website">Website</string>
<string name="new_contact">New contact</string> <string name="new_contact">New contact</string>
<string name="edit_contact">Edit contact</string> <string name="edit_contact">Edit contact</string>
@ -40,6 +43,7 @@
<string name="view_contact">View contact details</string> <string name="view_contact">View contact details</string>
<string name="show_favorites_tab">Show favorites tab</string> <string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string> <string name="show_groups_tab">Show groups tab</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails --> <!-- Emails -->
<string name="email">Email</string> <string name="email">Email</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Include contact sources</string> <string name="include_contact_sources">Include contact sources</string>
<string name="filename_without_vcf">Filename (without .vcf)</string> <string name="filename_without_vcf">Filename (without .vcf)</string>
<!-- Visible fields -->
<string name="select_fields_to_show">Select fields to show</string>
<string name="prefix">Prefix</string>
<string name="suffix">Suffix</string>
<string name="phone_numbers">Phone numbers</string>
<string name="emails">Emails</string>
<string name="addresses">Addresses</string>
<string name="events">Events (birthdays, anniversaries)</string>
<string name="notes">Notes</string>
<string name="organization">Organization</string>
<string name="websites">Websites</string>
<string name="groups">Groups</string>
<string name="contact_source">Contact source</string>
<!-- FAQ -->
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">A contacts app for managing your contacts without ads.</string> <string name="app_short_description">A contacts app for managing your contacts without ads.</string>

View File

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.2.30' ext.kotlin_version = '1.2.31'
repositories { repositories {
google() google()
@ -9,7 +9,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.0.1' classpath 'com.android.tools.build:gradle:3.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong