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
commit b852a477c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 1822 additions and 555 deletions

View File

@ -1,6 +1,21 @@
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)*
----------------------------

View File

@ -10,8 +10,8 @@ android {
applicationId "com.simplemobiletools.contacts"
minSdkVersion 16
targetSdkVersion 27
versionCode 15
versionName "3.4.0"
versionCode 17
versionName "3.5.1"
setProperty("archivesBaseName", "contacts")
}
@ -45,10 +45,9 @@ ext {
}
dependencies {
implementation 'com.simplemobiletools:commons:3.16.12'
implementation 'com.simplemobiletools:commons:3.18.23'
implementation 'joda-time:joda-time:2.9.9'
implementation 'com.facebook.stetho:stetho:1.5.0'
implementation 'com.google.code.gson:gson:2.8.2'
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"

View File

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

View File

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

View File

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

View File

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

View File

@ -4,9 +4,9 @@ import android.os.Bundle
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.updateTextColors
import com.simplemobiletools.commons.extensions.useEnglishToggled
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.dialogs.ManageVisibleFieldsDialog
import com.simplemobiletools.contacts.extensions.config
import com.simplemobiletools.contacts.helpers.ON_CLICK_CALL_CONTACT
import com.simplemobiletools.contacts.helpers.ON_CLICK_EDIT_CONTACT
@ -24,6 +24,7 @@ class SettingsActivity : SimpleActivity() {
super.onResume()
setupCustomizeColors()
setupManageShownContactFields()
setupUseEnglish()
setupAvoidWhatsNew()
setupShowInfoBubble()
@ -40,13 +41,19 @@ class SettingsActivity : SimpleActivity() {
}
}
private fun setupManageShownContactFields() {
settings_manage_contact_fields_holder.setOnClickListener {
ManageVisibleFieldsDialog(this)
}
}
private fun setupUseEnglish() {
settings_use_english_holder.beVisibleIf(config.wasUseEnglishToggled || Locale.getDefault().language != "en")
settings_use_english.isChecked = config.useEnglish
settings_use_english_holder.setOnClickListener {
settings_use_english.toggle()
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.contacts.R
import com.simplemobiletools.contacts.extensions.*
import com.simplemobiletools.contacts.helpers.CONTACT_ID
import com.simplemobiletools.contacts.helpers.ContactsHelper
import com.simplemobiletools.contacts.helpers.IS_PRIVATE
import com.simplemobiletools.contacts.helpers.*
import kotlinx.android.synthetic.main.activity_view_contact.*
import kotlinx.android.synthetic.main.item_event.view.*
import kotlinx.android.synthetic.main.item_view_address.view.*
import kotlinx.android.synthetic.main.item_view_email.view.*
import kotlinx.android.synthetic.main.item_view_group.view.*
import kotlinx.android.synthetic.main.item_view_phone_number.view.*
import kotlinx.android.synthetic.main.item_website.view.*
class ViewContactActivity : ContactActivity() {
private var isViewIntent = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_contact)
showFields = config.showContactFields
}
override fun 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 {
@ -48,22 +62,10 @@ class ViewContactActivity : ContactActivity() {
return true
}
private fun tryInitContact() {
handlePermission(PERMISSION_READ_CONTACTS) {
if (it) {
initContact()
} else {
toast(R.string.no_contacts_permission)
finish()
}
}
}
private fun initContact() {
var wasLookupKeyUsed = false
var contactId = intent.getIntExtra(CONTACT_ID, 0)
val action = intent.action
if (contactId == 0 && (action == ContactsContract.QuickContact.ACTION_QUICK_CONTACT || action == Intent.ACTION_VIEW)) {
if (contactId == 0 && isViewIntent) {
val data = intent.data
if (data != null) {
val rawId = if (data.path.contains("lookup")) {
@ -117,11 +119,13 @@ class ViewContactActivity : ContactActivity() {
contact_start_call.applyColorFilter(textColor)
contact_send_email.applyColorFilter(textColor)
contact_name_image.applyColorFilter(textColor)
contact_number_image.applyColorFilter(textColor)
contact_email_image.applyColorFilter(textColor)
contact_event_image.applyColorFilter(textColor)
contact_numbers_image.applyColorFilter(textColor)
contact_emails_image.applyColorFilter(textColor)
contact_events_image.applyColorFilter(textColor)
contact_source_image.applyColorFilter(textColor)
contact_notes_image.applyColorFilter(textColor)
contact_organization_image.applyColorFilter(textColor)
contact_websites_image.applyColorFilter(textColor)
contact_groups_image.applyColorFilter(textColor)
contact_send_sms.setOnClickListener { trySendSMS() }
@ -134,135 +138,223 @@ class ViewContactActivity : ContactActivity() {
private fun setupViewContact() {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
contact!!.apply {
contact_first_name.text = firstName
contact_first_name.beVisibleIf(firstName.isNotEmpty())
contact_middle_name.text = middleName
contact_middle_name.beVisibleIf(middleName.isNotEmpty())
contact_surname.text = surname
contact_surname.beVisibleIf(surname.isNotEmpty())
if (firstName.isEmpty() && middleName.isEmpty() && surname.isEmpty()) {
contact_name_image.beInvisible()
(contact_photo.layoutParams as RelativeLayout.LayoutParams).bottomMargin = resources.getDimension(R.dimen.medium_margin).toInt()
}
contact_source.text = getPublicContactSource(source)
}
setupFavorite()
setupNames()
setupPhoneNumbers()
setupEmails()
setupAddresses()
setupEvents()
setupNotes()
setupOrganization()
setupWebsites()
setupGroups()
setupContactSource()
}
private fun setupFavorite() {
contact_toggle_favorite.apply {
beVisible()
setImageDrawable(getStarDrawable(contact!!.starred == 1))
tag = contact!!.starred
applyColorFilter(config.textColor)
}
}
setupPhoneNumbers()
setupEmails()
setupAddresses()
setupEvents()
setupNotes()
setupGroups()
private fun setupNames() {
contact!!.apply {
contact_prefix.text = prefix
contact_prefix.beVisibleIf(prefix.isNotEmpty() && showFields and SHOW_PREFIX_FIELD != 0)
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() {
contact_numbers_holder.removeAllViews()
val phoneNumbers = contact!!.phoneNumbers
phoneNumbers.forEach {
layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false).apply {
val phoneNumber = it
contact_numbers_holder.addView(this)
contact_number.text = phoneNumber.value
contact_number_type.setText(getPhoneNumberTextId(phoneNumber.type))
if (phoneNumbers.isNotEmpty() && showFields and SHOW_PHONE_NUMBERS_FIELD != 0) {
phoneNumbers.forEach {
layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false).apply {
val phoneNumber = it
contact_numbers_holder.addView(this)
contact_number.text = phoneNumber.value
contact_number_type.setText(getPhoneNumberTextId(phoneNumber.type))
setOnClickListener {
startCallIntent(phoneNumber.value)
setOnClickListener {
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() {
contact_emails_holder.removeAllViews()
val emails = contact!!.emails
emails.forEach {
layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false).apply {
val email = it
contact_emails_holder.addView(this)
contact_email.text = email.value
contact_email_type.setText(getEmailTextId(email.type))
if (emails.isNotEmpty() && showFields and SHOW_EMAILS_FIELD != 0) {
emails.forEach {
layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false).apply {
val email = it
contact_emails_holder.addView(this)
contact_email.text = email.value
contact_email_type.setText(getEmailTextId(email.type))
setOnClickListener {
sendEmailIntent(email.value)
setOnClickListener {
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() {
contact_addresses_holder.removeAllViews()
val addresses = contact!!.addresses
addresses.forEach {
layoutInflater.inflate(R.layout.item_view_address, contact_addresses_holder, false).apply {
val address = it
contact_addresses_holder.addView(this)
contact_address.text = address.value
contact_address_type.setText(getAddressTextId(address.type))
if (addresses.isNotEmpty() && showFields and SHOW_ADDRESSES_FIELD != 0) {
addresses.forEach {
layoutInflater.inflate(R.layout.item_view_address, contact_addresses_holder, false).apply {
val address = it
contact_addresses_holder.addView(this)
contact_address.text = address.value
contact_address_type.setText(getAddressTextId(address.type))
setOnClickListener {
sendAddressIntent(address.value)
setOnClickListener {
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() {
contact_events_holder.removeAllViews()
val events = contact!!.events
events.forEach {
layoutInflater.inflate(R.layout.item_event, contact_events_holder, false).apply {
contact_events_holder.addView(this)
contact_event.alpha = 1f
getDateTime(it.value, contact_event)
contact_event_type.setText(getEventTextId(it.type))
contact_event_remove.beGone()
if (events.isNotEmpty() && showFields and SHOW_EVENTS_FIELD != 0) {
events.forEach {
layoutInflater.inflate(R.layout.item_event, contact_events_holder, false).apply {
contact_events_holder.addView(this)
contact_event.alpha = 1f
getDateTime(it.value, contact_event)
contact_event_type.setText(getEventTextId(it.type))
contact_event_remove.beGone()
}
}
contact_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() {
val notes = contact!!.notes
contact_notes.text = notes
contact_notes_image.beVisibleIf(notes.isNotEmpty())
contact_notes.beVisibleIf(notes.isNotEmpty())
if (notes.isNotEmpty() && showFields and SHOW_NOTES_FIELD != 0) {
contact_notes.text = notes
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() {
contact_groups_holder.removeAllViews()
val groups = contact!!.groups
groups.forEach {
layoutInflater.inflate(R.layout.item_view_group, contact_groups_holder, false).apply {
val group = it
contact_groups_holder.addView(this)
contact_group.text = group.title
if (groups.isNotEmpty() && showFields and SHOW_GROUPS_FIELD != 0) {
groups.forEach {
layoutInflater.inflate(R.layout.item_view_group, contact_groups_holder, false).apply {
val group = it
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())
contact_groups_holder.beVisibleIf(groups.isNotEmpty())
private fun setupContactSource() {
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)

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()
init {
setupDragListener(true)
initDrawables()
showContactThumbnails = config.showContactThumbnails
showPhoneNumbers = config.showPhoneNumbers
@ -220,10 +221,8 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
contactsIDs.add(contactItems[it].id)
}
ContactsHelper(activity).getContacts {
val filtered = it.filter { contactsIDs.contains(it.id) } as ArrayList<Contact>
activity.shareContacts(filtered)
}
val filtered = contactItems.filter { contactsIDs.contains(it.id) } as ArrayList<Contact>
activity.shareContacts(filtered)
}
override fun onViewRecycled(holder: ViewHolder) {
@ -235,7 +234,7 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
private fun setupView(view: View, contact: Contact) {
view.apply {
contact_name.text = contact.getFullName(startNameWithSurname)
contact_name.text = contact.getFullName()
contact_name.setTextColor(textColor)
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,
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 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

View File

@ -30,7 +30,6 @@ class SelectContactsAdapter(val activity: SimpleActivity, val contacts: List<Con
private val config = activity.config
private val textColor = config.textColor
private val contactDrawable = activity.resources.getColoredDrawableWithColor(R.drawable.ic_person, textColor)
private val startNameWithSurname = config.startNameWithSurname
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
@ -80,7 +79,7 @@ class SelectContactsAdapter(val activity: SimpleActivity, val contacts: List<Con
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
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)
}
@ -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,
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 {
itemView.apply {
contact_checkbox.beVisibleIf(showCheckbox)
contact_checkbox.setColors(config.textColor, context.getAdjustedPrimaryColor(), config.backgroundColor)
val textColor = config.textColor
contact_name.text = contact.getFullName(startNameWithSurname)
contact_name.text = contact.getFullName()
contact_name.setTextColor(textColor)
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.startWithSurname = activity.config.startNameWithSurname
allContacts.sort()
activity.runOnUiThread {

View File

@ -20,14 +20,13 @@ import java.io.File
fun SimpleActivity.startCallIntent(recipient: String) {
handlePermission(PERMISSION_CALL_PHONE) {
if (it) {
Intent(Intent.ACTION_CALL).apply {
data = Uri.fromParts("tel", recipient, null)
if (resolveActivity(packageManager) != null) {
startActivity(this)
} else {
toast(R.string.no_app_found)
}
val action = if (it) Intent.ACTION_CALL else Intent.ACTION_DIAL
Intent(action).apply {
data = Uri.fromParts("tel", recipient, null)
if (resolveActivity(packageManager) != null) {
startActivity(this)
} else {
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) {
val publicContacts = 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)
}

View File

@ -9,7 +9,10 @@ import android.os.Build
import android.provider.ContactsContract
import android.support.v4.content.FileProvider
import com.simplemobiletools.commons.extensions.getIntValue
import com.simplemobiletools.commons.extensions.hasPermission
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.contacts.BuildConfig
import com.simplemobiletools.contacts.R
@ -65,11 +68,23 @@ fun Context.sendAddressIntent(address: String) {
val location = Uri.encode(address)
val uri = Uri.parse("geo:0,0?q=$location")
val intent = Intent(Intent.ACTION_VIEW, uri)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
} else {
toast(R.string.no_app_found)
Intent(Intent.ACTION_VIEW, uri).apply {
if (resolveActivity(packageManager) != null) {
startActivity(this)
} else {
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) {
return cursor.getIntValue(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM)
}
} catch (ignored: Exception) {
} finally {
cursor?.close()
}
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.startWithSurname = config.startNameWithSurname
contacts.sort()
allContacts = contacts
@ -149,7 +150,6 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
activity!!.startActivity(this)
}
}.apply {
setupDragListener(true)
addVerticalDividers(true)
fragment_list.adapter = this
}
@ -190,7 +190,6 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
ON_CLICK_EDIT_CONTACT -> context!!.editContact(it as Contact)
}
}.apply {
setupDragListener(true)
addVerticalDividers(true)
fragment_list.adapter = this
}
@ -235,16 +234,20 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
fun onSearchQueryChanged(text: String) {
(fragment_list.adapter as? ContactsAdapter)?.apply {
val filtered = contactsIgnoringSearch.filter {
it.getFullName(startNameWithSurname).contains(text, true) ||
it.getFullName().contains(text, true) ||
it.phoneNumbers.any { it.value.contains(text, true) } ||
it.emails.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
Contact.sorting = config.sorting
Contact.startWithSurname = config.startNameWithSurname
filtered.sort()
filtered.sortBy { !it.getFullName(startNameWithSurname).startsWith(text, true) }
filtered.sortBy { !it.getFullName().startsWith(text, true) }
if (filtered.isEmpty() && this@MyViewPagerFragment is FavoritesFragment) {
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
get() = prefs.getInt(ON_CONTACT_CLICK, ON_CLICK_VIEW_CONTACT)
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_TYPE = "local_account_type"
const val ON_CONTACT_CLICK = "on_contact_click"
const val SHOW_CONTACT_FIELDS = "show_contact_fields"
const val CONTACT_ID = "contact_id"
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 ADR = "ADR"
const val NOTE = "NOTE:"
const val ORG = "ORG:"
const val TITLE = "TITLE:"
const val ENCODING = "ENCODING"
const val BASE64 = "BASE64"
const val JPEG = "JPEG"
@ -64,3 +67,19 @@ const val VOICE = "VOICE"
const val ON_CLICK_CALL_CONTACT = 1
const val ON_CLICK_VIEW_CONTACT = 2
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_DESCENDING
import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.extensions.config
import com.simplemobiletools.contacts.extensions.dbHelper
import com.simplemobiletools.contacts.extensions.getByteArray
import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize
import com.simplemobiletools.contacts.extensions.*
import com.simplemobiletools.contacts.models.*
class ContactsHelper(val activity: BaseSimpleActivity) {
private val BATCH_SIZE = 100
fun getContacts(callback: (ArrayList<Contact>) -> Unit) {
val contacts = SparseArray<Contact>()
Thread {
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 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)
}
val contacts = SparseArray<Contact>()
getDeviceContacts(contacts)
activity.dbHelper.getContacts(activity).forEach {
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
val groups = getContactGroups(getStoredGroups())
size = groups.size()
val size = groups.size()
for (i in 0 until size) {
val key = groups.keyAt(i)
resultContacts.firstOrNull { it.contactId == key }?.groups = groups.valueAt(i)
@ -125,6 +53,102 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
}.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>> {
val phoneNumbers = SparseArray<ArrayList<PhoneNumber>>()
val uri = CommonDataKinds.Phone.CONTENT_URI
@ -218,7 +242,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
if (cursor?.moveToFirst() == true) {
do {
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)
if (addresses[id] == null) {
@ -315,8 +339,90 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
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>> {
val groups = SparseArray<ArrayList<Group>>()
if (!activity.hasContactPermissions()) {
return groups
}
val uri = ContactsContract.Data.CONTENT_URI
val projection = arrayOf(
ContactsContract.Data.CONTACT_ID,
@ -357,7 +463,17 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
}
fun getStoredGroups(): ArrayList<Group> {
val groups = getDeviceStoredGroups()
groups.addAll(activity.dbHelper.getGroups())
return groups
}
fun getDeviceStoredGroups(): ArrayList<Group> {
val groups = ArrayList<Group>()
if (!activity.hasContactPermissions()) {
return groups
}
val uri = ContactsContract.Groups.CONTENT_URI
val projection = arrayOf(
ContactsContract.Groups._ID,
@ -374,7 +490,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
if (cursor?.moveToFirst() == true) {
do {
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)
if (groups.map { it.title }.contains(title) && systemId != null) {
@ -389,8 +505,6 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
} finally {
cursor?.close()
}
groups.addAll(activity.dbHelper.getGroups())
return groups
}
@ -477,9 +591,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor?.moveToFirst() == true) {
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.Phone.PHOTO_URI) ?: ""
val number = getPhoneNumbers(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 groups = getContactGroups(storedGroups, contactId)[contactId] ?: ArrayList()
val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
return Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName, starred, contactId,
thumbnailUri, null, notes, groups)
val organization = getOrganizations(id)[id] ?: Organization("", "")
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 {
cursor?.close()
@ -502,37 +620,44 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
}
fun getContactSources(callback: (ArrayList<ContactSource>) -> Unit) {
val sources = LinkedHashSet<ContactSource>()
Thread {
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("", ""))
}
val sources = LinkedHashSet<ContactSource>()
getDeviceContactSources(sources)
sources.add(ContactSource(activity.getString(R.string.phone_storage_hidden), SMT_PRIVATE))
callback(ArrayList(sources))
}.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 {
if (accountName.isEmpty()) {
return ""
@ -558,9 +683,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
private fun getContactProjection() = arrayOf(
ContactsContract.Data.CONTACT_ID,
ContactsContract.Data.RAW_CONTACT_ID,
CommonDataKinds.StructuredName.PREFIX,
CommonDataKinds.StructuredName.GIVEN_NAME,
CommonDataKinds.StructuredName.MIDDLE_NAME,
CommonDataKinds.StructuredName.FAMILY_NAME,
CommonDataKinds.StructuredName.SUFFIX,
CommonDataKinds.StructuredName.PHOTO_URI,
CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI,
CommonDataKinds.StructuredName.STARRED,
@ -613,9 +740,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?"
val selectionArgs = arrayOf(contact.id.toString(), CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
withSelection(selection, selectionArgs)
withValue(CommonDataKinds.StructuredName.PREFIX, contact.prefix)
withValue(CommonDataKinds.StructuredName.GIVEN_NAME, contact.firstName)
withValue(CommonDataKinds.StructuredName.MIDDLE_NAME, contact.middleName)
withValue(CommonDataKinds.StructuredName.FAMILY_NAME, contact.surname)
withValue(CommonDataKinds.StructuredName.SUFFIX, contact.suffix)
operations.add(build())
}
@ -704,6 +833,18 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
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
val relevantGroupIDs = getStoredGroups().map { it.id }
if (relevantGroupIDs.isNotEmpty()) {
@ -795,6 +936,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
withValue(CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId)
operations.add(build())
}
if (operations.size % BATCH_SIZE == 0) {
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
operations.clear()
}
}
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
}
@ -808,6 +954,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
withSelection(selection, selectionArgs)
operations.add(build())
}
if (operations.size % BATCH_SIZE == 0) {
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
operations.clear()
}
}
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
}
@ -829,9 +980,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
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.MIDDLE_NAME, contact.middleName)
withValue(CommonDataKinds.StructuredName.FAMILY_NAME, contact.surname)
withValue(CommonDataKinds.StructuredName.SUFFIX, contact.suffix)
operations.add(build())
}
@ -887,6 +1040,17 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
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
contact.groups.forEach {
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
@ -1000,16 +1164,19 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
fun addFavorites(contacts: ArrayList<Contact>) {
toggleLocalFavorites(contacts, true)
toggleFavorites(contacts, true)
if (activity.hasContactPermissions()) {
toggleFavorites(contacts, true)
}
}
fun removeFavorites(contacts: ArrayList<Contact>) {
toggleLocalFavorites(contacts, false)
toggleFavorites(contacts, false)
if (activity.hasContactPermissions()) {
toggleFavorites(contacts, false)
}
}
private fun toggleFavorites(contacts: ArrayList<Contact>, addToFavorites: Boolean) {
val applyBatchSize = 100
try {
val operations = ArrayList<ContentProviderOperation>()
contacts.filter { it.source != SMT_PRIVATE }.map { it.contactId.toString() }.forEach {
@ -1019,7 +1186,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
operations.add(build())
}
if (operations.size % applyBatchSize == 0) {
if (operations.size % BATCH_SIZE == 0) {
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
operations.clear()
}
@ -1044,25 +1211,27 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
}
fun deleteContacts(contacts: ArrayList<Contact>) {
val localContacts = contacts.filter { it.source == SMT_PRIVATE }.map { it.id.toString() }.toTypedArray()
activity.dbHelper.deleteContacts(localContacts)
Thread {
val localContacts = contacts.filter { it.source == SMT_PRIVATE }.map { it.id.toString() }.toTypedArray()
activity.dbHelper.deleteContacts(localContacts)
try {
val contactIDs = HashSet<String>()
val operations = ArrayList<ContentProviderOperation>()
val selection = "${ContactsContract.Data.CONTACT_ID} = ?"
contacts.filter { it.source != SMT_PRIVATE }.forEach {
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
val selectionArgs = arrayOf(it.contactId.toString())
withSelection(selection, selectionArgs)
operations.add(this.build())
try {
val contactIDs = HashSet<String>()
val operations = ArrayList<ContentProviderOperation>()
val selection = "${ContactsContract.Data.CONTACT_ID} = ?"
contacts.filter { it.source != SMT_PRIVATE }.forEach {
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
val selectionArgs = arrayOf(it.contactId.toString())
withSelection(selection, selectionArgs)
operations.add(this.build())
}
contactIDs.add(it.id.toString())
}
contactIDs.add(it.id.toString())
}
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
} catch (e: Exception) {
activity.showErrorToast(e)
}
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
} catch (e: Exception) {
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) {
private val CONTACTS_TABLE_NAME = "contacts"
private val COL_ID = "id"
private val COL_PREFIX = "prefix"
private val COL_FIRST_NAME = "first_name"
private val COL_MIDDLE_NAME = "middle_name"
private val COL_SURNAME = "surname"
private val COL_SUFFIX = "suffix"
private val COL_PHOTO = "photo"
private val COL_PHONE_NUMBERS = "phone_numbers"
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_ADDRESSES = "addresses"
private val COL_NOTES = "notes"
private val COL_COMPANY = "company"
private val COL_JOB_POSITION = "job_position"
private val COL_GROUPS = "groups"
private val GROUPS_TABLE_NAME = "groups"
@ -43,9 +47,10 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
private val mDb = writableDatabase
companion object {
private const val DB_VERSION = 3
private const val DB_VERSION = 4
const val DB_NAME = "contacts.db"
var dbInstance: DBHelper? = null
var gson = Gson()
fun newInstance(context: Context): DBHelper {
if (dbInstance == null)
@ -58,7 +63,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE $CONTACTS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_FIRST_NAME TEXT, $COL_MIDDLE_NAME TEXT, " +
"$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER, " +
"$COL_ADDRESSES TEXT, $COL_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
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)
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) {
@ -108,16 +120,20 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
private fun fillContactValues(contact: Contact): ContentValues {
return ContentValues().apply {
put(COL_PREFIX, contact.prefix)
put(COL_FIRST_NAME, contact.firstName)
put(COL_MIDDLE_NAME, contact.middleName)
put(COL_SURNAME, contact.surname)
put(COL_PHONE_NUMBERS, Gson().toJson(contact.phoneNumbers))
put(COL_EMAILS, Gson().toJson(contact.emails))
put(COL_ADDRESSES, Gson().toJson(contact.addresses))
put(COL_EVENTS, Gson().toJson(contact.events))
put(COL_SUFFIX, contact.suffix)
put(COL_PHONE_NUMBERS, gson.toJson(contact.phoneNumbers))
put(COL_EMAILS, gson.toJson(contact.emails))
put(COL_ADDRESSES, gson.toJson(contact.addresses))
put(COL_EVENTS, gson.toJson(contact.events))
put(COL_STARRED, contact.starred)
put(COL_NOTES, contact.notes)
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()) {
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 deleteGroups(ids: Array<String>) {
private fun deleteGroups(ids: Array<String>) {
val args = TextUtils.join(", ", ids)
val selection = "$GROUPS_TABLE_NAME.$COL_ID IN ($args)"
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 selection = "$COL_ID = ?"
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 {
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> {
val storedGroups = ContactsHelper(activity).getStoredGroups()
val contacts = ArrayList<Contact>()
val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED,
COL_PHOTO, COL_ADDRESSES, COL_NOTES, COL_GROUPS)
val projection = arrayOf(COL_ID, COL_PREFIX, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_SUFFIX, COL_PHONE_NUMBERS, COL_EMAILS,
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)
cursor.use {
while (cursor.moveToNext()) {
val id = cursor.getIntValue(COL_ID)
val prefix = cursor.getStringValue(COL_PREFIX)
val firstName = cursor.getStringValue(COL_FIRST_NAME)
val middleName = cursor.getStringValue(COL_MIDDLE_NAME)
val surname = cursor.getStringValue(COL_SURNAME)
val suffix = cursor.getStringValue(COL_SUFFIX)
val phoneNumbersJson = cursor.getStringValue(COL_PHONE_NUMBERS)
val phoneNumbersToken = object : TypeToken<List<PhoneNumber>>() {}.type
val phoneNumbers = Gson().fromJson<ArrayList<PhoneNumber>>(phoneNumbersJson, phoneNumbersToken) ?: ArrayList(1)
val phoneNumbers = if (phoneNumbersJson == "[]") ArrayList() else gson.fromJson<ArrayList<PhoneNumber>>(phoneNumbersJson, phoneNumbersToken)
?: ArrayList(1)
val emailsJson = cursor.getStringValue(COL_EMAILS)
val emailsToken = object : TypeToken<List<Email>>() {}.type
val emails = Gson().fromJson<ArrayList<Email>>(emailsJson, emailsToken) ?: ArrayList(1)
val emails = if (emailsJson == "[]") ArrayList() else gson.fromJson<ArrayList<Email>>(emailsJson, emailsToken)
?: ArrayList(1)
val addressesJson = cursor.getStringValue(COL_ADDRESSES)
val addressesToken = object : TypeToken<List<Address>>() {}.type
val addresses = Gson().fromJson<ArrayList<Address>>(addressesJson, addressesToken) ?: ArrayList(1)
val addresses = if (addressesJson == "[]") ArrayList() else gson.fromJson<ArrayList<Address>>(addressesJson, addressesToken)
?: ArrayList(1)
val eventsJson = cursor.getStringValue(COL_EVENTS)
val eventsToken = object : TypeToken<List<Event>>() {}.type
val events = Gson().fromJson<ArrayList<Event>>(eventsJson, eventsToken) ?: ArrayList(1)
val events = if (eventsJson == "[]") ArrayList() else gson.fromJson<ArrayList<Event>>(eventsJson, eventsToken)
?: ArrayList(1)
val photoByteArray = cursor.getBlobValue(COL_PHOTO) ?: null
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 groupIdsJson = cursor.getStringValue(COL_GROUPS)
val groupIdsToken = object : TypeToken<List<Long>>() {}.type
val groupIds = Gson().fromJson<ArrayList<Long>>(groupIdsJson, groupIdsToken) ?: ArrayList(1)
val groupIds = if (groupIdsJson == "[]") ArrayList() else gson.fromJson<ArrayList<Long>>(groupIdsJson, groupIdsToken)
?: ArrayList(1)
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)
}
}

View File

@ -66,6 +66,11 @@ class VcfExporter {
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()) {
val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, Uri.parse(contact.thumbnailUri))
addBitmap(bitmap, out)
@ -116,17 +121,23 @@ class VcfExporter {
var firstName = contact.firstName
var surName = contact.surname
var middleName = contact.middleName
var prefix = contact.prefix
var suffix = contact.suffix
if (QuotedPrintable.urlEncode(firstName) != firstName
|| QuotedPrintable.urlEncode(surName) != surName
|| QuotedPrintable.urlEncode(middleName) != middleName) {
|| QuotedPrintable.urlEncode(middleName) != middleName
|| QuotedPrintable.urlEncode(prefix) != prefix
|| QuotedPrintable.urlEncode(suffix) != suffix) {
firstName = QuotedPrintable.encode(firstName)
surName = QuotedPrintable.encode(surName)
middleName = QuotedPrintable.encode(middleName)
prefix = QuotedPrintable.encode(prefix)
suffix = QuotedPrintable.encode(suffix)
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) {

View File

@ -19,16 +19,21 @@ class VcfImporter(val activity: SimpleActivity) {
IMPORT_FAIL, IMPORT_OK, IMPORT_PARTIAL
}
private var curPrefix = ""
private var curFirstName = ""
private var curMiddleName = ""
private var curSurname = ""
private var curSuffix = ""
private var curPhotoUri = ""
private var curNotes = ""
private var curCompany = ""
private var curJobPosition = ""
private var curPhoneNumbers = ArrayList<PhoneNumber>()
private var curEmails = ArrayList<Email>()
private var curEvents = ArrayList<Event>()
private var curAddresses = ArrayList<Address>()
private var curGroups = ArrayList<Group>()
private var curWebsites = ArrayList<String>()
private var isGettingPhoto = false
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(ANNIVERSARY) -> addAnniversary(line.substring(ANNIVERSARY.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)
isGettingPhoto -> currentPhotoString.append(line.trim())
}
@ -118,6 +125,8 @@ class VcfImporter(val activity: SimpleActivity) {
curFirstName = if (currentNameIsANSI) QuotedPrintable.decode(nameParts[1]) else nameParts[1]
if (nameParts.size > 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
}
private fun addCompany(company: String) {
curCompany = company
}
private fun addJobPosition(jobPosition: String) {
curJobPosition = jobPosition
}
private fun saveContact(source: String) {
val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curAddresses, curEvents,
source, 0, 0, "", null, curNotes, curGroups)
val organization = Organization(curCompany, curJobPosition)
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)) {
contactsImported++
}
}
private fun resetValues() {
curPrefix = ""
curFirstName = ""
curMiddleName = ""
curSurname = ""
curSuffix = ""
curPhotoUri = ""
curNotes = ""
curCompany = ""
curJobPosition = ""
curPhoneNumbers = ArrayList()
curEmails = ArrayList()
curEvents = ArrayList()
curAddresses = ArrayList()
curGroups = ArrayList()
curWebsites = ArrayList()
isGettingPhoto = false
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_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 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 {
var sorting = 0
var startWithSurname = false
}
override fun compareTo(other: Contact): Int {
var result = when {
sorting and SORT_BY_FIRST_NAME != 0 -> compareStrings(firstName, other.firstName)
sorting and SORT_BY_MIDDLE_NAME != 0 -> compareStrings(middleName, other.middleName)
else -> compareStrings(surname, other.surname)
val firstString: String
val secondString: String
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) {
@ -33,28 +64,21 @@ data class Contact(val id: Int, var firstName: String, var middleName: String, v
else -> surname
}
fun getFullName(startWithSurname: Boolean): String {
fun getFullName(): String {
var firstPart = if (startWithSurname) surname else firstName
if (middleName.isNotEmpty()) {
firstPart += " $middleName"
}
val lastPart = if (startWithSurname) firstName else surname
return "$firstPart $lastPart".trim()
}
private fun compareStrings(first: String, second: String): Int {
return if (first.firstOrNull()?.isLetter() == true && second.firstOrNull()?.isLetter() == false) {
-1
} else if (first.firstOrNull()?.isLetter() == false && second.firstOrNull()?.isLetter() == true) {
1
val lastPart = if (startWithSurname) firstName else surname
val suffixComma = if (suffix.isEmpty()) "" else ", $suffix"
val fullName = "$prefix $firstPart $lastPart$suffixComma".trim()
return if (fullName.isEmpty()) {
var fullOrganization = if (organization.jobPosition.isEmpty()) "" else "${organization.jobPosition}, "
fullOrganization += organization.company
fullOrganization.trim().trimEnd(',')
} else {
if (first.isEmpty() && second.isNotEmpty()) {
1
} else if (first.isNotEmpty() && second.isEmpty()) {
-1
} else {
first.toLowerCase().compareTo(second.toLowerCase())
}
fullName
}
}
}

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

View File

@ -33,6 +33,28 @@
</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
android:id="@+id/settings_use_english_holder"
android:layout_width="match_parent"

View File

@ -18,7 +18,8 @@
<ImageView
android:id="@+id/contact_photo"
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
android:id="@+id/contact_toggle_favorite"
@ -83,7 +84,7 @@
android:id="@+id/contact_name_image"
android:layout_width="@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:paddingEnd="@dimen/small_margin"
android:paddingRight="@dimen/small_margin"
@ -91,12 +92,26 @@
android:src="@drawable/ic_person"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/contact_first_name"
android:id="@+id/contact_prefix"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_photo"
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:lines="1"
android:maxLines="1"
@ -136,8 +151,23 @@
android:singleLine="true"
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
android:id="@+id/contact_number_image"
android:id="@+id/contact_numbers_image"
android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_numbers_holder"
@ -151,13 +181,13 @@
android:id="@+id/contact_numbers_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_surname"
android:layout_toRightOf="@+id/contact_number_image"
android:layout_below="@+id/contact_suffix"
android:layout_toRightOf="@+id/contact_numbers_image"
android:orientation="vertical"
android:paddingLeft="@dimen/small_margin"/>
<ImageView
android:id="@+id/contact_email_image"
android:id="@+id/contact_emails_image"
android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_emails_holder"
@ -177,7 +207,7 @@
android:paddingLeft="@dimen/small_margin"/>
<ImageView
android:id="@+id/contact_address_image"
android:id="@+id/contact_addresses_image"
android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_addresses_holder"
@ -197,7 +227,7 @@
android:paddingLeft="@dimen/small_margin"/>
<ImageView
android:id="@+id/contact_event_image"
android:id="@+id/contact_events_image"
android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_events_holder"
@ -239,6 +269,62 @@
android:paddingTop="@dimen/normal_margin"
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
android:id="@+id/contact_groups_image"
android:layout_width="@dimen/contact_icons_size"
@ -254,7 +340,7 @@
android:id="@+id/contact_groups_holder"
android:layout_width="match_parent"
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:orientation="vertical"
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="phone_storage">Gerätespeicher</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="edit_contact">Kontakt bearbeiten</string>
@ -16,15 +19,15 @@
<string name="surname">Familienname</string>
<!-- Groups -->
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="remove_from_group">Remove from group</string>
<string name="no_group_participants">This group is empty</string>
<string name="add_contacts">Add contacts</string>
<string name="no_group_created">There are no contact groups on the device</string>
<string name="create_group">Create group</string>
<string name="add_to_group">Add to group</string>
<string name="create_group_under_account">Create group under account</string>
<string name="no_groups">Keine Gruppen</string>
<string name="create_new_group">Eine neue Gruppe erstellen</string>
<string name="remove_from_group">Von Gruppe entfernen</string>
<string name="no_group_participants">Diese Gruppe ist leer</string>
<string name="add_contacts">Kontakte hinzufügen</string>
<string name="no_group_created">Es sind keine Kontaktgruppen auf diesem Gerät vorhanden</string>
<string name="create_group">Erstelle Gruppe</string>
<string name="add_to_group">Zu Gruppe hinzufügen</string>
<string name="create_group_under_account">Gruppe in diesem Konto erstellen</string>
<!-- Photo -->
<string name="take_photo">Foto machen</string>
@ -40,6 +43,7 @@
<string name="view_contact">Kontaktdetails ansehen</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails -->
<string name="email">Email</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Kontaktquellen einschließen</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 -->
<!-- Short description has to have less than 80 chars -->
<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_launcher_name">Επαφές</string>
<string name="address">Διεύθυνση</string>
<string name="inserting">Εισαγωγή...</string>
<string name="updating">Ενημέρωση...</string>
<string name="inserting">Εισαγωγή</string>
<string name="updating">Ενημέρωση</string>
<string name="phone_storage">Μνήμη τηλεφώνου</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="edit_contact">Επεξεργασία επαφής</string>
@ -40,6 +43,7 @@
<string name="view_contact">Εμφάνιση λεπτομερειών επαφής</string>
<string name="show_favorites_tab">Εμφάνιση καρτέλας αγαπημένων</string>
<string name="show_groups_tab">Εμφάνιση καρτέλας ομάδων</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails -->
<string name="email">Email</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Συμπερίληψη πηγών επαφών</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 -->
<!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Μια εφαρμογή επαφών για να διαχειρίζεσαι τις επαφές σου χωρίς διαφημίσεις.</string>

View File

@ -6,25 +6,28 @@
<string name="updating">Mise à jour…</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="company">Société</string>
<string name="job_position">Poste</string>
<string name="website">Website</string>
<string name="new_contact">Nouveau contact</string>
<string name="edit_contact">Modifier contact</string>
<string name="select_contact">Sélectionner un contact</string>
<string name="select_contacts">Sélectionner des contacts</string>
<string name="first_name">Prénom</string>
<string name="middle_name">Nom</string>
<string name="surname">Surnom</string>
<string name="middle_name">Deuxième prénom</string>
<string name="surname">Nom</string>
<!-- Groups -->
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="remove_from_group">Remove from group</string>
<string name="no_group_participants">This group is empty</string>
<string name="add_contacts">Add contacts</string>
<string name="no_group_created">There are no contact groups on the device</string>
<string name="create_group">Create group</string>
<string name="add_to_group">Add to group</string>
<string name="create_group_under_account">Create group under account</string>
<string name="no_groups">Pas de groupe</string>
<string name="create_new_group">Créer un nouveau groupe</string>
<string name="remove_from_group">Enlever du groupe</string>
<string name="no_group_participants">Ce groupe est vide</string>
<string name="add_contacts">Ajout contacts</string>
<string name="no_group_created">Il n\'y a pas de groupes de contacts sur l\'appareil</string>
<string name="create_group">Créer un groupe</string>
<string name="add_to_group">Ajouter à un groupe</string>
<string name="create_group_under_account">Créer un groupe pris en compte</string>
<!-- Photo -->
<string name="take_photo">Prendre une photo</string>
@ -32,14 +35,15 @@
<string name="remove_photo">Supprimer la photo</string>
<!-- 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_contact_thumbnails">Afficher les vignettes des contacts</string>
<string name="on_contact_click">Sur appui du contact</string>
<string name="call_contact">Appeler le 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_groups_tab">Show groups tab</string>
<string name="show_favorites_tab">Afficher l\'onglet favoris</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 -->
<string name="email">E-mail</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Inclure les sources du contact</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 -->
<!-- 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>

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="phone_storage">Phone storage</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="edit_contact">연락처 수정</string>
@ -40,6 +43,7 @@
<string name="view_contact">View contact details</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails -->
<string name="email">이메일</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">가져오기 대상</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 -->
<!-- Short description has to have less than 80 chars -->
<string name="app_short_description">광고가 없는 연락처 관리 애플리케이션입니다.</string>

View File

@ -6,6 +6,9 @@
<string name="updating">Atnaujinama…</string>
<string name="phone_storage">Telefono atmintis</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="edit_contact">Redaguoti kontaktą</string>
@ -18,13 +21,13 @@
<!-- Groups -->
<string name="no_groups">Nėra grupių</string>
<string name="create_new_group">Sukurti naują grupę</string>
<string name="remove_from_group">Remove from group</string>
<string name="no_group_participants">This group is empty</string>
<string name="add_contacts">Add contacts</string>
<string name="no_group_created">There are no contact groups on the device</string>
<string name="create_group">Create group</string>
<string name="add_to_group">Add to group</string>
<string name="create_group_under_account">Create group under account</string>
<string name="remove_from_group">Pašalinti iš grupės</string>
<string name="no_group_participants">Ši grupė tuščia</string>
<string name="add_contacts">Įtraukti kontaktus</string>
<string name="no_group_created">Šiame įrenginyje nėra kontaktų grupių</string>
<string name="create_group">Sukurti grupę</string>
<string name="add_to_group">Įtraukti į grupę</string>
<string name="create_group_under_account">Sukurti grupę paskyroje</string>
<!-- Photo -->
<string name="take_photo">Nufotografuoti</string>
@ -40,6 +43,7 @@
<string name="view_contact">Žiūrėti kontakto detales</string>
<string name="show_favorites_tab">Rodyti mėgiamiausiųjų skirtuką</string>
<string name="show_groups_tab">Rodyti grupių skirtuką</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails -->
<string name="email">Elektroninis paštas</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Įtraukti kontaktų šaltinius</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 -->
<!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Kontaktų programėlė įrenginio kontaktų tvarkymui, be reklamų.</string>

View File

@ -1,11 +1,14 @@
<resources>
<string name="app_name">Simple Contacts</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="updating">A atualizar…</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="company">Organização</string>
<string name="job_position">Cargo</string>
<string name="website">Website</string>
<string name="new_contact">Novo contacto</string>
<string name="edit_contact">Editar contacto</string>
@ -16,15 +19,15 @@
<string name="surname">Apelido</string>
<!-- Groups -->
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="remove_from_group">Remove from group</string>
<string name="no_group_participants">This group is empty</string>
<string name="add_contacts">Add contacts</string>
<string name="no_group_created">There are no contact groups on the device</string>
<string name="create_group">Create group</string>
<string name="add_to_group">Add to group</string>
<string name="create_group_under_account">Create group under account</string>
<string name="no_groups">Não grupos</string>
<string name="create_new_group">Criar um novo grupo</string>
<string name="remove_from_group">Remover do grupo</string>
<string name="no_group_participants">Este grupo está vazio</string>
<string name="add_contacts">Adicionar contactos</string>
<string name="no_group_created">Não existem grupos de contactos neste dispositivo</string>
<string name="create_group">Criar um grupo</string>
<string name="add_to_group">Adicionar ao grupo</string>
<string name="create_group_under_account">Criar grupo para a conta</string>
<!-- Photo -->
<string name="take_photo">Tirar foto</string>
@ -38,8 +41,9 @@
<string name="on_contact_click">Ao clicar no contacto</string>
<string name="call_contact">Ligar</string>
<string name="view_contact">Ver detalhes</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<string name="show_favorites_tab">Mostrar favoritos</string>
<string name="show_groups_tab">Mostrar grupos</string>
<string name="manage_shown_contact_fields">Gerir campos a exibir</string>
<!-- Emails -->
<string name="email">E-mail</string>
@ -79,17 +83,35 @@
<string name="include_contact_sources">Incluir fontes dos contactos</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 -->
<!-- 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">
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>
<!--

View File

@ -6,6 +6,9 @@
<string name="updating">Обновление…</string>
<string name="phone_storage">Память устройства</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="edit_contact">Редактировать контакт</string>
@ -40,6 +43,7 @@
<string name="view_contact">Просмотреть подробности о контакте</string>
<string name="show_favorites_tab">Показывать вкладку избранного</string>
<string name="show_groups_tab">Показывать вкладку групп</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails -->
<string name="email">Эл. почта</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Включить источники контактов</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 -->
<!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Приложение для управления контактами без рекламы.</string>

View File

@ -6,6 +6,9 @@
<string name="updating">Upravuje sa…</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="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="edit_contact">Upraviť kontakt</string>
@ -40,6 +43,7 @@
<string name="view_contact">Zobraziť údaje kontaktu</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="manage_shown_contact_fields">Spravovať zobrazené polia kontaktov</string>
<!-- Emails -->
<string name="email">Email</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Zahrnúť zdroje kontaktov</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 -->
<!-- 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>

View File

@ -6,6 +6,9 @@
<string name="updating">Uppdaterar…</string>
<string name="phone_storage">Telefonens lagringsutrymme</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="edit_contact">Redigera kontakt</string>
@ -16,15 +19,15 @@
<string name="surname">Efternamn</string>
<!-- Groups -->
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="remove_from_group">Remove from group</string>
<string name="no_group_participants">This group is empty</string>
<string name="add_contacts">Add contacts</string>
<string name="no_group_created">There are no contact groups on the device</string>
<string name="create_group">Create group</string>
<string name="add_to_group">Add to group</string>
<string name="create_group_under_account">Create group under account</string>
<string name="no_groups">Inga grupper</string>
<string name="create_new_group">Skapa en ny grupp</string>
<string name="remove_from_group">Ta bort från grupp</string>
<string name="no_group_participants">Denna grupp är tom</string>
<string name="add_contacts">Lägg till kontakter</string>
<string name="no_group_created">Det finns inga kontaktgrupper på enheten</string>
<string name="create_group">Skapa grupp</string>
<string name="add_to_group">Lägg till i grupp</string>
<string name="create_group_under_account">Skapa gruppen i kontot</string>
<!-- Photo -->
<string name="take_photo">Ta foto</string>
@ -38,8 +41,9 @@
<string name="on_contact_click">Vid kontakttryckning</string>
<string name="call_contact">Ring kontakt</string>
<string name="view_contact">Visa kontaktuppgifter</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<string name="show_favorites_tab">Visa fliken Favoriter</string>
<string name="show_groups_tab">Visa fliken Grupper</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails -->
<string name="email">E-post</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Inkludera kontaktkällor</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 -->
<!-- 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>

View File

@ -6,6 +6,9 @@
<string name="updating">更新中…</string>
<string name="phone_storage">手機空間</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="edit_contact">編輯聯絡人</string>
@ -24,7 +27,7 @@
<string name="no_group_created">裝置內沒有聯絡人群組</string>
<string name="create_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 -->
<string name="take_photo">拍照</string>
@ -40,9 +43,10 @@
<string name="view_contact">顯示聯絡人資料</string>
<string name="show_favorites_tab">顯示我的最愛頁面</string>
<string name="show_groups_tab">顯示群組頁面</string>
<string name="manage_shown_contact_fields">管理顯示的聯絡人欄位</string>
<!-- Emails -->
<string name="email">信箱</string>
<string name="email">電子信箱</string>
<string name="home">住家</string>
<string name="work">工作</string>
<string name="other">其它</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">包含聯絡人來源</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 -->
<!-- Short description has to have less than 80 chars -->
<string name="app_short_description">一個用來管理聯絡人,且沒有廣告的通訊錄應用程式。</string>

View File

@ -2,6 +2,10 @@
<resources>
<!-- 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_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="phone_storage">Phone storage</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="edit_contact">Edit contact</string>
@ -40,6 +43,7 @@
<string name="view_contact">View contact details</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<string name="manage_shown_contact_fields">Manage shown contact fields</string>
<!-- Emails -->
<string name="email">Email</string>
@ -79,6 +83,24 @@
<string name="include_contact_sources">Include contact sources</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 -->
<!-- Short description has to have less than 80 chars -->
<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.
buildscript {
ext.kotlin_version = '1.2.30'
ext.kotlin_version = '1.2.31'
repositories {
google()
@ -9,7 +9,7 @@ buildscript {
}
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"
// NOTE: Do not place your application dependencies here; they belong