Merge pull request #9 from SimpleMobileTools/master

upd
This commit is contained in:
solokot 2018-03-19 15:06:10 +03:00 committed by GitHub
commit 7298b53f76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 830 additions and 102 deletions

View File

@ -45,7 +45,7 @@ ext {
} }
dependencies { dependencies {
implementation 'com.simplemobiletools:commons:3.14.12' implementation 'com.simplemobiletools:commons:3.16.11'
implementation 'joda-time:joda-time:2.9.9' implementation 'joda-time:joda-time:2.9.9'
implementation 'com.facebook.stetho:stetho:1.5.0' implementation 'com.facebook.stetho:stetho:1.5.0'
implementation 'com.google.code.gson:gson:2.8.2' implementation 'com.google.code.gson:gson:2.8.2'

View File

@ -20,6 +20,7 @@ import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CONTACTS import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CONTACTS
import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.dialogs.SelectGroupsDialog
import com.simplemobiletools.contacts.extensions.* import com.simplemobiletools.contacts.extensions.*
import com.simplemobiletools.contacts.helpers.* import com.simplemobiletools.contacts.helpers.*
import com.simplemobiletools.contacts.models.* import com.simplemobiletools.contacts.models.*
@ -28,15 +29,16 @@ import kotlinx.android.synthetic.main.item_edit_address.view.*
import kotlinx.android.synthetic.main.item_edit_email.view.* import kotlinx.android.synthetic.main.item_edit_email.view.*
import kotlinx.android.synthetic.main.item_edit_phone_number.view.* import kotlinx.android.synthetic.main.item_edit_phone_number.view.*
import kotlinx.android.synthetic.main.item_event.view.* import kotlinx.android.synthetic.main.item_event.view.*
import kotlinx.android.synthetic.main.item_group.view.*
import org.joda.time.DateTime import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat import org.joda.time.format.DateTimeFormat
import java.util.* import java.util.*
class EditContactActivity : ContactActivity() { class EditContactActivity : ContactActivity() {
val DEFAULT_EMAIL_TYPE = CommonDataKinds.Email.TYPE_HOME private val DEFAULT_EMAIL_TYPE = CommonDataKinds.Email.TYPE_HOME
val DEFAULT_PHONE_NUMBER_TYPE = CommonDataKinds.Phone.TYPE_MOBILE private val DEFAULT_PHONE_NUMBER_TYPE = CommonDataKinds.Phone.TYPE_MOBILE
val DEFAULT_ADDRESS_TYPE = CommonDataKinds.StructuredPostal.TYPE_HOME private val DEFAULT_ADDRESS_TYPE = CommonDataKinds.StructuredPostal.TYPE_HOME
val DEFAULT_EVENT_TYPE = CommonDataKinds.Event.TYPE_BIRTHDAY private val DEFAULT_EVENT_TYPE = CommonDataKinds.Event.TYPE_BIRTHDAY
private val INTENT_TAKE_PHOTO = 1 private val INTENT_TAKE_PHOTO = 1
private val INTENT_CHOOSE_PHOTO = 2 private val INTENT_CHOOSE_PHOTO = 2
@ -166,6 +168,7 @@ class EditContactActivity : ContactActivity() {
contact_event_image.applyColorFilter(textColor) contact_event_image.applyColorFilter(textColor)
contact_notes_image.applyColorFilter(textColor) contact_notes_image.applyColorFilter(textColor)
contact_source_image.applyColorFilter(textColor) contact_source_image.applyColorFilter(textColor)
contact_groups_image.applyColorFilter(textColor)
val adjustedPrimaryColor = getAdjustedPrimaryColor() val adjustedPrimaryColor = getAdjustedPrimaryColor()
contact_number_add_new.applyColorFilter(adjustedPrimaryColor) contact_number_add_new.applyColorFilter(adjustedPrimaryColor)
@ -176,6 +179,8 @@ class EditContactActivity : ContactActivity() {
contact_address_add_new.background.applyColorFilter(textColor) contact_address_add_new.background.applyColorFilter(textColor)
contact_event_add_new.applyColorFilter(adjustedPrimaryColor) contact_event_add_new.applyColorFilter(adjustedPrimaryColor)
contact_event_add_new.background.applyColorFilter(textColor) contact_event_add_new.background.applyColorFilter(textColor)
contact_groups_add_new.applyColorFilter(adjustedPrimaryColor)
contact_groups_add_new.background.applyColorFilter(textColor)
contact_toggle_favorite.setOnClickListener { toggleFavorite() } contact_toggle_favorite.setOnClickListener { toggleFavorite() }
contact_photo.setOnClickListener { trySetPhoto() } contact_photo.setOnClickListener { trySetPhoto() }
@ -186,6 +191,7 @@ class EditContactActivity : ContactActivity() {
contact_email_add_new.setOnClickListener { addNewEmailField() } contact_email_add_new.setOnClickListener { addNewEmailField() }
contact_address_add_new.setOnClickListener { addNewAddressField() } contact_address_add_new.setOnClickListener { addNewAddressField() }
contact_event_add_new.setOnClickListener { addNewEventField() } contact_event_add_new.setOnClickListener { addNewEventField() }
contact_groups_add_new.setOnClickListener { showSelectGroupsDialog() }
contact_toggle_favorite.apply { contact_toggle_favorite.apply {
setImageDrawable(getStarDrawable(contact!!.starred == 1)) setImageDrawable(getStarDrawable(contact!!.starred == 1))
@ -238,6 +244,7 @@ class EditContactActivity : ContactActivity() {
setupAddresses() setupAddresses()
setupNotes() setupNotes()
setupEvents() setupEvents()
setupGroups()
} }
private fun setupPhoneNumbers() { private fun setupPhoneNumbers() {
@ -318,10 +325,60 @@ 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_group, contact_groups_holder, false)
contact_groups_holder.addView(groupHolder)
}
(groupHolder as ViewGroup).apply {
contact_group.apply {
text = group.title
setTextColor(config.textColor)
tag = group.id
alpha = 1f
}
setOnClickListener {
showSelectGroupsDialog()
}
contact_group_remove.apply {
beVisible()
applyColorFilter(getAdjustedPrimaryColor())
background.applyColorFilter(config.textColor)
setOnClickListener {
removeGroup(group.id)
}
}
}
}
if (groups.isEmpty()) {
layoutInflater.inflate(R.layout.item_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()
}
}
}
}
private fun setupNewContact() { private fun setupNewContact() {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
supportActionBar?.title = resources.getString(R.string.new_contact) supportActionBar?.title = resources.getString(R.string.new_contact)
contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "", null, "") contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "", null, "", ArrayList())
contact_source.text = getPublicContactSource(contact!!.source) contact_source.text = getPublicContactSource(contact!!.source)
contact_source.setOnClickListener { contact_source.setOnClickListener {
showContactSourcePicker(contact!!.source) { showContactSourcePicker(contact!!.source) {
@ -359,6 +416,13 @@ class EditContactActivity : ContactActivity() {
setupEventTypePicker(this) setupEventTypePicker(this)
} }
} }
if (contact!!.groups.isEmpty()) {
val groupsHolder = contact_groups_holder.getChildAt(0)
(groupsHolder as? ViewGroup)?.contact_group?.apply {
setupGroupsPicker(this)
}
}
} }
private fun setupPhoneNumberTypePicker(numberTypeField: TextView, type: Int = DEFAULT_PHONE_NUMBER_TYPE) { private fun setupPhoneNumberTypePicker(numberTypeField: TextView, type: Int = DEFAULT_PHONE_NUMBER_TYPE) {
@ -422,6 +486,16 @@ class EditContactActivity : ContactActivity() {
} }
} }
private fun setupGroupsPicker(groupTitleField: TextView, group: Group? = null) {
groupTitleField.apply {
text = group?.title ?: getString(R.string.no_groups)
alpha = if (group == null) 0.5f else 1f
setOnClickListener {
showSelectGroupsDialog()
}
}
}
private fun resetContactEvent(contactEvent: TextView, removeContactEventButton: ImageView) { private fun resetContactEvent(contactEvent: TextView, removeContactEventButton: ImageView) {
contactEvent.apply { contactEvent.apply {
text = getString(R.string.unknown) text = getString(R.string.unknown)
@ -431,6 +505,11 @@ class EditContactActivity : ContactActivity() {
removeContactEventButton.beGone() removeContactEventButton.beGone()
} }
private fun removeGroup(id: Long) {
contact!!.groups = contact!!.groups.filter { it.id != id } as ArrayList<Group>
setupGroups()
}
private fun showNumberTypePicker(numberTypeField: TextView) { private fun showNumberTypePicker(numberTypeField: TextView) {
val items = arrayListOf( val items = arrayListOf(
RadioItem(CommonDataKinds.Phone.TYPE_MOBILE, getString(R.string.mobile)), RadioItem(CommonDataKinds.Phone.TYPE_MOBILE, getString(R.string.mobile)),
@ -489,8 +568,15 @@ class EditContactActivity : ContactActivity() {
} }
} }
private fun showSelectGroupsDialog() {
SelectGroupsDialog(this@EditContactActivity, contact!!.groups) {
contact!!.groups = it
setupGroups()
}
}
private fun saveContact() { private fun saveContact() {
if (isSaving) { if (isSaving || contact == null) {
return return
} }

View File

@ -26,6 +26,7 @@ import com.simplemobiletools.contacts.dialogs.ImportContactsDialog
import com.simplemobiletools.contacts.extensions.config import com.simplemobiletools.contacts.extensions.config
import com.simplemobiletools.contacts.extensions.dbHelper import com.simplemobiletools.contacts.extensions.dbHelper
import com.simplemobiletools.contacts.extensions.getTempFile import com.simplemobiletools.contacts.extensions.getTempFile
import com.simplemobiletools.contacts.fragments.MyViewPagerFragment
import com.simplemobiletools.contacts.helpers.ContactsHelper import com.simplemobiletools.contacts.helpers.ContactsHelper
import com.simplemobiletools.contacts.helpers.VcfExporter import com.simplemobiletools.contacts.helpers.VcfExporter
import com.simplemobiletools.contacts.interfaces.RefreshContactsListener import com.simplemobiletools.contacts.interfaces.RefreshContactsListener
@ -33,6 +34,7 @@ import com.simplemobiletools.contacts.models.Contact
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_contacts.* import kotlinx.android.synthetic.main.fragment_contacts.*
import kotlinx.android.synthetic.main.fragment_favorites.* import kotlinx.android.synthetic.main.fragment_favorites.*
import kotlinx.android.synthetic.main.fragment_groups.*
import java.io.FileOutputStream import java.io.FileOutputStream
class MainActivity : SimpleActivity(), RefreshContactsListener { class MainActivity : SimpleActivity(), RefreshContactsListener {
@ -91,15 +93,17 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
val configShowContactThumbnails = config.showContactThumbnails val configShowContactThumbnails = config.showContactThumbnails
if (storedShowContactThumbnails != configShowContactThumbnails) { if (storedShowContactThumbnails != configShowContactThumbnails) {
contacts_fragment.showContactThumbnailsChanged(configShowContactThumbnails) contacts_fragment?.showContactThumbnailsChanged(configShowContactThumbnails)
favorites_fragment.showContactThumbnailsChanged(configShowContactThumbnails) favorites_fragment?.showContactThumbnailsChanged(configShowContactThumbnails)
} }
val configTextColor = config.textColor val configTextColor = config.textColor
if (storedTextColor != configTextColor) { if (storedTextColor != configTextColor) {
main_tabs_holder.getTabAt(getOtherViewPagerItem(viewpager.currentItem))?.icon?.applyColorFilter(configTextColor) getInactiveTabIndexes(viewpager.currentItem).forEach {
contacts_fragment.textColorChanged(configTextColor) main_tabs_holder.getTabAt(it)?.icon?.applyColorFilter(configTextColor)
favorites_fragment.textColorChanged(configTextColor) }
contacts_fragment?.textColorChanged(configTextColor)
favorites_fragment?.textColorChanged(configTextColor)
} }
val configBackgroundColor = config.backgroundColor val configBackgroundColor = config.backgroundColor
@ -111,14 +115,14 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
if (storedPrimaryColor != configPrimaryColor) { if (storedPrimaryColor != configPrimaryColor) {
main_tabs_holder.setSelectedTabIndicatorColor(getAdjustedPrimaryColor()) main_tabs_holder.setSelectedTabIndicatorColor(getAdjustedPrimaryColor())
main_tabs_holder.getTabAt(viewpager.currentItem)?.icon?.applyColorFilter(getAdjustedPrimaryColor()) main_tabs_holder.getTabAt(viewpager.currentItem)?.icon?.applyColorFilter(getAdjustedPrimaryColor())
contacts_fragment.primaryColorChanged() contacts_fragment?.primaryColorChanged(configPrimaryColor)
favorites_fragment.primaryColorChanged() favorites_fragment?.primaryColorChanged(configPrimaryColor)
} }
val configStartNameWithSurname = config.startNameWithSurname val configStartNameWithSurname = config.startNameWithSurname
if (storedStartNameWithSurname != configStartNameWithSurname) { if (storedStartNameWithSurname != configStartNameWithSurname) {
contacts_fragment.startNameWithSurnameChanged(configStartNameWithSurname) contacts_fragment?.startNameWithSurnameChanged(configStartNameWithSurname)
favorites_fragment.startNameWithSurnameChanged(configStartNameWithSurname) favorites_fragment?.startNameWithSurnameChanged(configStartNameWithSurname)
} }
if (!isFirstResume) { if (!isFirstResume) {
@ -126,10 +130,9 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
initFragments() initFragments()
} }
contacts_fragment?.initContacts()
contacts_fragment?.onActivityResume() contacts_fragment?.onActivityResume()
favorites_fragment?.initContacts()
favorites_fragment?.onActivityResume() favorites_fragment?.onActivityResume()
refreshContacts(true, true)
} }
if (hasPermission(PERMISSION_WRITE_CONTACTS)) { if (hasPermission(PERMISSION_WRITE_CONTACTS)) {
@ -190,7 +193,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
override fun onQueryTextChange(newText: String): Boolean { override fun onQueryTextChange(newText: String): Boolean {
if (isSearchOpen) { if (isSearchOpen) {
getCurrentFragment()?.onSearchQueryChanged(newText) (getCurrentFragment() as? MyViewPagerFragment)?.onSearchQueryChanged(newText)
} }
return true return true
} }
@ -199,20 +202,24 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
MenuItemCompat.setOnActionExpandListener(searchMenuItem, object : MenuItemCompat.OnActionExpandListener { MenuItemCompat.setOnActionExpandListener(searchMenuItem, object : MenuItemCompat.OnActionExpandListener {
override fun onMenuItemActionExpand(item: MenuItem?): Boolean { override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
getCurrentFragment()?.onSearchOpened() (getCurrentFragment() as? MyViewPagerFragment)?.onSearchOpened()
isSearchOpen = true isSearchOpen = true
return true return true
} }
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean { override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
getCurrentFragment()?.onSearchClosed() (getCurrentFragment() as? MyViewPagerFragment)?.onSearchClosed()
isSearchOpen = false isSearchOpen = false
return true return true
} }
}) })
} }
private fun getCurrentFragment() = if (viewpager.currentItem == 0) contacts_fragment else favorites_fragment private fun getCurrentFragment() = when (viewpager.currentItem) {
0 -> contacts_fragment
1 -> favorites_fragment
else -> groups_fragment
}
private fun setupTabColors() { private fun setupTabColors() {
val lastUsedPage = config.lastUsedViewPagerPage val lastUsedPage = config.lastUsedViewPagerPage
@ -221,7 +228,10 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
setSelectedTabIndicatorColor(getAdjustedPrimaryColor()) setSelectedTabIndicatorColor(getAdjustedPrimaryColor())
getTabAt(lastUsedPage)?.select() getTabAt(lastUsedPage)?.select()
getTabAt(lastUsedPage)?.icon?.applyColorFilter(getAdjustedPrimaryColor()) getTabAt(lastUsedPage)?.icon?.applyColorFilter(getAdjustedPrimaryColor())
getTabAt(getOtherViewPagerItem(lastUsedPage))?.icon?.applyColorFilter(config.textColor)
getInactiveTabIndexes(lastUsedPage).forEach {
getTabAt(it)?.icon?.applyColorFilter(config.textColor)
}
} }
} }
@ -253,14 +263,15 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
} }
} }
private fun getOtherViewPagerItem(used: Int) = if (used == 1) 0 else 1 private fun getInactiveTabIndexes(activeIndex: Int) = arrayListOf(0, 1, 2).filter { it != activeIndex }
private fun initFragments() { private fun initFragments() {
viewpager.adapter = ViewPagerAdapter(this) refreshContacts(true, true)
viewpager.offscreenPageLimit = 2
viewpager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { viewpager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) { override fun onPageScrollStateChanged(state: Int) {
if (isSearchOpen) { if (isSearchOpen) {
getCurrentFragment().onSearchQueryChanged("") (getCurrentFragment() as? MyViewPagerFragment)?.onSearchQueryChanged("")
searchMenuItem?.collapseActionView() searchMenuItem?.collapseActionView()
} }
} }
@ -294,15 +305,14 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
private fun showSortingDialog() { private fun showSortingDialog() {
ChangeSortingDialog(this) { ChangeSortingDialog(this) {
contacts_fragment?.initContacts() refreshContacts(true, true)
favorites_fragment?.initContacts()
} }
} }
fun showFilterDialog() { fun showFilterDialog() {
FilterContactSourcesDialog(this) { FilterContactSourcesDialog(this) {
contacts_fragment?.forceListRedraw = true contacts_fragment?.forceListRedraw = true
contacts_fragment?.initContacts() refreshContacts(true, false)
} }
} }
@ -324,7 +334,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
ImportContactsDialog(this, path) { ImportContactsDialog(this, path) {
if (it) { if (it) {
runOnUiThread { runOnUiThread {
refreshContacts() refreshContacts(true, true)
} }
} }
} }
@ -383,17 +393,36 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
private fun launchAbout() { private fun launchAbout() {
val faqItems = arrayListOf(FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons)) val faqItems = arrayListOf(FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons))
startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_MULTISELECT or LICENSE_JODA or LICENSE_GLIDE or LICENSE_GSON or LICENSE_STETHO, startAboutActivity(R.string.app_name, LICENSE_MULTISELECT or LICENSE_JODA or LICENSE_GLIDE or LICENSE_GSON or LICENSE_STETHO,
BuildConfig.VERSION_NAME, faqItems) BuildConfig.VERSION_NAME, faqItems)
} }
override fun refreshContacts() { override fun refreshContacts(refreshContactsTab: Boolean, refreshFavoritesTab: Boolean) {
contacts_fragment.initContacts() if (isActivityDestroyed()) {
favorites_fragment.initContacts() return
}
ContactsHelper(this).getContacts {
if (isActivityDestroyed()) {
return@getContacts
}
if (viewpager.adapter == null) {
viewpager.adapter = ViewPagerAdapter(this, it)
}
if (refreshContactsTab) {
contacts_fragment?.refreshContacts(it)
}
if (refreshFavoritesTab) {
favorites_fragment?.refreshContacts(it)
}
}
} }
override fun refreshFavorites() { override fun refreshFavorites() {
favorites_fragment?.initContacts() refreshContacts(false, true)
} }
private fun checkWhatsNewDialog() { private fun checkWhatsNewDialog() {

View File

@ -19,6 +19,7 @@ import kotlinx.android.synthetic.main.activity_view_contact.*
import kotlinx.android.synthetic.main.item_event.view.* import kotlinx.android.synthetic.main.item_event.view.*
import kotlinx.android.synthetic.main.item_view_address.view.* import kotlinx.android.synthetic.main.item_view_address.view.*
import kotlinx.android.synthetic.main.item_view_email.view.* import kotlinx.android.synthetic.main.item_view_email.view.*
import kotlinx.android.synthetic.main.item_view_group.view.*
import kotlinx.android.synthetic.main.item_view_phone_number.view.* import kotlinx.android.synthetic.main.item_view_phone_number.view.*
class ViewContactActivity : ContactActivity() { class ViewContactActivity : ContactActivity() {
@ -65,6 +66,11 @@ class ViewContactActivity : ContactActivity() {
val data = intent.data val data = intent.data
if (data != null) { if (data != null) {
val rawId = if (data.path.contains("lookup")) { val rawId = if (data.path.contains("lookup")) {
val lookupKey = getLookupKeyFromUri(data)
if (lookupKey != null) {
contact = ContactsHelper(this).getContactWithLookupKey(lookupKey)
}
getLookupUriRawId(data) getLookupUriRawId(data)
} else { } else {
getContactUriRawId(data) getContactUriRawId(data)
@ -76,7 +82,7 @@ class ViewContactActivity : ContactActivity() {
} }
} }
if (contactId != 0) { if (contactId != 0 && contact == null) {
contact = ContactsHelper(this).getContactWithId(contactId, intent.getBooleanExtra(IS_PRIVATE, false)) contact = ContactsHelper(this).getContactWithId(contactId, intent.getBooleanExtra(IS_PRIVATE, false))
if (contact == null) { if (contact == null) {
toast(R.string.unknown_error_occurred) toast(R.string.unknown_error_occurred)
@ -114,6 +120,7 @@ class ViewContactActivity : ContactActivity() {
contact_event_image.applyColorFilter(textColor) contact_event_image.applyColorFilter(textColor)
contact_source_image.applyColorFilter(textColor) contact_source_image.applyColorFilter(textColor)
contact_notes_image.applyColorFilter(textColor) contact_notes_image.applyColorFilter(textColor)
contact_groups_image.applyColorFilter(textColor)
contact_send_sms.setOnClickListener { trySendSMS() } contact_send_sms.setOnClickListener { trySendSMS() }
contact_start_call.setOnClickListener { tryStartCall(contact!!) } contact_start_call.setOnClickListener { tryStartCall(contact!!) }
@ -154,6 +161,7 @@ class ViewContactActivity : ContactActivity() {
setupAddresses() setupAddresses()
setupEvents() setupEvents()
setupNotes() setupNotes()
setupGroups()
} }
private fun setupPhoneNumbers() { private fun setupPhoneNumbers() {
@ -161,9 +169,14 @@ class ViewContactActivity : ContactActivity() {
val phoneNumbers = contact!!.phoneNumbers val phoneNumbers = contact!!.phoneNumbers
phoneNumbers.forEach { phoneNumbers.forEach {
layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false).apply { layoutInflater.inflate(R.layout.item_view_phone_number, contact_numbers_holder, false).apply {
val phoneNumber = it
contact_numbers_holder.addView(this) contact_numbers_holder.addView(this)
contact_number.text = it.value contact_number.text = phoneNumber.value
contact_number_type.setText(getPhoneNumberTextId(it.type)) contact_number_type.setText(getPhoneNumberTextId(phoneNumber.type))
setOnClickListener {
startCallIntent(phoneNumber.value)
}
} }
} }
@ -176,9 +189,14 @@ class ViewContactActivity : ContactActivity() {
val emails = contact!!.emails val emails = contact!!.emails
emails.forEach { emails.forEach {
layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false).apply { layoutInflater.inflate(R.layout.item_view_email, contact_emails_holder, false).apply {
val email = it
contact_emails_holder.addView(this) contact_emails_holder.addView(this)
contact_email.text = it.value contact_email.text = email.value
contact_email_type.setText(getEmailTextId(it.type)) contact_email_type.setText(getEmailTextId(email.type))
setOnClickListener {
sendEmailIntent(email.value)
}
} }
} }
@ -191,9 +209,14 @@ class ViewContactActivity : ContactActivity() {
val addresses = contact!!.addresses val addresses = contact!!.addresses
addresses.forEach { addresses.forEach {
layoutInflater.inflate(R.layout.item_view_address, contact_addresses_holder, false).apply { layoutInflater.inflate(R.layout.item_view_address, contact_addresses_holder, false).apply {
val address = it
contact_addresses_holder.addView(this) contact_addresses_holder.addView(this)
contact_address.text = it.value contact_address.text = address.value
contact_address_type.setText(getAddressTextId(it.type)) contact_address_type.setText(getAddressTextId(address.type))
setOnClickListener {
sendAddressIntent(address.value)
}
} }
} }
@ -225,5 +248,20 @@ class ViewContactActivity : ContactActivity() {
contact_notes.beVisibleIf(notes.isNotEmpty()) contact_notes.beVisibleIf(notes.isNotEmpty())
} }
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
}
}
contact_groups_image.beVisibleIf(groups.isNotEmpty())
contact_groups_holder.beVisibleIf(groups.isNotEmpty())
}
private fun getStarDrawable(on: Boolean) = resources.getDrawable(if (on) R.drawable.ic_star_on_big else R.drawable.ic_star_off_big) private fun getStarDrawable(on: Boolean) = resources.getDrawable(if (on) R.drawable.ic_star_on_big else R.drawable.ic_star_off_big)
} }

View File

@ -130,7 +130,7 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
ContactsHelper(activity).deleteContacts(contactsToRemove) ContactsHelper(activity).deleteContacts(contactsToRemove)
if (contactItems.isEmpty()) { if (contactItems.isEmpty()) {
listener?.refreshContacts() listener?.refreshContacts(true, true)
finishActMode() finishActMode()
} else { } else {
removeSelectedItems() removeSelectedItems()

View File

@ -5,15 +5,19 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.activities.MainActivity import com.simplemobiletools.contacts.activities.MainActivity
import com.simplemobiletools.contacts.fragments.MyViewPagerFragment import com.simplemobiletools.contacts.interfaces.FragmentInterface
import com.simplemobiletools.contacts.models.Contact
class ViewPagerAdapter(val activity: MainActivity) : PagerAdapter() { class ViewPagerAdapter(val activity: MainActivity, val contacts: ArrayList<Contact>) : PagerAdapter() {
override fun instantiateItem(container: ViewGroup, position: Int): Any { override fun instantiateItem(container: ViewGroup, position: Int): Any {
val layout = if (position == 0) R.layout.fragment_contacts else R.layout.fragment_favorites val layout = getFragment(position)
val view = activity.layoutInflater.inflate(layout, container, false) val view = activity.layoutInflater.inflate(layout, container, false)
container.addView(view) container.addView(view)
(view as MyViewPagerFragment).setupFragment(activity) (view as FragmentInterface).apply {
setupFragment(activity)
refreshContacts(contacts)
}
return view return view
} }
@ -21,6 +25,12 @@ class ViewPagerAdapter(val activity: MainActivity) : PagerAdapter() {
container.removeView(item as View) container.removeView(item as View)
} }
override fun getCount() = 2 override fun getCount() = 3
override fun isViewFromObject(view: View, item: Any) = view == item override fun isViewFromObject(view: View, item: Any) = view == item
private fun getFragment(position: Int) = when (position) {
0 -> R.layout.fragment_contacts
1 -> R.layout.fragment_favorites
else -> R.layout.fragment_groups
}
} }

View File

@ -0,0 +1,41 @@
package com.simplemobiletools.contacts.dialogs
import android.support.v7.app.AlertDialog
import android.view.View
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.showKeyboard
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.value
import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.helpers.ContactsHelper
import com.simplemobiletools.contacts.models.Group
import kotlinx.android.synthetic.main.dialog_create_new_group.view.*
class CreateNewGroupDialog(val activity: BaseSimpleActivity, val callback: (newGroup: Group) -> Unit) {
init {
val view = activity.layoutInflater.inflate(R.layout.dialog_create_new_group, null)
AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
activity.setupDialogStuff(view, this, R.string.create_new_group) {
showKeyboard(view.group_name)
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(View.OnClickListener {
val name = view.group_name.value
if (name.isEmpty()) {
activity.toast(R.string.empty_name)
return@OnClickListener
}
val newGroup = ContactsHelper(activity).createNewGroup(name)
if (newGroup != null) {
callback(newGroup)
}
dismiss()
})
}
}
}
}

View File

@ -0,0 +1,85 @@
package com.simplemobiletools.contacts.dialogs
import android.support.v7.app.AlertDialog
import android.view.ViewGroup
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.views.MyAppCompatCheckbox
import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.activities.SimpleActivity
import com.simplemobiletools.contacts.extensions.config
import com.simplemobiletools.contacts.helpers.ContactsHelper
import com.simplemobiletools.contacts.models.Group
import kotlinx.android.synthetic.main.dialog_select_groups.view.*
import kotlinx.android.synthetic.main.item_checkbox.view.*
import kotlinx.android.synthetic.main.item_textview.view.*
import java.util.*
class SelectGroupsDialog(val activity: SimpleActivity, val selectedGroups: ArrayList<Group>, val callback: (newGroups: ArrayList<Group>) -> Unit) {
private val view = activity.layoutInflater.inflate(R.layout.dialog_select_groups, null) as ViewGroup
private val checkboxes = ArrayList<MyAppCompatCheckbox>()
private val groups = ContactsHelper(activity).getStoredGroups()
private val config = activity.config
private val dialog: AlertDialog?
init {
groups.forEach {
addGroupCheckbox(it)
}
addCreateNewGroupButton()
dialog = AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, { dialog, which -> dialogConfirmed() })
.setNegativeButton(R.string.cancel, null)
.create().apply {
activity.setupDialogStuff(view, this)
}
}
private fun addGroupCheckbox(group: Group) {
activity.layoutInflater.inflate(R.layout.item_checkbox, null, false).apply {
checkboxes.add(item_checkbox)
item_checkbox_holder.setOnClickListener {
item_checkbox.toggle()
}
item_checkbox.apply {
isChecked = selectedGroups.contains(group)
text = group.title
tag = group.id
setColors(config.textColor, config.primaryColor, config.backgroundColor)
}
view.dialog_groups_holder.addView(this)
}
}
private fun addCreateNewGroupButton() {
val newGroup = Group(0, activity.getString(R.string.create_new_group))
activity.layoutInflater.inflate(R.layout.item_textview, null, false).item_textview.apply {
text = newGroup.title
tag = newGroup.id
setTextColor(config.textColor)
view.dialog_groups_holder.addView(this)
setOnClickListener {
CreateNewGroupDialog(activity) {
selectedGroups.add(it)
groups.add(it)
view.dialog_groups_holder.removeViewAt(view.dialog_groups_holder.childCount - 1)
addGroupCheckbox(it)
addCreateNewGroupButton()
}
}
}
}
private fun dialogConfirmed() {
val selectedGroups = ArrayList<Group>()
checkboxes.filter { it.isChecked }.forEach {
val groupId = it.tag as Long
groups.firstOrNull { it.id == groupId }?.apply {
selectedGroups.add(this)
}
}
callback(selectedGroups)
}
}

View File

@ -9,8 +9,8 @@ import android.os.Build
import android.provider.ContactsContract import android.provider.ContactsContract
import android.support.v4.content.FileProvider import android.support.v4.content.FileProvider
import com.simplemobiletools.commons.extensions.getIntValue import com.simplemobiletools.commons.extensions.getIntValue
import com.simplemobiletools.commons.extensions.isLollipopPlus
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.helpers.isLollipopPlus
import com.simplemobiletools.contacts.BuildConfig import com.simplemobiletools.contacts.BuildConfig
import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.R
import com.simplemobiletools.contacts.activities.EditContactActivity import com.simplemobiletools.contacts.activities.EditContactActivity
@ -61,6 +61,18 @@ fun Context.sendSMSIntent(recipient: String) {
} }
} }
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)
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP) @TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.getLookupUriRawId(dataUri: Uri): Int { fun Context.getLookupUriRawId(dataUri: Uri): Int {
val lookupKey = getLookupKeyFromUri(dataUri) val lookupKey = getLookupKeyFromUri(dataUri)

View File

@ -16,7 +16,7 @@ class FavoritesFragment(context: Context, attributeSet: AttributeSet) : MyViewPa
private fun showAddFavoritesDialog() { private fun showAddFavoritesDialog() {
AddFavoritesDialog(activity!!) { AddFavoritesDialog(activity!!) {
initContacts() activity!!.refreshContacts(false, true)
} }
} }
} }

View File

@ -0,0 +1,22 @@
package com.simplemobiletools.contacts.fragments
import android.content.Context
import android.support.design.widget.CoordinatorLayout
import android.util.AttributeSet
import com.simplemobiletools.contacts.activities.MainActivity
import com.simplemobiletools.contacts.interfaces.FragmentInterface
import com.simplemobiletools.contacts.models.Contact
class GroupsFragment(context: Context, attributeSet: AttributeSet) : CoordinatorLayout(context, attributeSet), FragmentInterface {
override fun setupFragment(activity: MainActivity) {
}
override fun textColorChanged(color: Int) {
}
override fun primaryColorChanged(color: Int) {
}
override fun refreshContacts(contacts: ArrayList<Contact>) {
}
}

View File

@ -15,11 +15,15 @@ import com.simplemobiletools.contacts.extensions.config
import com.simplemobiletools.contacts.extensions.editContact import com.simplemobiletools.contacts.extensions.editContact
import com.simplemobiletools.contacts.extensions.tryStartCall import com.simplemobiletools.contacts.extensions.tryStartCall
import com.simplemobiletools.contacts.extensions.viewContact import com.simplemobiletools.contacts.extensions.viewContact
import com.simplemobiletools.contacts.helpers.* import com.simplemobiletools.contacts.helpers.Config
import com.simplemobiletools.contacts.helpers.ON_CLICK_CALL_CONTACT
import com.simplemobiletools.contacts.helpers.ON_CLICK_EDIT_CONTACT
import com.simplemobiletools.contacts.helpers.ON_CLICK_VIEW_CONTACT
import com.simplemobiletools.contacts.interfaces.FragmentInterface
import com.simplemobiletools.contacts.models.Contact import com.simplemobiletools.contacts.models.Contact
import kotlinx.android.synthetic.main.fragment_layout.view.* import kotlinx.android.synthetic.main.fragment_layout.view.*
abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet) : CoordinatorLayout(context, attributeSet) { abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet) : CoordinatorLayout(context, attributeSet), FragmentInterface {
protected var activity: MainActivity? = null protected var activity: MainActivity? = null
private var lastHashCode = 0 private var lastHashCode = 0
private var contactsIgnoringSearch = ArrayList<Contact>() private var contactsIgnoringSearch = ArrayList<Contact>()
@ -27,7 +31,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
var forceListRedraw = false var forceListRedraw = false
fun setupFragment(activity: MainActivity) { override fun setupFragment(activity: MainActivity) {
config = activity.config config = activity.config
if (this.activity == null) { if (this.activity == null) {
this.activity = activity this.activity = activity
@ -47,18 +51,16 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
fragment_placeholder_2.text = activity.getString(R.string.add_favorites) fragment_placeholder_2.text = activity.getString(R.string.add_favorites)
} }
} }
initContacts()
} }
fun textColorChanged(color: Int) { override fun textColorChanged(color: Int) {
(fragment_list.adapter as ContactsAdapter).apply { (fragment_list.adapter as ContactsAdapter).apply {
updateTextColor(color) updateTextColor(color)
initDrawables() initDrawables()
} }
} }
fun primaryColorChanged() { override fun primaryColorChanged(color: Int) {
fragment_fastscroller.updatePrimaryColor() fragment_fastscroller.updatePrimaryColor()
fragment_fastscroller.updateBubblePrimaryColor() fragment_fastscroller.updateBubblePrimaryColor()
} }
@ -66,45 +68,34 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
fun startNameWithSurnameChanged(startNameWithSurname: Boolean) { fun startNameWithSurnameChanged(startNameWithSurname: Boolean) {
(fragment_list.adapter as ContactsAdapter).apply { (fragment_list.adapter as ContactsAdapter).apply {
config.sorting = if (startNameWithSurname) SORT_BY_SURNAME else SORT_BY_FIRST_NAME config.sorting = if (startNameWithSurname) SORT_BY_SURNAME else SORT_BY_FIRST_NAME
initContacts() this@MyViewPagerFragment.activity!!.refreshContacts(true, true)
} }
} }
fun initContacts() { override fun refreshContacts(contacts: ArrayList<Contact>) {
if (activity == null || activity!!.isActivityDestroyed()) { if (config.lastUsedContactSource.isEmpty()) {
return val grouped = contacts.groupBy { it.source }.maxWith(compareBy { it.value.size })
config.lastUsedContactSource = grouped?.key ?: ""
} }
ContactsHelper(activity!!).getContacts { val filtered = if (this is FavoritesFragment) {
var contacts = it contacts.filter { it.starred == 1 } as ArrayList<Contact>
if (activity == null || activity!!.isActivityDestroyed()) { } else {
return@getContacts val contactSources = config.displayContactSources
} if (config.showAllContacts()) {
contacts
if (config.lastUsedContactSource.isEmpty()) {
val grouped = contacts.groupBy { it.source }.maxWith(compareBy { it.value.size })
config.lastUsedContactSource = grouped?.key ?: ""
}
contacts = if (this is FavoritesFragment) {
contacts.filter { it.starred == 1 } as ArrayList<Contact>
} else { } else {
val contactSources = config.displayContactSources contacts.filter { contactSources.contains(it.source) } as ArrayList<Contact>
if (config.showAllContacts()) {
contacts
} else {
contacts.filter { contactSources.contains(it.source) } as ArrayList<Contact>
}
} }
}
Contact.sorting = config.sorting Contact.sorting = config.sorting
contacts.sort() filtered.sort()
if (contacts.hashCode() != lastHashCode) { if (filtered.hashCode() != lastHashCode) {
lastHashCode = contacts.hashCode() lastHashCode = filtered.hashCode()
activity!!.runOnUiThread { activity?.runOnUiThread {
setupContacts(contacts) setupContacts(filtered)
}
} }
} }
} }

View File

@ -13,10 +13,7 @@ import android.provider.ContactsContract.CommonDataKinds.Note
import android.provider.MediaStore import android.provider.MediaStore
import android.util.SparseArray import android.util.SparseArray
import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.getIntValue import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.extensions.getStringValue
import com.simplemobiletools.commons.extensions.showErrorToast
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.helpers.SORT_BY_FIRST_NAME import com.simplemobiletools.commons.helpers.SORT_BY_FIRST_NAME
import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME
import com.simplemobiletools.commons.helpers.SORT_BY_SURNAME import com.simplemobiletools.commons.helpers.SORT_BY_SURNAME
@ -57,8 +54,9 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
val notes = "" val notes = ""
val groups = ArrayList<Group>()
val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName, val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName,
starred, contactId, thumbnailUri, null, notes) starred, contactId, thumbnailUri, null, notes, groups)
contacts.put(id, contact) contacts.put(id, contact)
} while (cursor.moveToNext()) } while (cursor.moveToNext())
} }
@ -103,6 +101,13 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
contacts[key]?.notes = notes.valueAt(i) contacts[key]?.notes = notes.valueAt(i)
} }
val groups = getContactGroups(getStoredGroups())
size = groups.size()
for (i in 0 until size) {
val key = groups.keyAt(i)
contacts[key]?.groups = groups.valueAt(i)
}
activity.dbHelper.getContacts().forEach { activity.dbHelper.getContacts().forEach {
contacts.put(it.id, it) contacts.put(it.id, it)
} }
@ -111,7 +116,9 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
var resultContacts = ArrayList<Contact>(contactsSize) var resultContacts = ArrayList<Contact>(contactsSize)
(0 until contactsSize).mapTo(resultContacts) { contacts.valueAt(it) } (0 until contactsSize).mapTo(resultContacts) { contacts.valueAt(it) }
resultContacts = resultContacts.distinctBy { it.contactId } as ArrayList<Contact> resultContacts = resultContacts.distinctBy { it.contactId } as ArrayList<Contact>
callback(resultContacts) activity.runOnUiThread {
callback(resultContacts)
}
}.start() }.start()
} }
@ -305,6 +312,109 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
return notes return notes
} }
private fun getContactGroups(storedGroups: ArrayList<Group>, contactId: Int? = null): SparseArray<ArrayList<Group>> {
val groups = SparseArray<ArrayList<Group>>()
val uri = ContactsContract.Data.CONTENT_URI
val projection = arrayOf(
ContactsContract.Data.CONTACT_ID,
ContactsContract.Data.DATA1
)
var selection = "${ContactsContract.Data.MIMETYPE} = ?"
var selectionArgs = arrayOf(CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE)
if (contactId != null) {
selection += " AND ${ContactsContract.Data.CONTACT_ID} = ?"
selectionArgs = arrayOf(CommonDataKinds.GroupMembership.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.CONTACT_ID)
val newRowId = cursor.getLongValue(ContactsContract.Data.DATA1)
if (groups[id] == null) {
groups.put(id, ArrayList())
}
val groupTitle = storedGroups.firstOrNull { it.id == newRowId }?.title ?: continue
val group = Group(newRowId, groupTitle)
groups[id]!!.add(group)
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity.showErrorToast(e)
} finally {
cursor?.close()
}
return groups
}
fun getStoredGroups(): ArrayList<Group> {
val groups = ArrayList<Group>()
val uri = ContactsContract.Groups.CONTENT_URI
val projection = arrayOf(
ContactsContract.Groups._ID,
ContactsContract.Groups.TITLE
)
val selection = "${ContactsContract.Groups.AUTO_ADD} = ? AND ${ContactsContract.Groups.FAVORITES} = ? AND ${ContactsContract.Groups.SYSTEM_ID} IS NULL"
val selectionArgs = arrayOf("0", "0")
var cursor: Cursor? = null
try {
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor?.moveToFirst() == true) {
do {
val id = cursor.getLongValue(ContactsContract.Groups._ID)
val title = cursor.getStringValue(ContactsContract.Groups.TITLE)
groups.add(Group(id, title))
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity.showErrorToast(e)
} finally {
cursor?.close()
}
return groups
}
fun createNewGroup(title: String): Group? {
try {
val operations = ArrayList<ContentProviderOperation>()
ContentProviderOperation.newInsert(ContactsContract.Groups.CONTENT_URI).apply {
withValue(ContactsContract.Groups.TITLE, title)
operations.add(build())
}
val results = activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
val rawId = ContentUris.parseId(results[0].uri)
return Group(rawId, title)
} catch (e: Exception) {
activity.showErrorToast(e)
}
return null
}
fun deleteGroup(id: Long) {
try {
val operations = ArrayList<ContentProviderOperation>()
val uri = ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, id).buildUpon()
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
.build()
operations.add(ContentProviderOperation.newDelete(uri).build())
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
} catch (e: Exception) {
activity.showErrorToast(e)
}
}
fun getContactWithId(id: Int, isLocalPrivate: Boolean): Contact? { fun getContactWithId(id: Int, isLocalPrivate: Boolean): Contact? {
if (id == 0) { if (id == 0) {
return null return null
@ -312,14 +422,26 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
return activity.dbHelper.getContactWithId(id) return activity.dbHelper.getContactWithId(id)
} }
val uri = ContactsContract.Data.CONTENT_URI
val projection = getContactProjection()
val selection = "${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?" val selection = "${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
val selectionArgs = arrayOf(CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, id.toString()) val selectionArgs = arrayOf(CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, id.toString())
return parseContactCursor(selection, selectionArgs)
}
fun getContactWithLookupKey(key: String): Contact? {
val selection = "${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.Data.LOOKUP_KEY} = ?"
val selectionArgs = arrayOf(CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, key)
return parseContactCursor(selection, selectionArgs)
}
private fun parseContactCursor(selection: String, selectionArgs: Array<String>): Contact? {
val storedGroups = getStoredGroups()
val uri = ContactsContract.Data.CONTENT_URI
val projection = getContactProjection()
var cursor: Cursor? = null var cursor: Cursor? = null
try { try {
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null) cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor?.moveToFirst() == true) { if (cursor?.moveToFirst() == true) {
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
val firstName = cursor.getStringValue(CommonDataKinds.StructuredName.GIVEN_NAME) ?: "" val firstName = cursor.getStringValue(CommonDataKinds.StructuredName.GIVEN_NAME) ?: ""
val middleName = cursor.getStringValue(CommonDataKinds.StructuredName.MIDDLE_NAME) ?: "" val middleName = cursor.getStringValue(CommonDataKinds.StructuredName.MIDDLE_NAME) ?: ""
val surname = cursor.getStringValue(CommonDataKinds.StructuredName.FAMILY_NAME) ?: "" val surname = cursor.getStringValue(CommonDataKinds.StructuredName.FAMILY_NAME) ?: ""
@ -332,8 +454,10 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: "" val accountName = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: ""
val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED)
val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
val groups = getContactGroups(storedGroups, contactId)[contactId] ?: ArrayList()
val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
return Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName, starred, contactId, thumbnailUri, null, notes) return Contact(id, firstName, middleName, surname, photoUri, number, emails, addresses, events, accountName, starred, contactId,
thumbnailUri, null, notes, groups)
} }
} finally { } finally {
cursor?.close() cursor?.close()
@ -539,6 +663,24 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
operations.add(build()) operations.add(build())
} }
// delete groups
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? "
val selectionArgs = arrayOf(contact.id.toString(), CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE)
withSelection(selection, selectionArgs)
operations.add(build())
}
// add groups
contact.groups.forEach {
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
withValue(ContactsContract.Data.RAW_CONTACT_ID, contact.id)
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE)
withValue(CommonDataKinds.GroupMembership.GROUP_ROW_ID, it.id)
operations.add(build())
}
}
// favorite // favorite
try { try {
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, contact.contactId.toString()) val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, contact.contactId.toString())
@ -673,6 +815,16 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
operations.add(build()) operations.add(build())
} }
// groups
contact.groups.forEach {
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE)
withValue(CommonDataKinds.GroupMembership.GROUP_ROW_ID, it.id)
operations.add(build())
}
}
// photo (inspired by https://gist.github.com/slightfoot/5985900) // photo (inspired by https://gist.github.com/slightfoot/5985900)
var fullSizePhotoData: ByteArray? = null var fullSizePhotoData: ByteArray? = null
var scaledSizePhotoData: ByteArray? var scaledSizePhotoData: ByteArray?

View File

@ -163,8 +163,9 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
val notes = cursor.getStringValue(COL_NOTES) val notes = cursor.getStringValue(COL_NOTES)
val starred = cursor.getIntValue(COL_STARRED) val starred = cursor.getIntValue(COL_STARRED)
val groups = ArrayList<Group>()
val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, addresses, events, SMT_PRIVATE, starred, id, "", photo, notes) val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, addresses, events, SMT_PRIVATE, starred, id, "", photo, notes, groups)
contacts.add(contact) contacts.add(contact)
} }
} }

View File

@ -28,6 +28,7 @@ class VcfImporter(val activity: SimpleActivity) {
private var curEmails = ArrayList<Email>() private var curEmails = ArrayList<Email>()
private var curEvents = ArrayList<Event>() private var curEvents = ArrayList<Event>()
private var curAddresses = ArrayList<Address>() private var curAddresses = ArrayList<Address>()
private var curGroups = ArrayList<Group>()
private var isGettingPhoto = false private var isGettingPhoto = false
private var currentPhotoString = StringBuilder() private var currentPhotoString = StringBuilder()
@ -234,7 +235,8 @@ class VcfImporter(val activity: SimpleActivity) {
} }
private fun saveContact(source: String) { private fun saveContact(source: String) {
val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curAddresses, curEvents, source, 0, 0, "", null, curNotes) val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curAddresses, curEvents,
source, 0, 0, "", null, curNotes, curGroups)
if (ContactsHelper(activity).insertContact(contact)) { if (ContactsHelper(activity).insertContact(contact)) {
contactsImported++ contactsImported++
} }
@ -250,6 +252,7 @@ class VcfImporter(val activity: SimpleActivity) {
curEmails = ArrayList() curEmails = ArrayList()
curEvents = ArrayList() curEvents = ArrayList()
curAddresses = ArrayList() curAddresses = ArrayList()
curGroups = ArrayList()
isGettingPhoto = false isGettingPhoto = false
currentPhotoString = StringBuilder() currentPhotoString = StringBuilder()

View File

@ -0,0 +1,14 @@
package com.simplemobiletools.contacts.interfaces
import com.simplemobiletools.contacts.activities.MainActivity
import com.simplemobiletools.contacts.models.Contact
interface FragmentInterface {
fun setupFragment(activity: MainActivity)
fun textColorChanged(color: Int)
fun primaryColorChanged(color: Int)
fun refreshContacts(contacts: ArrayList<Contact>)
}

View File

@ -1,7 +1,7 @@
package com.simplemobiletools.contacts.interfaces package com.simplemobiletools.contacts.interfaces
interface RefreshContactsListener { interface RefreshContactsListener {
fun refreshContacts() fun refreshContacts(refreshContactsTab: Boolean, refreshFavoritesTab: Boolean)
fun refreshFavorites() fun refreshFavorites()
} }

View File

@ -7,7 +7,8 @@ import com.simplemobiletools.commons.helpers.SORT_DESCENDING
data class Contact(val id: Int, var firstName: String, var middleName: String, var surname: String, var photoUri: String, data class Contact(val id: Int, var firstName: String, var middleName: String, var surname: String, var photoUri: String,
var phoneNumbers: ArrayList<PhoneNumber>, var emails: ArrayList<Email>, var addresses: ArrayList<Address>, var events: ArrayList<Event>, var phoneNumbers: ArrayList<PhoneNumber>, var emails: ArrayList<Email>, var addresses: ArrayList<Address>, var events: ArrayList<Event>,
var source: String, var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?, var notes: String) : Comparable<Contact> { var source: String, var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?, var notes: String,
var groups: ArrayList<Group>) : Comparable<Contact> {
companion object { companion object {
var sorting = 0 var sorting = 0
} }

View File

@ -0,0 +1,3 @@
package com.simplemobiletools.contacts.models
data class Group(var id: Long, var title: String)

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

View File

@ -313,6 +313,44 @@
android:textCursorDrawable="@null" android:textCursorDrawable="@null"
android:textSize="@dimen/bigger_text_size"/> android:textSize="@dimen/bigger_text_size"/>
<ImageView
android:id="@+id/contact_groups_image"
android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_groups_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_group"/>
<LinearLayout
android:id="@+id/contact_groups_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_notes"
android:layout_marginTop="@dimen/medium_margin"
android:layout_toRightOf="@+id/contact_name_image"
android:orientation="vertical">
<include layout="@layout/item_group"/>
</LinearLayout>
<ImageView
android:id="@+id/contact_groups_add_new"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_groups_holder"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/small_margin"
android:background="@drawable/button_background"
android:paddingBottom="@dimen/medium_margin"
android:paddingLeft="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin"
android:paddingTop="@dimen/medium_margin"
android:src="@drawable/ic_plus"/>
<ImageView <ImageView
android:id="@+id/contact_source_image" android:id="@+id/contact_source_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
@ -328,7 +366,7 @@
android:id="@+id/contact_source" android:id="@+id/contact_source"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/contact_notes" android:layout_below="@+id/contact_groups_add_new"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginTop="@dimen/medium_margin" android:layout_marginTop="@dimen/medium_margin"
android:layout_toRightOf="@+id/contact_name_image" android:layout_toRightOf="@+id/contact_name_image"

View File

@ -28,6 +28,12 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:icon="@drawable/ic_star_on"/> android:icon="@drawable/ic_star_on"/>
<android.support.design.widget.TabItem
android:id="@+id/tab_groups"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="@drawable/ic_group"/>
</android.support.design.widget.TabLayout> </android.support.design.widget.TabLayout>
<com.booking.rtlviewpager.RtlViewPager <com.booking.rtlviewpager.RtlViewPager

View File

@ -239,6 +239,26 @@
android:paddingTop="@dimen/normal_margin" android:paddingTop="@dimen/normal_margin"
android:textSize="@dimen/bigger_text_size"/> android:textSize="@dimen/bigger_text_size"/>
<ImageView
android:id="@+id/contact_groups_image"
android:layout_width="@dimen/contact_icons_size"
android:layout_height="@dimen/contact_icons_size"
android:layout_alignTop="@+id/contact_groups_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_group"/>
<LinearLayout
android:id="@+id/contact_groups_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/contact_notes"
android:layout_toRightOf="@+id/contact_name_image"
android:orientation="vertical"
android:paddingLeft="@dimen/small_margin"/>
<ImageView <ImageView
android:id="@+id/contact_source_image" android:id="@+id/contact_source_image"
android:layout_width="@dimen/contact_icons_size" android:layout_width="@dimen/contact_icons_size"
@ -254,7 +274,7 @@
android:id="@+id/contact_source" android:id="@+id/contact_source"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/contact_notes" android:layout_below="@+id/contact_groups_holder"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_toRightOf="@+id/contact_name_image" android:layout_toRightOf="@+id/contact_name_image"
android:lines="1" android:lines="1"

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/group_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/name"/>
<com.simplemobiletools.commons.views.MyEditText
android:id="@+id/group_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_margin"
android:inputType="textCapSentences"
android:singleLine="true"
android:textCursorDrawable="@null"
android:textSize="@dimen/normal_text_size"/>
</LinearLayout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_radio_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/dialog_groups_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/normal_margin"/>
</ScrollView>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<com.simplemobiletools.contacts.fragments.GroupsFragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/groups_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.simplemobiletools.contacts.fragments.GroupsFragment>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_checkbox_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/normal_margin"
android:paddingTop="@dimen/normal_margin">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/item_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"/>
</RelativeLayout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contact_group_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/contact_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/contact_group_remove"
android:layout_toStartOf="@+id/contact_group_remove"
android:alpha="0.5"
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/no_groups"
android:textSize="@dimen/bigger_text_size"/>
<ImageView
android:id="@+id/contact_group_remove"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/contact_group"
android:layout_alignParentRight="true"
android:layout_alignTop="@+id/contact_group"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/medium_margin"
android:layout_marginLeft="@dimen/small_margin"
android:layout_marginRight="@dimen/small_margin"
android:layout_marginTop="@dimen/medium_margin"
android:background="@drawable/button_background"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_minus"
android:visibility="gone"/>
</RelativeLayout>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<com.simplemobiletools.commons.views.MyTextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/activity_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/medium_margin"
android:paddingTop="@dimen/activity_margin"/>

View File

@ -4,6 +4,7 @@
android:id="@+id/contact_address_holder" android:id="@+id/contact_address_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/normal_margin" android:paddingBottom="@dimen/normal_margin"
android:paddingTop="@dimen/normal_margin"> android:paddingTop="@dimen/normal_margin">

View File

@ -4,6 +4,7 @@
android:id="@+id/contact_email_holder" android:id="@+id/contact_email_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/normal_margin" android:paddingBottom="@dimen/normal_margin"
android:paddingTop="@dimen/normal_margin"> android:paddingTop="@dimen/normal_margin">

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_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:ellipsize="end"
android:lines="1"
android:maxLines="1"
android:paddingBottom="@dimen/normal_margin"
android:paddingTop="@dimen/normal_margin"
android:singleLine="true"
android:textSize="@dimen/bigger_text_size"/>

View File

@ -4,6 +4,7 @@
android:id="@+id/contact_number_holder" android:id="@+id/contact_number_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/normal_margin" android:paddingBottom="@dimen/normal_margin"
android:paddingTop="@dimen/normal_margin"> android:paddingTop="@dimen/normal_margin">

View File

@ -6,6 +6,8 @@
<string name="updating">Aktualisiere…</string> <string name="updating">Aktualisiere…</string>
<string name="phone_storage">Gerätespeicher</string> <string name="phone_storage">Gerätespeicher</string>
<string name="phone_storage_hidden">Gerätespeicher (nicht sichtbar für andere Apps)</string> <string name="phone_storage_hidden">Gerätespeicher (nicht sichtbar für andere Apps)</string>
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="new_contact">Neuer Kontakt</string> <string name="new_contact">Neuer Kontakt</string>
<string name="edit_contact">Kontakt bearbeiten</string> <string name="edit_contact">Kontakt bearbeiten</string>
@ -27,6 +29,8 @@
<string name="on_contact_click">Beim Klicken auf den Kontakt</string> <string name="on_contact_click">Beim Klicken auf den Kontakt</string>
<string name="call_contact">Kontakt anrufen</string> <string name="call_contact">Kontakt anrufen</string>
<string name="view_contact">Kontaktdetails ansehen</string> <string name="view_contact">Kontaktdetails ansehen</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<!-- Emails --> <!-- Emails -->
<string name="email">Email</string> <string name="email">Email</string>

View File

@ -6,6 +6,8 @@
<string name="updating">Mise à jour…</string> <string name="updating">Mise à jour…</string>
<string name="phone_storage">Stockage du téléphone</string> <string name="phone_storage">Stockage du téléphone</string>
<string name="phone_storage_hidden">Stockage du téléphone (non visible par d\'autres applis)</string> <string name="phone_storage_hidden">Stockage du téléphone (non visible par d\'autres applis)</string>
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="new_contact">Nouveau contact</string> <string name="new_contact">Nouveau contact</string>
<string name="edit_contact">Modifier contact</string> <string name="edit_contact">Modifier contact</string>
@ -27,6 +29,8 @@
<string name="on_contact_click">Sur appui du contact</string> <string name="on_contact_click">Sur appui du contact</string>
<string name="call_contact">Appeler le contact</string> <string name="call_contact">Appeler le contact</string>
<string name="view_contact">Voir les détails du contact</string> <string name="view_contact">Voir les détails du contact</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<!-- Emails --> <!-- Emails -->
<string name="email">E-mail</string> <string name="email">E-mail</string>

View File

@ -6,6 +6,8 @@
<string name="updating">수정중…</string> <string name="updating">수정중…</string>
<string name="phone_storage">Phone storage</string> <string name="phone_storage">Phone storage</string>
<string name="phone_storage_hidden">Phone storage (not visible by other apps)</string> <string name="phone_storage_hidden">Phone storage (not visible by other apps)</string>
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="new_contact">새로운 연락처</string> <string name="new_contact">새로운 연락처</string>
<string name="edit_contact">연락처 수정</string> <string name="edit_contact">연락처 수정</string>
@ -27,6 +29,8 @@
<string name="on_contact_click">On contact click</string> <string name="on_contact_click">On contact click</string>
<string name="call_contact">Call contact</string> <string name="call_contact">Call contact</string>
<string name="view_contact">View contact details</string> <string name="view_contact">View contact details</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<!-- Emails --> <!-- Emails -->
<string name="email">이메일</string> <string name="email">이메일</string>

View File

@ -6,6 +6,8 @@
<string name="updating">A atualizar…</string> <string name="updating">A atualizar…</string>
<string name="phone_storage">Armazenamento do telefone</string> <string name="phone_storage">Armazenamento do telefone</string>
<string name="phone_storage_hidden">Armazenamento do telefone (não visível por outras alicações)</string> <string name="phone_storage_hidden">Armazenamento do telefone (não visível por outras alicações)</string>
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="new_contact">Novo contacto</string> <string name="new_contact">Novo contacto</string>
<string name="edit_contact">Editar contacto</string> <string name="edit_contact">Editar contacto</string>
@ -27,6 +29,8 @@
<string name="on_contact_click">Ao clicar no contacto</string> <string name="on_contact_click">Ao clicar no contacto</string>
<string name="call_contact">Ligar</string> <string name="call_contact">Ligar</string>
<string name="view_contact">Ver detalhes</string> <string name="view_contact">Ver detalhes</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<!-- Emails --> <!-- Emails -->
<string name="email">E-mail</string> <string name="email">E-mail</string>

View File

@ -6,6 +6,8 @@
<string name="updating">Обновление…</string> <string name="updating">Обновление…</string>
<string name="phone_storage">Память устройства</string> <string name="phone_storage">Память устройства</string>
<string name="phone_storage_hidden">Память устройства (не видна другим приложениям)</string> <string name="phone_storage_hidden">Память устройства (не видна другим приложениям)</string>
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="new_contact">Новый контакт</string> <string name="new_contact">Новый контакт</string>
<string name="edit_contact">Редактировать контакт</string> <string name="edit_contact">Редактировать контакт</string>
@ -27,6 +29,8 @@
<string name="on_contact_click">При нажатии на контакт</string> <string name="on_contact_click">При нажатии на контакт</string>
<string name="call_contact">Позвонить контакту</string> <string name="call_contact">Позвонить контакту</string>
<string name="view_contact">Просмотреть подробности о контакте</string> <string name="view_contact">Просмотреть подробности о контакте</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<!-- Emails --> <!-- Emails -->
<string name="email">Эл. почта</string> <string name="email">Эл. почта</string>

View File

@ -6,6 +6,8 @@
<string name="updating">Upravuje sa…</string> <string name="updating">Upravuje sa…</string>
<string name="phone_storage">Úložisko mobilu</string> <string name="phone_storage">Úložisko mobilu</string>
<string name="phone_storage_hidden">Úložisko mobilu (neviditeľné pre ostatné apky)</string> <string name="phone_storage_hidden">Úložisko mobilu (neviditeľné pre ostatné apky)</string>
<string name="no_groups">Žiadne skupiny</string>
<string name="create_new_group">Vytvoriť novú skupinu</string>
<string name="new_contact">Nový kontakt</string> <string name="new_contact">Nový kontakt</string>
<string name="edit_contact">Upraviť kontakt</string> <string name="edit_contact">Upraviť kontakt</string>
@ -27,6 +29,8 @@
<string name="on_contact_click">Po kliknutí na kontakt</string> <string name="on_contact_click">Po kliknutí na kontakt</string>
<string name="call_contact">Zavolať kontakt</string> <string name="call_contact">Zavolať kontakt</string>
<string name="view_contact">Zobraziť údaje kontaktu</string> <string name="view_contact">Zobraziť údaje kontaktu</string>
<string name="show_favorites_tab">Zobraziť okno s obľúbenými</string>
<string name="show_groups_tab">Zobraziť okno so skupinami</string>
<!-- Emails --> <!-- Emails -->
<string name="email">Email</string> <string name="email">Email</string>

View File

@ -6,6 +6,8 @@
<string name="updating">Uppdaterar…</string> <string name="updating">Uppdaterar…</string>
<string name="phone_storage">Telefonens lagringsutrymme</string> <string name="phone_storage">Telefonens lagringsutrymme</string>
<string name="phone_storage_hidden">Telefonens lagringsutrymme (inte synligt för andra appar)</string> <string name="phone_storage_hidden">Telefonens lagringsutrymme (inte synligt för andra appar)</string>
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="new_contact">Ny kontakt</string> <string name="new_contact">Ny kontakt</string>
<string name="edit_contact">Redigera kontakt</string> <string name="edit_contact">Redigera kontakt</string>
@ -27,6 +29,8 @@
<string name="on_contact_click">Vid kontakttryckning</string> <string name="on_contact_click">Vid kontakttryckning</string>
<string name="call_contact">Ring kontakt</string> <string name="call_contact">Ring kontakt</string>
<string name="view_contact">Visa kontaktuppgifter</string> <string name="view_contact">Visa kontaktuppgifter</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<!-- Emails --> <!-- Emails -->
<string name="email">E-post</string> <string name="email">E-post</string>

View File

@ -6,6 +6,8 @@
<string name="updating">更新中…</string> <string name="updating">更新中…</string>
<string name="phone_storage">手機空間</string> <string name="phone_storage">手機空間</string>
<string name="phone_storage_hidden">手機空間 (其他程式不可見)</string> <string name="phone_storage_hidden">手機空間 (其他程式不可見)</string>
<string name="no_groups">沒有群組</string>
<string name="create_new_group">Create a new group</string>
<string name="new_contact">新聯絡人</string> <string name="new_contact">新聯絡人</string>
<string name="edit_contact">編輯聯絡人</string> <string name="edit_contact">編輯聯絡人</string>
@ -27,6 +29,8 @@
<string name="on_contact_click">點擊聯絡人</string> <string name="on_contact_click">點擊聯絡人</string>
<string name="call_contact">打電話給聯絡人</string> <string name="call_contact">打電話給聯絡人</string>
<string name="view_contact">顯示聯絡人資料</string> <string name="view_contact">顯示聯絡人資料</string>
<string name="show_favorites_tab">顯示我的最愛頁面</string>
<string name="show_groups_tab">顯示群組頁面</string>
<!-- Emails --> <!-- Emails -->
<string name="email">信箱</string> <string name="email">信箱</string>

View File

@ -6,6 +6,8 @@
<string name="updating">Updating…</string> <string name="updating">Updating…</string>
<string name="phone_storage">Phone storage</string> <string name="phone_storage">Phone storage</string>
<string name="phone_storage_hidden">Phone storage (not visible by other apps)</string> <string name="phone_storage_hidden">Phone storage (not visible by other apps)</string>
<string name="no_groups">No groups</string>
<string name="create_new_group">Create a new group</string>
<string name="new_contact">New contact</string> <string name="new_contact">New contact</string>
<string name="edit_contact">Edit contact</string> <string name="edit_contact">Edit contact</string>
@ -27,6 +29,8 @@
<string name="on_contact_click">On contact click</string> <string name="on_contact_click">On contact click</string>
<string name="call_contact">Call contact</string> <string name="call_contact">Call contact</string>
<string name="view_contact">View contact details</string> <string name="view_contact">View contact details</string>
<string name="show_favorites_tab">Show favorites tab</string>
<string name="show_groups_tab">Show groups tab</string>
<!-- Emails --> <!-- Emails -->
<string name="email">Email</string> <string name="email">Email</string>