@ -1,6 +1,13 @@
|
||||
Changelog
|
||||
==========
|
||||
|
||||
Version 3.4.0 *(2018-03-21)*
|
||||
----------------------------
|
||||
|
||||
* Added groups
|
||||
* Make phone numbers, emails and addresses clickable on the view screen
|
||||
* Many smaller improvements and bugfixes
|
||||
|
||||
Version 3.3.3 *(2018-03-04)*
|
||||
----------------------------
|
||||
|
||||
|
@ -10,8 +10,8 @@ android {
|
||||
applicationId "com.simplemobiletools.contacts"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 27
|
||||
versionCode 14
|
||||
versionName "3.3.3"
|
||||
versionCode 15
|
||||
versionName "3.4.0"
|
||||
setProperty("archivesBaseName", "contacts")
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ ext {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.simplemobiletools:commons:3.16.11'
|
||||
implementation 'com.simplemobiletools:commons:3.16.12'
|
||||
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'
|
||||
|
@ -74,6 +74,10 @@
|
||||
android:label="@string/settings"
|
||||
android:parentActivityName=".activities.MainActivity"/>
|
||||
|
||||
<activity
|
||||
android:name=".activities.GroupContactsActivity"
|
||||
android:parentActivityName=".activities.MainActivity"/>
|
||||
|
||||
<activity
|
||||
android:name=".activities.ViewContactActivity"
|
||||
android:label="@string/details"
|
||||
|
@ -27,9 +27,9 @@ import com.simplemobiletools.contacts.models.*
|
||||
import kotlinx.android.synthetic.main.activity_edit_contact.*
|
||||
import kotlinx.android.synthetic.main.item_edit_address.view.*
|
||||
import kotlinx.android.synthetic.main.item_edit_email.view.*
|
||||
import kotlinx.android.synthetic.main.item_edit_group.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_group.view.*
|
||||
import org.joda.time.DateTime
|
||||
import org.joda.time.format.DateTimeFormat
|
||||
import java.util.*
|
||||
@ -331,7 +331,7 @@ class EditContactActivity : ContactActivity() {
|
||||
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)
|
||||
groupHolder = layoutInflater.inflate(R.layout.item_edit_group, contact_groups_holder, false)
|
||||
contact_groups_holder.addView(groupHolder)
|
||||
}
|
||||
|
||||
@ -359,7 +359,7 @@ class EditContactActivity : ContactActivity() {
|
||||
}
|
||||
|
||||
if (groups.isEmpty()) {
|
||||
layoutInflater.inflate(R.layout.item_group, contact_groups_holder, false).apply {
|
||||
layoutInflater.inflate(R.layout.item_edit_group, contact_groups_holder, false).apply {
|
||||
contact_group.apply {
|
||||
alpha = 0.5f
|
||||
text = getString(R.string.no_groups)
|
||||
|
@ -0,0 +1,118 @@
|
||||
package com.simplemobiletools.contacts.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.contacts.R
|
||||
import com.simplemobiletools.contacts.adapters.ContactsAdapter
|
||||
import com.simplemobiletools.contacts.dialogs.SelectContactsDialog
|
||||
import com.simplemobiletools.contacts.extensions.*
|
||||
import com.simplemobiletools.contacts.helpers.*
|
||||
import com.simplemobiletools.contacts.interfaces.RefreshContactsListener
|
||||
import com.simplemobiletools.contacts.interfaces.RemoveFromGroupListener
|
||||
import com.simplemobiletools.contacts.models.Contact
|
||||
import com.simplemobiletools.contacts.models.Group
|
||||
import kotlinx.android.synthetic.main.activity_group_contacts.*
|
||||
|
||||
class GroupContactsActivity : SimpleActivity(), RemoveFromGroupListener, RefreshContactsListener {
|
||||
private var allContacts = ArrayList<Contact>()
|
||||
private var groupContacts = ArrayList<Contact>()
|
||||
private var wasInit = false
|
||||
lateinit var group: Group
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_group_contacts)
|
||||
updateTextColors(group_contacts_coordinator)
|
||||
|
||||
group = intent.extras.getSerializable(GROUP) as Group
|
||||
supportActionBar?.title = group.title
|
||||
|
||||
group_contacts_fab.setOnClickListener {
|
||||
if (wasInit) {
|
||||
fabClicked()
|
||||
}
|
||||
}
|
||||
|
||||
group_contacts_placeholder_2.setOnClickListener {
|
||||
fabClicked()
|
||||
}
|
||||
|
||||
group_contacts_placeholder_2.underlineText()
|
||||
group_contacts_placeholder_2.setTextColor(getAdjustedPrimaryColor())
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
refreshContacts()
|
||||
}
|
||||
|
||||
private fun fabClicked() {
|
||||
SelectContactsDialog(this, allContacts, groupContacts) { addedContacts, removedContacts ->
|
||||
Thread {
|
||||
addContactsToGroup(addedContacts, group.id)
|
||||
removeContactsFromGroup(removedContacts, group.id)
|
||||
refreshContacts()
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshContacts() {
|
||||
ContactsHelper(this).getContacts {
|
||||
wasInit = true
|
||||
allContacts = it
|
||||
|
||||
groupContacts = it.filter { it.groups.map { it.id }.contains(group.id) } as ArrayList<Contact>
|
||||
group_contacts_placeholder_2.beVisibleIf(groupContacts.isEmpty())
|
||||
group_contacts_placeholder.beVisibleIf(groupContacts.isEmpty())
|
||||
group_contacts_list.beVisibleIf(groupContacts.isNotEmpty())
|
||||
|
||||
Contact.sorting = config.sorting
|
||||
groupContacts.sort()
|
||||
|
||||
updateContacts(groupContacts)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateContacts(contacts: ArrayList<Contact>) {
|
||||
val currAdapter = group_contacts_list.adapter
|
||||
if (currAdapter == null) {
|
||||
ContactsAdapter(this, contacts, this, LOCATION_GROUP_CONTACTS, this, group_contacts_list, group_contacts_fastscroller) {
|
||||
when (config.onContactClick) {
|
||||
ON_CLICK_CALL_CONTACT -> {
|
||||
val contact = it as Contact
|
||||
if (contact.phoneNumbers.isNotEmpty()) {
|
||||
tryStartCall(it)
|
||||
} else {
|
||||
toast(R.string.no_phone_number_found)
|
||||
}
|
||||
}
|
||||
ON_CLICK_VIEW_CONTACT -> viewContact(it as Contact)
|
||||
ON_CLICK_EDIT_CONTACT -> editContact(it as Contact)
|
||||
}
|
||||
}.apply {
|
||||
setupDragListener(true)
|
||||
addVerticalDividers(true)
|
||||
group_contacts_list.adapter = this
|
||||
}
|
||||
|
||||
group_contacts_fastscroller.setScrollTo(0)
|
||||
group_contacts_fastscroller.setViews(group_contacts_list) {
|
||||
val item = (group_contacts_list.adapter as ContactsAdapter).contactItems.getOrNull(it)
|
||||
group_contacts_fastscroller.updateBubbleText(item?.getBubbleText() ?: "")
|
||||
}
|
||||
} else {
|
||||
(currAdapter as ContactsAdapter).updateItems(contacts)
|
||||
}
|
||||
}
|
||||
|
||||
override fun refreshContacts(refreshTabsMask: Int) {
|
||||
refreshContacts()
|
||||
}
|
||||
|
||||
override fun removeFromGroup(contacts: ArrayList<Contact>) {
|
||||
ContactsHelper(this).removeContactsFromGroup(contacts, group.id)
|
||||
if (groupContacts.size == 0) {
|
||||
refreshContacts()
|
||||
}
|
||||
}
|
||||
}
|
@ -26,9 +26,7 @@ import com.simplemobiletools.contacts.dialogs.ImportContactsDialog
|
||||
import com.simplemobiletools.contacts.extensions.config
|
||||
import com.simplemobiletools.contacts.extensions.dbHelper
|
||||
import com.simplemobiletools.contacts.extensions.getTempFile
|
||||
import com.simplemobiletools.contacts.fragments.MyViewPagerFragment
|
||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.helpers.VcfExporter
|
||||
import com.simplemobiletools.contacts.helpers.*
|
||||
import com.simplemobiletools.contacts.interfaces.RefreshContactsListener
|
||||
import com.simplemobiletools.contacts.models.Contact
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
@ -93,8 +91,9 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
|
||||
val configShowContactThumbnails = config.showContactThumbnails
|
||||
if (storedShowContactThumbnails != configShowContactThumbnails) {
|
||||
contacts_fragment?.showContactThumbnailsChanged(configShowContactThumbnails)
|
||||
favorites_fragment?.showContactThumbnailsChanged(configShowContactThumbnails)
|
||||
getAllFragments().forEach {
|
||||
it?.showContactThumbnailsChanged(configShowContactThumbnails)
|
||||
}
|
||||
}
|
||||
|
||||
val configTextColor = config.textColor
|
||||
@ -102,8 +101,9 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
getInactiveTabIndexes(viewpager.currentItem).forEach {
|
||||
main_tabs_holder.getTabAt(it)?.icon?.applyColorFilter(configTextColor)
|
||||
}
|
||||
contacts_fragment?.textColorChanged(configTextColor)
|
||||
favorites_fragment?.textColorChanged(configTextColor)
|
||||
getAllFragments().forEach {
|
||||
it?.textColorChanged(configTextColor)
|
||||
}
|
||||
}
|
||||
|
||||
val configBackgroundColor = config.backgroundColor
|
||||
@ -115,8 +115,9 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
if (storedPrimaryColor != configPrimaryColor) {
|
||||
main_tabs_holder.setSelectedTabIndicatorColor(getAdjustedPrimaryColor())
|
||||
main_tabs_holder.getTabAt(viewpager.currentItem)?.icon?.applyColorFilter(getAdjustedPrimaryColor())
|
||||
contacts_fragment?.primaryColorChanged(configPrimaryColor)
|
||||
favorites_fragment?.primaryColorChanged(configPrimaryColor)
|
||||
getAllFragments().forEach {
|
||||
it?.primaryColorChanged()
|
||||
}
|
||||
}
|
||||
|
||||
val configStartNameWithSurname = config.startNameWithSurname
|
||||
@ -130,9 +131,10 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
initFragments()
|
||||
}
|
||||
|
||||
contacts_fragment?.onActivityResume()
|
||||
favorites_fragment?.onActivityResume()
|
||||
refreshContacts(true, true)
|
||||
getAllFragments().forEach {
|
||||
it?.onActivityResume()
|
||||
}
|
||||
refreshContacts(ALL_TABS_MASK)
|
||||
}
|
||||
|
||||
if (hasPermission(PERMISSION_WRITE_CONTACTS)) {
|
||||
@ -152,6 +154,12 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu, menu)
|
||||
val currentPage = viewpager?.currentItem
|
||||
menu.apply {
|
||||
findItem(R.id.search).isVisible = currentPage != LOCATION_GROUPS_TAB
|
||||
findItem(R.id.sort).isVisible = currentPage != LOCATION_GROUPS_TAB
|
||||
findItem(R.id.filter).isVisible = currentPage != LOCATION_GROUPS_TAB
|
||||
}
|
||||
setupSearch(menu)
|
||||
return true
|
||||
}
|
||||
@ -193,7 +201,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
if (isSearchOpen) {
|
||||
(getCurrentFragment() as? MyViewPagerFragment)?.onSearchQueryChanged(newText)
|
||||
getCurrentFragment()?.onSearchQueryChanged(newText)
|
||||
}
|
||||
return true
|
||||
}
|
||||
@ -202,13 +210,13 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
|
||||
MenuItemCompat.setOnActionExpandListener(searchMenuItem, object : MenuItemCompat.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
||||
(getCurrentFragment() as? MyViewPagerFragment)?.onSearchOpened()
|
||||
getCurrentFragment()?.onSearchOpened()
|
||||
isSearchOpen = true
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
||||
(getCurrentFragment() as? MyViewPagerFragment)?.onSearchClosed()
|
||||
getCurrentFragment()?.onSearchClosed()
|
||||
isSearchOpen = false
|
||||
return true
|
||||
}
|
||||
@ -266,12 +274,12 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
private fun getInactiveTabIndexes(activeIndex: Int) = arrayListOf(0, 1, 2).filter { it != activeIndex }
|
||||
|
||||
private fun initFragments() {
|
||||
refreshContacts(true, true)
|
||||
refreshContacts(ALL_TABS_MASK)
|
||||
viewpager.offscreenPageLimit = 2
|
||||
viewpager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
if (isSearchOpen) {
|
||||
(getCurrentFragment() as? MyViewPagerFragment)?.onSearchQueryChanged("")
|
||||
getCurrentFragment()?.onSearchQueryChanged("")
|
||||
searchMenuItem?.collapseActionView()
|
||||
}
|
||||
}
|
||||
@ -281,12 +289,12 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
main_tabs_holder.getTabAt(position)?.select()
|
||||
contacts_fragment?.finishActMode()
|
||||
favorites_fragment?.finishActMode()
|
||||
getAllFragments().forEach {
|
||||
it?.finishActMode()
|
||||
}
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
})
|
||||
viewpager.currentItem = config.lastUsedViewPagerPage
|
||||
|
||||
main_tabs_holder.onTabSelectionChanged(
|
||||
tabUnselectedAction = {
|
||||
@ -305,14 +313,14 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
|
||||
private fun showSortingDialog() {
|
||||
ChangeSortingDialog(this) {
|
||||
refreshContacts(true, true)
|
||||
refreshContacts(CONTACTS_TAB_MASK or FAVORITES_TAB_MASK)
|
||||
}
|
||||
}
|
||||
|
||||
fun showFilterDialog() {
|
||||
FilterContactSourcesDialog(this) {
|
||||
contacts_fragment?.forceListRedraw = true
|
||||
refreshContacts(true, false)
|
||||
refreshContacts(CONTACTS_TAB_MASK)
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,7 +342,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
ImportContactsDialog(this, path) {
|
||||
if (it) {
|
||||
runOnUiThread {
|
||||
refreshContacts(true, true)
|
||||
refreshContacts(ALL_TABS_MASK)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -397,7 +405,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
BuildConfig.VERSION_NAME, faqItems)
|
||||
}
|
||||
|
||||
override fun refreshContacts(refreshContactsTab: Boolean, refreshFavoritesTab: Boolean) {
|
||||
override fun refreshContacts(refreshTabsMask: Int) {
|
||||
if (isActivityDestroyed()) {
|
||||
return
|
||||
}
|
||||
@ -409,21 +417,27 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
|
||||
if (viewpager.adapter == null) {
|
||||
viewpager.adapter = ViewPagerAdapter(this, it)
|
||||
viewpager.currentItem = config.lastUsedViewPagerPage
|
||||
}
|
||||
|
||||
if (refreshContactsTab) {
|
||||
if (refreshTabsMask and CONTACTS_TAB_MASK != 0) {
|
||||
contacts_fragment?.refreshContacts(it)
|
||||
}
|
||||
|
||||
if (refreshFavoritesTab) {
|
||||
if (refreshTabsMask and FAVORITES_TAB_MASK != 0) {
|
||||
favorites_fragment?.refreshContacts(it)
|
||||
}
|
||||
|
||||
if (refreshTabsMask and GROUPS_TAB_MASK != 0) {
|
||||
if (refreshTabsMask == GROUPS_TAB_MASK) {
|
||||
groups_fragment.skipHashComparing = true
|
||||
}
|
||||
groups_fragment?.refreshContacts(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun refreshFavorites() {
|
||||
refreshContacts(false, true)
|
||||
}
|
||||
private fun getAllFragments() = arrayListOf(contacts_fragment, favorites_fragment, groups_fragment)
|
||||
|
||||
private fun checkWhatsNewDialog() {
|
||||
arrayListOf<Release>().apply {
|
||||
|
@ -23,7 +23,7 @@ import com.simplemobiletools.contacts.models.Contact
|
||||
import kotlinx.android.synthetic.main.layout_select_contact.*
|
||||
|
||||
class SelectContactActivity : SimpleActivity() {
|
||||
private var isGetEmailIntent = false
|
||||
private var specialMimeType: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -34,7 +34,11 @@ class SelectContactActivity : SimpleActivity() {
|
||||
if (it) {
|
||||
handlePermission(PERMISSION_WRITE_CONTACTS) {
|
||||
if (it) {
|
||||
isGetEmailIntent = intent.data == ContactsContract.CommonDataKinds.Email.CONTENT_URI
|
||||
specialMimeType = when (intent.data) {
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_URI -> ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE
|
||||
ContactsContract.CommonDataKinds.Phone.CONTENT_URI -> ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
||||
else -> null
|
||||
}
|
||||
initContacts()
|
||||
} else {
|
||||
toast(R.string.no_contacts_permission)
|
||||
@ -81,8 +85,13 @@ class SelectContactActivity : SimpleActivity() {
|
||||
}
|
||||
|
||||
var contacts = it.filter {
|
||||
if (isGetEmailIntent) {
|
||||
(it.source != SMT_PRIVATE && it.emails.isNotEmpty())
|
||||
if (specialMimeType != null) {
|
||||
val hasRequiredValues = when (specialMimeType) {
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE -> it.emails.isNotEmpty()
|
||||
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> it.phoneNumbers.isNotEmpty()
|
||||
else -> true
|
||||
}
|
||||
it.source != SMT_PRIVATE && hasRequiredValues
|
||||
} else {
|
||||
true
|
||||
}
|
||||
@ -119,12 +128,15 @@ class SelectContactActivity : SimpleActivity() {
|
||||
}
|
||||
|
||||
private fun getResultUri(contact: Contact): Uri {
|
||||
return if (isGetEmailIntent) {
|
||||
val emailID = ContactsHelper(this).getContactDataId(contact.id.toString())
|
||||
Uri.withAppendedPath(ContactsContract.Data.CONTENT_URI, emailID)
|
||||
} else {
|
||||
val lookupKey = ContactsHelper(this).getContactLookupKey(contact.id.toString())
|
||||
Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
|
||||
return when {
|
||||
specialMimeType != null -> {
|
||||
val contactId = ContactsHelper(this).getContactMimeTypeId(contact.id.toString(), specialMimeType!!)
|
||||
Uri.withAppendedPath(ContactsContract.Data.CONTENT_URI, contactId)
|
||||
}
|
||||
else -> {
|
||||
val lookupKey = ContactsHelper(this).getContactLookupKey(contact.id.toString())
|
||||
Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
}
|
||||
|
||||
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)) {
|
||||
@ -69,6 +70,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
val lookupKey = getLookupKeyFromUri(data)
|
||||
if (lookupKey != null) {
|
||||
contact = ContactsHelper(this).getContactWithLookupKey(lookupKey)
|
||||
wasLookupKeyUsed = true
|
||||
}
|
||||
|
||||
getLookupUriRawId(data)
|
||||
@ -82,7 +84,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
if (contactId != 0 && contact == null) {
|
||||
if (contactId != 0 && !wasLookupKeyUsed) {
|
||||
contact = ContactsHelper(this).getContactWithId(contactId, intent.getBooleanExtra(IS_PRIVATE, false))
|
||||
if (contact == null) {
|
||||
toast(R.string.unknown_error_occurred)
|
||||
|
@ -11,28 +11,34 @@ import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.signature.ObjectKey
|
||||
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
|
||||
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
||||
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||
import com.simplemobiletools.commons.extensions.beVisibleIf
|
||||
import com.simplemobiletools.commons.extensions.getColoredDrawableWithColor
|
||||
import com.simplemobiletools.commons.extensions.isActivityDestroyed
|
||||
import com.simplemobiletools.commons.models.RadioItem
|
||||
import com.simplemobiletools.commons.views.FastScroller
|
||||
import com.simplemobiletools.commons.views.MyRecyclerView
|
||||
import com.simplemobiletools.contacts.R
|
||||
import com.simplemobiletools.contacts.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.dialogs.CreateNewGroupDialog
|
||||
import com.simplemobiletools.contacts.extensions.addContactsToGroup
|
||||
import com.simplemobiletools.contacts.extensions.config
|
||||
import com.simplemobiletools.contacts.extensions.editContact
|
||||
import com.simplemobiletools.contacts.extensions.shareContacts
|
||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.helpers.*
|
||||
import com.simplemobiletools.contacts.interfaces.RefreshContactsListener
|
||||
import com.simplemobiletools.contacts.interfaces.RemoveFromGroupListener
|
||||
import com.simplemobiletools.contacts.models.Contact
|
||||
import kotlinx.android.synthetic.main.item_contact_with_number.view.*
|
||||
import java.util.*
|
||||
|
||||
class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Contact>, private val listener: RefreshContactsListener?,
|
||||
private val isFavoritesFragment: Boolean, recyclerView: MyRecyclerView, fastScroller: FastScroller, itemClick: (Any) -> Unit) :
|
||||
class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Contact>, private val refreshListener: RefreshContactsListener?,
|
||||
private val location: Int, private val removeListener: RemoveFromGroupListener?, recyclerView: MyRecyclerView,
|
||||
fastScroller: FastScroller, itemClick: (Any) -> Unit) :
|
||||
MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
|
||||
|
||||
private lateinit var contactDrawable: Drawable
|
||||
var config = activity.config
|
||||
private var config = activity.config
|
||||
var startNameWithSurname: Boolean
|
||||
var showContactThumbnails: Boolean
|
||||
var showPhoneNumbers: Boolean
|
||||
@ -52,10 +58,14 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
|
||||
override fun prepareActionMode(menu: Menu) {
|
||||
menu.apply {
|
||||
findItem(R.id.cab_edit).isVisible = isOneItemSelected()
|
||||
findItem(R.id.cab_remove).isVisible = isFavoritesFragment
|
||||
findItem(R.id.cab_select_all).isVisible = isFavoritesFragment
|
||||
findItem(R.id.cab_add_to_favorites).isVisible = !isFavoritesFragment
|
||||
findItem(R.id.cab_delete).isVisible = !isFavoritesFragment
|
||||
findItem(R.id.cab_remove).isVisible = location == LOCATION_FAVORITES_TAB || location == LOCATION_GROUP_CONTACTS
|
||||
findItem(R.id.cab_add_to_favorites).isVisible = location == LOCATION_CONTACTS_TAB
|
||||
findItem(R.id.cab_add_to_group).isVisible = location == LOCATION_CONTACTS_TAB || location == LOCATION_FAVORITES_TAB
|
||||
findItem(R.id.cab_delete).isVisible = location == LOCATION_CONTACTS_TAB || location == LOCATION_GROUP_CONTACTS
|
||||
|
||||
if (location == LOCATION_GROUP_CONTACTS) {
|
||||
findItem(R.id.cab_remove).title = activity.getString(R.string.remove_from_group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,8 +84,9 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
|
||||
R.id.cab_edit -> editContact()
|
||||
R.id.cab_select_all -> selectAll()
|
||||
R.id.cab_add_to_favorites -> addToFavorites()
|
||||
R.id.cab_add_to_group -> addToGroup()
|
||||
R.id.cab_share -> shareContacts()
|
||||
R.id.cab_remove -> removeFavorites()
|
||||
R.id.cab_remove -> removeContacts()
|
||||
R.id.cab_delete -> askConfirmDelete()
|
||||
}
|
||||
}
|
||||
@ -102,9 +113,11 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
|
||||
}
|
||||
|
||||
fun updateItems(newItems: ArrayList<Contact>) {
|
||||
contactItems = newItems
|
||||
notifyDataSetChanged()
|
||||
finishActMode()
|
||||
if (newItems.hashCode() != contactItems.hashCode()) {
|
||||
contactItems = newItems
|
||||
notifyDataSetChanged()
|
||||
finishActMode()
|
||||
}
|
||||
}
|
||||
|
||||
private fun editContact() {
|
||||
@ -130,38 +143,77 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
|
||||
|
||||
ContactsHelper(activity).deleteContacts(contactsToRemove)
|
||||
if (contactItems.isEmpty()) {
|
||||
listener?.refreshContacts(true, true)
|
||||
refreshListener?.refreshContacts(ALL_TABS_MASK)
|
||||
finishActMode()
|
||||
} else {
|
||||
removeSelectedItems()
|
||||
listener?.refreshFavorites()
|
||||
refreshListener?.refreshContacts(FAVORITES_TAB_MASK)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeFavorites() {
|
||||
val favoritesToRemove = ArrayList<Contact>()
|
||||
private fun removeContacts() {
|
||||
val contactsToRemove = ArrayList<Contact>()
|
||||
selectedPositions.sortedDescending().forEach {
|
||||
favoritesToRemove.add(contactItems[it])
|
||||
contactsToRemove.add(contactItems[it])
|
||||
}
|
||||
contactItems.removeAll(favoritesToRemove)
|
||||
contactItems.removeAll(contactsToRemove)
|
||||
|
||||
ContactsHelper(activity).removeFavorites(favoritesToRemove)
|
||||
if (contactItems.isEmpty()) {
|
||||
listener?.refreshFavorites()
|
||||
finishActMode()
|
||||
} else {
|
||||
if (location == LOCATION_FAVORITES_TAB) {
|
||||
ContactsHelper(activity).removeFavorites(contactsToRemove)
|
||||
if (contactItems.isEmpty()) {
|
||||
refreshListener?.refreshContacts(FAVORITES_TAB_MASK)
|
||||
finishActMode()
|
||||
} else {
|
||||
removeSelectedItems()
|
||||
}
|
||||
} else if (location == LOCATION_GROUP_CONTACTS) {
|
||||
removeListener?.removeFromGroup(contactsToRemove)
|
||||
removeSelectedItems()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addToFavorites() {
|
||||
val newFavorites = ArrayList<Contact>()
|
||||
selectedPositions.forEach { newFavorites.add(contactItems[it]) }
|
||||
selectedPositions.forEach {
|
||||
newFavorites.add(contactItems[it])
|
||||
}
|
||||
ContactsHelper(activity).addFavorites(newFavorites)
|
||||
listener?.refreshFavorites()
|
||||
refreshListener?.refreshContacts(FAVORITES_TAB_MASK)
|
||||
finishActMode()
|
||||
}
|
||||
|
||||
private fun addToGroup() {
|
||||
val selectedContacts = ArrayList<Contact>()
|
||||
selectedPositions.forEach {
|
||||
selectedContacts.add(contactItems[it])
|
||||
}
|
||||
|
||||
val NEW_GROUP_ID = -1
|
||||
val items = ArrayList<RadioItem>()
|
||||
ContactsHelper(activity).getStoredGroups().forEach {
|
||||
items.add(RadioItem(it.id.toInt(), it.title))
|
||||
}
|
||||
items.add(RadioItem(NEW_GROUP_ID, activity.getString(R.string.create_new_group)))
|
||||
|
||||
RadioGroupDialog(activity, items, 0) {
|
||||
if (it as Int == NEW_GROUP_ID) {
|
||||
CreateNewGroupDialog(activity) {
|
||||
Thread {
|
||||
activity.addContactsToGroup(selectedContacts, it.id)
|
||||
refreshListener?.refreshContacts(GROUPS_TAB_MASK)
|
||||
}.start()
|
||||
finishActMode()
|
||||
}
|
||||
} else {
|
||||
Thread {
|
||||
activity.addContactsToGroup(selectedContacts, it.toLong())
|
||||
refreshListener?.refreshContacts(GROUPS_TAB_MASK)
|
||||
}.start()
|
||||
finishActMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shareContacts() {
|
||||
val contactsIDs = ArrayList<Int>()
|
||||
selectedPositions.forEach {
|
||||
|
@ -0,0 +1,131 @@
|
||||
package com.simplemobiletools.contacts.adapters
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
|
||||
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
||||
import com.simplemobiletools.commons.extensions.applyColorFilter
|
||||
import com.simplemobiletools.commons.extensions.beVisibleIf
|
||||
import com.simplemobiletools.commons.views.FastScroller
|
||||
import com.simplemobiletools.commons.views.MyRecyclerView
|
||||
import com.simplemobiletools.contacts.R
|
||||
import com.simplemobiletools.contacts.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.dialogs.RenameGroupDialog
|
||||
import com.simplemobiletools.contacts.extensions.config
|
||||
import com.simplemobiletools.contacts.extensions.dbHelper
|
||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.helpers.GROUPS_TAB_MASK
|
||||
import com.simplemobiletools.contacts.interfaces.RefreshContactsListener
|
||||
import com.simplemobiletools.contacts.models.Group
|
||||
import kotlinx.android.synthetic.main.item_group.view.*
|
||||
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
|
||||
|
||||
override fun getActionMenuId() = R.menu.cab_groups
|
||||
|
||||
override fun prepareActionMode(menu: Menu) {
|
||||
menu.apply {
|
||||
findItem(R.id.cab_edit).isVisible = isOneItemSelected()
|
||||
}
|
||||
}
|
||||
|
||||
override fun prepareItemSelection(view: View) {}
|
||||
|
||||
override fun markItemSelection(select: Boolean, view: View?) {
|
||||
view?.group_frame?.isSelected = select
|
||||
}
|
||||
|
||||
override fun actionItemPressed(id: Int) {
|
||||
if (selectedPositions.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
when (id) {
|
||||
R.id.cab_edit -> editGroup()
|
||||
R.id.cab_select_all -> selectAll()
|
||||
R.id.cab_delete -> askConfirmDelete()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSelectableItemCount() = groups.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_group, parent)
|
||||
|
||||
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
|
||||
val group = groups[position]
|
||||
val view = holder.bindView(group, true) { itemView, layoutPosition ->
|
||||
setupView(itemView, group)
|
||||
}
|
||||
bindViewHolder(holder, position, view)
|
||||
}
|
||||
|
||||
override fun getItemCount() = groups.size
|
||||
|
||||
fun updateItems(newItems: ArrayList<Group>) {
|
||||
groups = newItems
|
||||
notifyDataSetChanged()
|
||||
finishActMode()
|
||||
}
|
||||
|
||||
private fun editGroup() {
|
||||
RenameGroupDialog(activity, groups[selectedPositions.first()]) {
|
||||
finishActMode()
|
||||
refreshListener?.refreshContacts(GROUPS_TAB_MASK)
|
||||
}
|
||||
}
|
||||
|
||||
private fun askConfirmDelete() {
|
||||
ConfirmationDialog(activity) {
|
||||
deleteContacts()
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteContacts() {
|
||||
if (selectedPositions.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val groupsToRemove = ArrayList<Group>()
|
||||
selectedPositions.sortedDescending().forEach {
|
||||
val group = groups[it]
|
||||
groupsToRemove.add(group)
|
||||
if (group.isPrivateSecretGroup()) {
|
||||
activity.dbHelper.deleteGroup(group.id)
|
||||
} else {
|
||||
ContactsHelper(activity).deleteGroup(group.id)
|
||||
}
|
||||
}
|
||||
groups.removeAll(groupsToRemove)
|
||||
|
||||
if (groups.isEmpty()) {
|
||||
refreshListener?.refreshContacts(GROUPS_TAB_MASK)
|
||||
finishActMode()
|
||||
} else {
|
||||
removeSelectedItems()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupView(view: View, group: Group) {
|
||||
view.apply {
|
||||
group_name.apply {
|
||||
setTextColor(textColor)
|
||||
text = String.format(activity.getString(R.string.groups_placeholder), group.title, group.contactsCount.toString())
|
||||
setPadding(if (showContactThumbnails) smallPadding else bigPadding, smallPadding, smallPadding, 0)
|
||||
}
|
||||
|
||||
group_tmb.beVisibleIf(showContactThumbnails)
|
||||
if (showContactThumbnails) {
|
||||
group_tmb.applyColorFilter(textColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ import com.simplemobiletools.contacts.models.Contact
|
||||
import kotlinx.android.synthetic.main.item_add_favorite_with_number.view.*
|
||||
import java.util.*
|
||||
|
||||
class SelectContactsAdapter(val activity: SimpleActivity, val contacts: List<Contact>, private val selectedContacts: ArrayList<String>, private val allowPickMultiple: Boolean,
|
||||
class SelectContactsAdapter(val activity: SimpleActivity, val contacts: List<Contact>, private val selectedContacts: ArrayList<Contact>, private val allowPickMultiple: Boolean,
|
||||
private val itemClick: ((Contact) -> Unit)? = null) : RecyclerView.Adapter<SelectContactsAdapter.ViewHolder>() {
|
||||
private val itemViews = SparseArray<View>()
|
||||
private val selectedPositions = HashSet<Int>()
|
||||
@ -39,7 +39,7 @@ class SelectContactsAdapter(val activity: SimpleActivity, val contacts: List<Con
|
||||
|
||||
init {
|
||||
contacts.forEachIndexed { index, contact ->
|
||||
if (selectedContacts.contains(contact.id.toString())) {
|
||||
if (selectedContacts.map { it.id }.contains(contact.id)) {
|
||||
selectedPositions.add(index)
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.simplemobiletools.contacts.R
|
||||
import com.simplemobiletools.contacts.activities.MainActivity
|
||||
import com.simplemobiletools.contacts.interfaces.FragmentInterface
|
||||
import com.simplemobiletools.contacts.fragments.MyViewPagerFragment
|
||||
import com.simplemobiletools.contacts.models.Contact
|
||||
|
||||
class ViewPagerAdapter(val activity: MainActivity, val contacts: ArrayList<Contact>) : PagerAdapter() {
|
||||
@ -14,7 +14,7 @@ class ViewPagerAdapter(val activity: MainActivity, val contacts: ArrayList<Conta
|
||||
val layout = getFragment(position)
|
||||
val view = activity.layoutInflater.inflate(layout, container, false)
|
||||
container.addView(view)
|
||||
(view as FragmentInterface).apply {
|
||||
(view as MyViewPagerFragment).apply {
|
||||
setupFragment(activity)
|
||||
refreshContacts(contacts)
|
||||
}
|
||||
|
@ -1,67 +0,0 @@
|
||||
package com.simplemobiletools.contacts.dialogs
|
||||
|
||||
import android.support.v7.app.AlertDialog
|
||||
import com.simplemobiletools.commons.extensions.baseConfig
|
||||
import com.simplemobiletools.commons.extensions.setupDialogStuff
|
||||
import com.simplemobiletools.contacts.R
|
||||
import com.simplemobiletools.contacts.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.adapters.SelectContactsAdapter
|
||||
import com.simplemobiletools.contacts.extensions.config
|
||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.models.Contact
|
||||
import kotlinx.android.synthetic.main.layout_select_contact.view.*
|
||||
|
||||
class AddFavoritesDialog(val activity: SimpleActivity, private val callback: () -> Unit) {
|
||||
private var view = activity.layoutInflater.inflate(R.layout.layout_select_contact, null)
|
||||
private val config = activity.config
|
||||
private var allContacts = ArrayList<Contact>()
|
||||
|
||||
init {
|
||||
ContactsHelper(activity).getContacts {
|
||||
allContacts = it
|
||||
|
||||
val contactSources = config.displayContactSources
|
||||
if (!activity.config.showAllContacts()) {
|
||||
allContacts = allContacts.filter { contactSources.contains(it.source) } as ArrayList<Contact>
|
||||
}
|
||||
|
||||
val favorites = allContacts.filter { it.starred == 1 }.map { it.id.toString() } as ArrayList<String>
|
||||
|
||||
Contact.sorting = config.sorting
|
||||
allContacts.sort()
|
||||
|
||||
activity.runOnUiThread {
|
||||
view.apply {
|
||||
select_contact_list.adapter = SelectContactsAdapter(activity, allContacts, favorites, true)
|
||||
select_contact_fastscroller.allowBubbleDisplay = activity.baseConfig.showInfoBubble
|
||||
select_contact_fastscroller.setViews(select_contact_list) {
|
||||
select_contact_fastscroller.updateBubbleText(allContacts[it].getBubbleText())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
.setPositiveButton(R.string.ok, { dialog, which -> dialogConfirmed() })
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.create().apply {
|
||||
activity.setupDialogStuff(view, this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dialogConfirmed() {
|
||||
Thread {
|
||||
val contactsHelper = ContactsHelper(activity)
|
||||
val allDisplayedContacts = ArrayList<Contact>()
|
||||
allContacts.mapTo(allDisplayedContacts, { it })
|
||||
val selectedContacts = (view?.select_contact_list?.adapter as? SelectContactsAdapter)?.getSelectedItemsSet() ?: LinkedHashSet()
|
||||
val contactsToAdd = selectedContacts.map { it } as ArrayList<Contact>
|
||||
contactsHelper.addFavorites(contactsToAdd)
|
||||
|
||||
allDisplayedContacts.removeAll(selectedContacts)
|
||||
contactsHelper.removeFavorites(allDisplayedContacts)
|
||||
|
||||
callback()
|
||||
}.start()
|
||||
}
|
||||
}
|
@ -3,12 +3,17 @@ 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.dialogs.RadioGroupDialog
|
||||
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.commons.models.RadioItem
|
||||
import com.simplemobiletools.contacts.R
|
||||
import com.simplemobiletools.contacts.extensions.config
|
||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.helpers.SMT_PRIVATE
|
||||
import com.simplemobiletools.contacts.models.ContactSource
|
||||
import com.simplemobiletools.contacts.models.Group
|
||||
import kotlinx.android.synthetic.main.dialog_create_new_group.view.*
|
||||
|
||||
@ -29,13 +34,41 @@ class CreateNewGroupDialog(val activity: BaseSimpleActivity, val callback: (newG
|
||||
return@OnClickListener
|
||||
}
|
||||
|
||||
val newGroup = ContactsHelper(activity).createNewGroup(name)
|
||||
if (newGroup != null) {
|
||||
callback(newGroup)
|
||||
val contactSources = ArrayList<ContactSource>()
|
||||
if (activity.config.localAccountName.isNotEmpty()) {
|
||||
contactSources.add(ContactSource(activity.config.localAccountName, activity.config.localAccountType))
|
||||
}
|
||||
|
||||
ContactsHelper(activity).getContactSources {
|
||||
it.filter { it.type.contains("google", true) }.mapTo(contactSources, { ContactSource(it.name, it.type) })
|
||||
contactSources.add(ContactSource(activity.getString(R.string.phone_storage_hidden), SMT_PRIVATE))
|
||||
|
||||
val items = ArrayList<RadioItem>()
|
||||
contactSources.forEachIndexed { index, contactSource ->
|
||||
items.add(RadioItem(index, contactSource.name))
|
||||
}
|
||||
|
||||
activity.runOnUiThread {
|
||||
if (items.size == 1) {
|
||||
createGroupUnder(name, contactSources.first(), this)
|
||||
} else {
|
||||
RadioGroupDialog(activity, items, titleId = R.string.create_group_under_account) {
|
||||
val contactSource = contactSources[it as Int]
|
||||
createGroupUnder(name, contactSource, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dismiss()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createGroupUnder(name: String, contactSource: ContactSource, dialog: AlertDialog) {
|
||||
val newGroup = ContactsHelper(activity).createNewGroup(name, contactSource.name, contactSource.type)
|
||||
if (newGroup != null) {
|
||||
callback(newGroup)
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
package com.simplemobiletools.contacts.dialogs
|
||||
|
||||
import android.support.v7.app.AlertDialog
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.contacts.R
|
||||
import com.simplemobiletools.contacts.extensions.dbHelper
|
||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.models.Group
|
||||
import kotlinx.android.synthetic.main.dialog_rename_group.view.*
|
||||
|
||||
class RenameGroupDialog(val activity: BaseSimpleActivity, val group: Group, val callback: () -> Unit) {
|
||||
init {
|
||||
|
||||
val view = activity.layoutInflater.inflate(R.layout.dialog_rename_group, null).apply {
|
||||
rename_group_title.setText(group.title)
|
||||
}
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.create().apply {
|
||||
activity.setupDialogStuff(view, this, R.string.rename) {
|
||||
showKeyboard(view.rename_group_title)
|
||||
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||
val newTitle = view.rename_group_title.value
|
||||
if (newTitle.isEmpty()) {
|
||||
activity.toast(R.string.empty_name)
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
if (!newTitle.isAValidFilename()) {
|
||||
activity.toast(R.string.invalid_name)
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
group.title = newTitle
|
||||
if (group.isPrivateSecretGroup()) {
|
||||
activity.dbHelper.renameGroup(group)
|
||||
} else {
|
||||
ContactsHelper(activity).renameGroup(group)
|
||||
}
|
||||
callback()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.simplemobiletools.contacts.dialogs
|
||||
|
||||
import android.support.v7.app.AlertDialog
|
||||
import com.simplemobiletools.commons.extensions.baseConfig
|
||||
import com.simplemobiletools.commons.extensions.setupDialogStuff
|
||||
import com.simplemobiletools.contacts.R
|
||||
import com.simplemobiletools.contacts.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.adapters.SelectContactsAdapter
|
||||
import com.simplemobiletools.contacts.extensions.config
|
||||
import com.simplemobiletools.contacts.models.Contact
|
||||
import kotlinx.android.synthetic.main.layout_select_contact.view.*
|
||||
|
||||
class SelectContactsDialog(val activity: SimpleActivity, initialContacts: ArrayList<Contact>, val selectContacts: ArrayList<Contact>? = null,
|
||||
val callback: (addedContacts: ArrayList<Contact>, removedContacts: ArrayList<Contact>) -> Unit) {
|
||||
private var view = activity.layoutInflater.inflate(R.layout.layout_select_contact, null)
|
||||
private var initiallySelectedContacts = ArrayList<Contact>()
|
||||
|
||||
init {
|
||||
var allContacts = initialContacts
|
||||
if (selectContacts == null) {
|
||||
val contactSources = activity.config.displayContactSources
|
||||
if (!activity.config.showAllContacts()) {
|
||||
allContacts = allContacts.filter { contactSources.contains(it.source) } as ArrayList<Contact>
|
||||
}
|
||||
|
||||
initiallySelectedContacts = allContacts.filter { it.starred == 1 } as ArrayList<Contact>
|
||||
} else {
|
||||
initiallySelectedContacts = selectContacts
|
||||
}
|
||||
|
||||
Contact.sorting = activity.config.sorting
|
||||
allContacts.sort()
|
||||
|
||||
activity.runOnUiThread {
|
||||
view.apply {
|
||||
select_contact_list.adapter = SelectContactsAdapter(activity, allContacts, initiallySelectedContacts, true)
|
||||
select_contact_fastscroller.allowBubbleDisplay = activity.baseConfig.showInfoBubble
|
||||
select_contact_fastscroller.setViews(select_contact_list) {
|
||||
select_contact_fastscroller.updateBubbleText(allContacts[it].getBubbleText())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
.setPositiveButton(R.string.ok, { dialog, which -> dialogConfirmed() })
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.create().apply {
|
||||
activity.setupDialogStuff(view, this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dialogConfirmed() {
|
||||
Thread {
|
||||
val adapter = view?.select_contact_list?.adapter as? SelectContactsAdapter
|
||||
val selectedContacts = adapter?.getSelectedItemsSet()?.toList() ?: ArrayList()
|
||||
|
||||
val newlySelectedContacts = selectedContacts.filter { !initiallySelectedContacts.contains(it) } as ArrayList
|
||||
val unselectedContacts = initiallySelectedContacts.filter { !selectedContacts.contains(it) } as ArrayList
|
||||
callback(newlySelectedContacts, unselectedContacts)
|
||||
}.start()
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import android.net.Uri
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||
import com.simplemobiletools.commons.extensions.sharePathIntent
|
||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||
import com.simplemobiletools.commons.extensions.toast
|
||||
import com.simplemobiletools.commons.helpers.PERMISSION_CALL_PHONE
|
||||
import com.simplemobiletools.commons.models.RadioItem
|
||||
@ -93,6 +94,8 @@ fun BaseSimpleActivity.shareContacts(contacts: ArrayList<Contact>) {
|
||||
VcfExporter().exportContacts(this, file, contacts) {
|
||||
if (it == VcfExporter.ExportResult.EXPORT_OK) {
|
||||
sharePathIntent(file.absolutePath, BuildConfig.APPLICATION_ID)
|
||||
} else {
|
||||
showErrorToast("$it")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,3 +111,27 @@ fun BaseSimpleActivity.getTempFile(): File? {
|
||||
|
||||
return File(folder, "contacts.vcf")
|
||||
}
|
||||
|
||||
fun BaseSimpleActivity.addContactsToGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
val publicContacts = contacts.filter { it.source != SMT_PRIVATE }
|
||||
val privateContacts = contacts.filter { it.source == SMT_PRIVATE }
|
||||
if (publicContacts.isNotEmpty()) {
|
||||
ContactsHelper(this).addContactsToGroup(contacts, groupId)
|
||||
}
|
||||
|
||||
if (privateContacts.isNotEmpty()) {
|
||||
dbHelper.addContactsToGroup(contacts, 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()) {
|
||||
ContactsHelper(this).removeContactsFromGroup(contacts, groupId)
|
||||
}
|
||||
|
||||
if (privateContacts.isNotEmpty()) {
|
||||
dbHelper.removeContactsFromGroup(contacts, groupId)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,10 @@ package com.simplemobiletools.contacts.fragments
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import com.simplemobiletools.contacts.dialogs.AddFavoritesDialog
|
||||
import com.simplemobiletools.contacts.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.dialogs.SelectContactsDialog
|
||||
import com.simplemobiletools.contacts.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.helpers.FAVORITES_TAB_MASK
|
||||
|
||||
class FavoritesFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet) {
|
||||
override fun fabClicked() {
|
||||
@ -15,8 +18,13 @@ class FavoritesFragment(context: Context, attributeSet: AttributeSet) : MyViewPa
|
||||
}
|
||||
|
||||
private fun showAddFavoritesDialog() {
|
||||
AddFavoritesDialog(activity!!) {
|
||||
activity!!.refreshContacts(false, true)
|
||||
SelectContactsDialog(activity!!, allContacts) { addedContacts, removedContacts ->
|
||||
ContactsHelper(activity as SimpleActivity).apply {
|
||||
addFavorites(addedContacts)
|
||||
removeFavorites(removedContacts)
|
||||
}
|
||||
|
||||
activity!!.refreshContacts(FAVORITES_TAB_MASK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,24 @@
|
||||
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
|
||||
import com.simplemobiletools.contacts.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.dialogs.CreateNewGroupDialog
|
||||
import com.simplemobiletools.contacts.helpers.GROUPS_TAB_MASK
|
||||
|
||||
class GroupsFragment(context: Context, attributeSet: AttributeSet) : CoordinatorLayout(context, attributeSet), FragmentInterface {
|
||||
override fun setupFragment(activity: MainActivity) {
|
||||
class GroupsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet) {
|
||||
override fun fabClicked() {
|
||||
finishActMode()
|
||||
showNewGroupsDialog()
|
||||
}
|
||||
|
||||
override fun textColorChanged(color: Int) {
|
||||
override fun placeholderClicked() {
|
||||
showNewGroupsDialog()
|
||||
}
|
||||
|
||||
override fun primaryColorChanged(color: Int) {
|
||||
}
|
||||
|
||||
override fun refreshContacts(contacts: ArrayList<Contact>) {
|
||||
private fun showNewGroupsDialog() {
|
||||
CreateNewGroupDialog(activity as SimpleActivity) {
|
||||
activity!!.refreshContacts(GROUPS_TAB_MASK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,41 @@
|
||||
package com.simplemobiletools.contacts.fragments
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.support.design.widget.CoordinatorLayout
|
||||
import android.util.AttributeSet
|
||||
import android.view.ViewGroup
|
||||
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_FIRST_NAME
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_SURNAME
|
||||
import com.simplemobiletools.contacts.R
|
||||
import com.simplemobiletools.contacts.activities.GroupContactsActivity
|
||||
import com.simplemobiletools.contacts.activities.MainActivity
|
||||
import com.simplemobiletools.contacts.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.adapters.ContactsAdapter
|
||||
import com.simplemobiletools.contacts.adapters.GroupsAdapter
|
||||
import com.simplemobiletools.contacts.extensions.config
|
||||
import com.simplemobiletools.contacts.extensions.editContact
|
||||
import com.simplemobiletools.contacts.extensions.tryStartCall
|
||||
import com.simplemobiletools.contacts.extensions.viewContact
|
||||
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.helpers.*
|
||||
import com.simplemobiletools.contacts.models.Contact
|
||||
import com.simplemobiletools.contacts.models.Group
|
||||
import kotlinx.android.synthetic.main.fragment_layout.view.*
|
||||
|
||||
abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet) : CoordinatorLayout(context, attributeSet), FragmentInterface {
|
||||
abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet) : CoordinatorLayout(context, attributeSet) {
|
||||
protected var activity: MainActivity? = null
|
||||
protected var allContacts = ArrayList<Contact>()
|
||||
|
||||
private var lastHashCode = 0
|
||||
private var contactsIgnoringSearch = ArrayList<Contact>()
|
||||
private lateinit var config: Config
|
||||
|
||||
var skipHashComparing = false
|
||||
var forceListRedraw = false
|
||||
|
||||
override fun setupFragment(activity: MainActivity) {
|
||||
fun setupFragment(activity: MainActivity) {
|
||||
config = activity.config
|
||||
if (this.activity == null) {
|
||||
this.activity = activity
|
||||
@ -49,36 +53,51 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
||||
if (this is FavoritesFragment) {
|
||||
fragment_placeholder.text = activity.getString(R.string.no_favorites)
|
||||
fragment_placeholder_2.text = activity.getString(R.string.add_favorites)
|
||||
} else if (this is GroupsFragment) {
|
||||
fragment_placeholder.text = activity.getString(R.string.no_group_created)
|
||||
fragment_placeholder_2.text = activity.getString(R.string.create_group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun textColorChanged(color: Int) {
|
||||
(fragment_list.adapter as ContactsAdapter).apply {
|
||||
updateTextColor(color)
|
||||
initDrawables()
|
||||
fun textColorChanged(color: Int) {
|
||||
if (this is GroupsFragment) {
|
||||
(fragment_list.adapter as GroupsAdapter).updateTextColor(color)
|
||||
} else {
|
||||
(fragment_list.adapter as ContactsAdapter).apply {
|
||||
updateTextColor(color)
|
||||
initDrawables()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun primaryColorChanged(color: Int) {
|
||||
fun primaryColorChanged() {
|
||||
fragment_fastscroller.updatePrimaryColor()
|
||||
fragment_fastscroller.updateBubblePrimaryColor()
|
||||
}
|
||||
|
||||
fun startNameWithSurnameChanged(startNameWithSurname: Boolean) {
|
||||
(fragment_list.adapter as ContactsAdapter).apply {
|
||||
config.sorting = if (startNameWithSurname) SORT_BY_SURNAME else SORT_BY_FIRST_NAME
|
||||
this@MyViewPagerFragment.activity!!.refreshContacts(true, true)
|
||||
if (this !is GroupsFragment) {
|
||||
(fragment_list.adapter as ContactsAdapter).apply {
|
||||
config.sorting = if (startNameWithSurname) SORT_BY_SURNAME else SORT_BY_FIRST_NAME
|
||||
this@MyViewPagerFragment.activity!!.refreshContacts(CONTACTS_TAB_MASK or FAVORITES_TAB_MASK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun refreshContacts(contacts: ArrayList<Contact>) {
|
||||
fun refreshContacts(contacts: ArrayList<Contact>) {
|
||||
if (config.lastUsedContactSource.isEmpty()) {
|
||||
val grouped = contacts.groupBy { it.source }.maxWith(compareBy { it.value.size })
|
||||
config.lastUsedContactSource = grouped?.key ?: ""
|
||||
}
|
||||
|
||||
val filtered = if (this is FavoritesFragment) {
|
||||
Contact.sorting = config.sorting
|
||||
contacts.sort()
|
||||
allContacts = contacts
|
||||
|
||||
val filtered = if (this is GroupsFragment) {
|
||||
contacts
|
||||
} else if (this is FavoritesFragment) {
|
||||
contacts.filter { it.starred == 1 } as ArrayList<Contact>
|
||||
} else {
|
||||
val contactSources = config.displayContactSources
|
||||
@ -89,10 +108,8 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
||||
}
|
||||
}
|
||||
|
||||
Contact.sorting = config.sorting
|
||||
filtered.sort()
|
||||
|
||||
if (filtered.hashCode() != lastHashCode) {
|
||||
if (filtered.hashCode() != lastHashCode || skipHashComparing) {
|
||||
skipHashComparing = false
|
||||
lastHashCode = filtered.hashCode()
|
||||
activity?.runOnUiThread {
|
||||
setupContacts(filtered)
|
||||
@ -101,6 +118,56 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
||||
}
|
||||
|
||||
private fun setupContacts(contacts: ArrayList<Contact>) {
|
||||
if (this is GroupsFragment) {
|
||||
setupGroupsAdapter(contacts)
|
||||
} else {
|
||||
setupContactsFavoritesAdapter(contacts)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupGroupsAdapter(contacts: ArrayList<Contact>) {
|
||||
var storedGroups = ContactsHelper(activity!!).getStoredGroups()
|
||||
contacts.forEach {
|
||||
it.groups.forEach {
|
||||
val group = it
|
||||
val storedGroup = storedGroups.firstOrNull { it.id == group.id }
|
||||
storedGroup?.addContact()
|
||||
}
|
||||
}
|
||||
|
||||
storedGroups = storedGroups.sortedWith(compareBy { it.title }).toMutableList() as ArrayList<Group>
|
||||
|
||||
fragment_placeholder_2.beVisibleIf(storedGroups.isEmpty())
|
||||
fragment_placeholder.beVisibleIf(storedGroups.isEmpty())
|
||||
fragment_list.beVisibleIf(storedGroups.isNotEmpty())
|
||||
|
||||
val currAdapter = fragment_list.adapter
|
||||
if (currAdapter == null) {
|
||||
GroupsAdapter(activity as SimpleActivity, storedGroups, activity, fragment_list, fragment_fastscroller) {
|
||||
Intent(activity, GroupContactsActivity::class.java).apply {
|
||||
putExtra(GROUP, it as Group)
|
||||
activity!!.startActivity(this)
|
||||
}
|
||||
}.apply {
|
||||
setupDragListener(true)
|
||||
addVerticalDividers(true)
|
||||
fragment_list.adapter = this
|
||||
}
|
||||
|
||||
fragment_fastscroller.setScrollTo(0)
|
||||
fragment_fastscroller.setViews(fragment_list) {
|
||||
val item = (fragment_list.adapter as GroupsAdapter).groups.getOrNull(it)
|
||||
fragment_fastscroller.updateBubbleText(item?.getBubbleText() ?: "")
|
||||
}
|
||||
} else {
|
||||
(currAdapter as GroupsAdapter).apply {
|
||||
showContactThumbnails = activity.config.showContactThumbnails
|
||||
updateItems(storedGroups)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupContactsFavoritesAdapter(contacts: ArrayList<Contact>) {
|
||||
fragment_placeholder_2.beVisibleIf(contacts.isEmpty())
|
||||
fragment_placeholder.beVisibleIf(contacts.isEmpty())
|
||||
fragment_list.beVisibleIf(contacts.isNotEmpty())
|
||||
@ -108,7 +175,8 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
||||
val currAdapter = fragment_list.adapter
|
||||
if (currAdapter == null || forceListRedraw) {
|
||||
forceListRedraw = false
|
||||
ContactsAdapter(activity as SimpleActivity, contacts, activity, this is FavoritesFragment, fragment_list, fragment_fastscroller) {
|
||||
val location = if (this is FavoritesFragment) LOCATION_FAVORITES_TAB else LOCATION_CONTACTS_TAB
|
||||
ContactsAdapter(activity as SimpleActivity, contacts, activity, location, null, fragment_list, fragment_fastscroller) {
|
||||
when (config.onContactClick) {
|
||||
ON_CLICK_CALL_CONTACT -> {
|
||||
val contact = it as Contact
|
||||
@ -143,9 +211,16 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
||||
}
|
||||
|
||||
fun showContactThumbnailsChanged(showThumbnails: Boolean) {
|
||||
(fragment_list.adapter as? ContactsAdapter)?.apply {
|
||||
showContactThumbnails = showThumbnails
|
||||
notifyDataSetChanged()
|
||||
if (this is GroupsFragment) {
|
||||
(fragment_list.adapter as? GroupsAdapter)?.apply {
|
||||
showContactThumbnails = showThumbnails
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
} else {
|
||||
(fragment_list.adapter as? ContactsAdapter)?.apply {
|
||||
showContactThumbnails = showThumbnails
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,7 +229,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
||||
}
|
||||
|
||||
fun finishActMode() {
|
||||
(fragment_list.adapter as? ContactsAdapter)?.finishActMode()
|
||||
(fragment_list.adapter as? MyRecyclerViewAdapter)?.finishActMode()
|
||||
}
|
||||
|
||||
fun onSearchQueryChanged(text: String) {
|
||||
|
@ -13,6 +13,18 @@ const val ON_CONTACT_CLICK = "on_contact_click"
|
||||
const val CONTACT_ID = "contact_id"
|
||||
const val SMT_PRIVATE = "smt_private" // used at the contact source of local contacts hidden from other apps
|
||||
const val IS_PRIVATE = "is_private"
|
||||
const val GROUP = "group"
|
||||
const val FIRST_GROUP_ID = 10000
|
||||
|
||||
const val LOCATION_CONTACTS_TAB = 0
|
||||
const val LOCATION_FAVORITES_TAB = 1
|
||||
const val LOCATION_GROUPS_TAB = 2
|
||||
const val LOCATION_GROUP_CONTACTS = 3
|
||||
|
||||
const val CONTACTS_TAB_MASK = 1
|
||||
const val FAVORITES_TAB_MASK = 2
|
||||
const val GROUPS_TAB_MASK = 4
|
||||
const val ALL_TABS_MASK = 7
|
||||
|
||||
// contact photo changes
|
||||
const val PHOTO_ADDED = 1
|
||||
|
@ -11,6 +11,7 @@ import android.provider.ContactsContract
|
||||
import android.provider.ContactsContract.CommonDataKinds
|
||||
import android.provider.ContactsContract.CommonDataKinds.Note
|
||||
import android.provider.MediaStore
|
||||
import android.text.TextUtils
|
||||
import android.util.SparseArray
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
@ -101,14 +102,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
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(activity).forEach {
|
||||
contacts.put(it.id, it)
|
||||
}
|
||||
|
||||
@ -116,6 +110,15 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
var resultContacts = ArrayList<Contact>(contactsSize)
|
||||
(0 until contactsSize).mapTo(resultContacts) { contacts.valueAt(it) }
|
||||
resultContacts = resultContacts.distinctBy { it.contactId } as ArrayList<Contact>
|
||||
|
||||
// groups are obtained with contactID, not rawID, so assign them to proper contacts like this
|
||||
val groups = getContactGroups(getStoredGroups())
|
||||
size = groups.size()
|
||||
for (i in 0 until size) {
|
||||
val key = groups.keyAt(i)
|
||||
resultContacts.firstOrNull { it.contactId == key }?.groups = groups.valueAt(i)
|
||||
}
|
||||
|
||||
activity.runOnUiThread {
|
||||
callback(resultContacts)
|
||||
}
|
||||
@ -336,12 +339,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
|
||||
val newRowId = cursor.getLongValue(ContactsContract.Data.DATA1)
|
||||
|
||||
val groupTitle = storedGroups.firstOrNull { it.id == newRowId }?.title ?: continue
|
||||
val group = Group(newRowId, groupTitle)
|
||||
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())
|
||||
}
|
||||
@ -359,10 +361,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
val uri = ContactsContract.Groups.CONTENT_URI
|
||||
val projection = arrayOf(
|
||||
ContactsContract.Groups._ID,
|
||||
ContactsContract.Groups.TITLE
|
||||
ContactsContract.Groups.TITLE,
|
||||
ContactsContract.Groups.SYSTEM_ID
|
||||
)
|
||||
|
||||
val selection = "${ContactsContract.Groups.AUTO_ADD} = ? AND ${ContactsContract.Groups.FAVORITES} = ? AND ${ContactsContract.Groups.SYSTEM_ID} IS NULL"
|
||||
val selection = "${ContactsContract.Groups.AUTO_ADD} = ? AND ${ContactsContract.Groups.FAVORITES} = ?"
|
||||
val selectionArgs = arrayOf("0", "0")
|
||||
|
||||
var cursor: Cursor? = null
|
||||
@ -372,6 +375,12 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
do {
|
||||
val id = cursor.getLongValue(ContactsContract.Groups._ID)
|
||||
val title = cursor.getStringValue(ContactsContract.Groups.TITLE)
|
||||
|
||||
val systemId = cursor.getStringValue(ContactsContract.Groups.SYSTEM_ID)
|
||||
if (groups.map { it.title }.contains(title) && systemId != null) {
|
||||
continue
|
||||
}
|
||||
|
||||
groups.add(Group(id, title))
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
@ -381,17 +390,25 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
cursor?.close()
|
||||
}
|
||||
|
||||
groups.addAll(activity.dbHelper.getGroups())
|
||||
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())
|
||||
}
|
||||
fun createNewGroup(title: String, accountName: String, accountType: String): Group? {
|
||||
if (accountType == SMT_PRIVATE) {
|
||||
return activity.dbHelper.insertGroup(Group(0, title))
|
||||
}
|
||||
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
ContentProviderOperation.newInsert(ContactsContract.Groups.CONTENT_URI).apply {
|
||||
withValue(ContactsContract.Groups.TITLE, title)
|
||||
withValue(ContactsContract.Groups.GROUP_VISIBLE, 1)
|
||||
withValue(ContactsContract.Groups.ACCOUNT_NAME, accountName)
|
||||
withValue(ContactsContract.Groups.ACCOUNT_TYPE, accountType)
|
||||
operations.add(build())
|
||||
}
|
||||
|
||||
try {
|
||||
val results = activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
val rawId = ContentUris.parseId(results[0].uri)
|
||||
return Group(rawId, title)
|
||||
@ -401,14 +418,32 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
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()
|
||||
fun renameGroup(group: Group) {
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
ContentProviderOperation.newUpdate(ContactsContract.Groups.CONTENT_URI).apply {
|
||||
val selection = "${ContactsContract.Groups._ID} = ?"
|
||||
val selectionArgs = arrayOf(group.id.toString())
|
||||
withSelection(selection, selectionArgs)
|
||||
withValue(ContactsContract.Groups.TITLE, group.title)
|
||||
operations.add(build())
|
||||
}
|
||||
|
||||
operations.add(ContentProviderOperation.newDelete(uri).build())
|
||||
try {
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteGroup(id: Long) {
|
||||
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())
|
||||
|
||||
try {
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
@ -419,7 +454,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
if (id == 0) {
|
||||
return null
|
||||
} else if (isLocalPrivate) {
|
||||
return activity.dbHelper.getContactWithId(id)
|
||||
return activity.dbHelper.getContactWithId(activity, id)
|
||||
}
|
||||
|
||||
val selection = "${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
|
||||
@ -489,6 +524,10 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
cursor?.close()
|
||||
}
|
||||
|
||||
if (sources.isEmpty() && activity.config.localAccountName.isEmpty() && activity.config.localAccountType.isEmpty()) {
|
||||
sources.add(ContactSource("", ""))
|
||||
}
|
||||
|
||||
sources.add(ContactSource(activity.getString(R.string.phone_storage_hidden), SMT_PRIVATE))
|
||||
callback(ArrayList(sources))
|
||||
}.start()
|
||||
@ -563,10 +602,12 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
}
|
||||
|
||||
fun updateContact(contact: Contact, photoUpdateStatus: Int): Boolean {
|
||||
return if (contact.source == SMT_PRIVATE) {
|
||||
activity.dbHelper.update(contact)
|
||||
} else try {
|
||||
activity.toast(R.string.updating)
|
||||
activity.toast(R.string.updating)
|
||||
if (contact.source == SMT_PRIVATE) {
|
||||
return activity.dbHelper.updateContact(contact)
|
||||
}
|
||||
|
||||
try {
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI).apply {
|
||||
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?"
|
||||
@ -664,11 +705,15 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
}
|
||||
|
||||
// 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())
|
||||
val relevantGroupIDs = getStoredGroups().map { it.id }
|
||||
if (relevantGroupIDs.isNotEmpty()) {
|
||||
val IDsString = TextUtils.join(",", relevantGroupIDs)
|
||||
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
|
||||
val selection = "${ContactsContract.Data.CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.Data.DATA1} IN ($IDsString)"
|
||||
val selectionArgs = arrayOf(contact.contactId.toString(), CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE)
|
||||
withSelection(selection, selectionArgs)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
// add groups
|
||||
@ -698,10 +743,10 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
}
|
||||
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
true
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
false
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ -741,144 +786,170 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
return operations
|
||||
}
|
||||
|
||||
fun insertContact(contact: Contact): Boolean {
|
||||
return if (contact.source == SMT_PRIVATE) {
|
||||
insertLocalContact(contact)
|
||||
} else {
|
||||
try {
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI).apply {
|
||||
withValue(ContactsContract.RawContacts.ACCOUNT_NAME, contact.source)
|
||||
withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, getContactSourceType(contact.source))
|
||||
operations.add(build())
|
||||
}
|
||||
|
||||
// names
|
||||
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.GIVEN_NAME, contact.firstName)
|
||||
withValue(CommonDataKinds.StructuredName.MIDDLE_NAME, contact.middleName)
|
||||
withValue(CommonDataKinds.StructuredName.FAMILY_NAME, contact.surname)
|
||||
operations.add(build())
|
||||
}
|
||||
|
||||
// phone numbers
|
||||
contact.phoneNumbers.forEach {
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.Phone.NUMBER, it.value)
|
||||
withValue(CommonDataKinds.Phone.TYPE, it.type)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
// emails
|
||||
contact.emails.forEach {
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Email.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.Email.DATA, it.value)
|
||||
withValue(CommonDataKinds.Email.TYPE, it.type)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
// addresses
|
||||
contact.addresses.forEach {
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, it.value)
|
||||
withValue(CommonDataKinds.StructuredPostal.TYPE, it.type)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
// events
|
||||
contact.events.forEach {
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Event.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.Event.START_DATE, it.value)
|
||||
withValue(CommonDataKinds.Event.TYPE, it.type)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
// notes
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, Note.CONTENT_ITEM_TYPE)
|
||||
withValue(Note.NOTE, contact.notes)
|
||||
operations.add(build())
|
||||
}
|
||||
|
||||
// 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)
|
||||
var fullSizePhotoData: ByteArray? = null
|
||||
var scaledSizePhotoData: ByteArray?
|
||||
if (contact.photoUri.isNotEmpty()) {
|
||||
val photoUri = Uri.parse(contact.photoUri)
|
||||
val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, photoUri)
|
||||
|
||||
val thumbnailSize = activity.getPhotoThumbnailSize()
|
||||
val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false)
|
||||
scaledSizePhotoData = scaledPhoto.getByteArray()
|
||||
|
||||
fullSizePhotoData = bitmap.getByteArray()
|
||||
scaledPhoto.recycle()
|
||||
bitmap.recycle()
|
||||
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.Photo.PHOTO, scaledSizePhotoData)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
val results: Array<ContentProviderResult>
|
||||
try {
|
||||
results = activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
} finally {
|
||||
scaledSizePhotoData = null
|
||||
}
|
||||
|
||||
// fullsize photo
|
||||
val rawId = ContentUris.parseId(results[0].uri)
|
||||
if (contact.photoUri.isNotEmpty() && fullSizePhotoData != null) {
|
||||
addFullSizePhoto(rawId, fullSizePhotoData)
|
||||
}
|
||||
|
||||
// favorite
|
||||
val userId = getRealContactId(rawId)
|
||||
if (userId != 0 && contact.starred == 1) {
|
||||
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, userId.toString())
|
||||
val contentValues = ContentValues(1)
|
||||
contentValues.put(ContactsContract.Contacts.STARRED, contact.starred)
|
||||
activity.contentResolver.update(uri, contentValues, null, null)
|
||||
}
|
||||
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
false
|
||||
fun addContactsToGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
contacts.forEach {
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValue(ContactsContract.Data.RAW_CONTACT_ID, it.id)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
}
|
||||
|
||||
fun removeContactsFromGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
contacts.forEach {
|
||||
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
|
||||
val selection = "${ContactsContract.Data.CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.Data.DATA1} = ?"
|
||||
val selectionArgs = arrayOf(it.contactId.toString(), CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE, groupId.toString())
|
||||
withSelection(selection, selectionArgs)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
}
|
||||
|
||||
fun insertContact(contact: Contact): Boolean {
|
||||
if (contact.source == SMT_PRIVATE) {
|
||||
return insertLocalContact(contact)
|
||||
}
|
||||
|
||||
try {
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI).apply {
|
||||
withValue(ContactsContract.RawContacts.ACCOUNT_NAME, contact.source)
|
||||
withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, getContactSourceType(contact.source))
|
||||
operations.add(build())
|
||||
}
|
||||
|
||||
// names
|
||||
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.GIVEN_NAME, contact.firstName)
|
||||
withValue(CommonDataKinds.StructuredName.MIDDLE_NAME, contact.middleName)
|
||||
withValue(CommonDataKinds.StructuredName.FAMILY_NAME, contact.surname)
|
||||
operations.add(build())
|
||||
}
|
||||
|
||||
// phone numbers
|
||||
contact.phoneNumbers.forEach {
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.Phone.NUMBER, it.value)
|
||||
withValue(CommonDataKinds.Phone.TYPE, it.type)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
// emails
|
||||
contact.emails.forEach {
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Email.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.Email.DATA, it.value)
|
||||
withValue(CommonDataKinds.Email.TYPE, it.type)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
// addresses
|
||||
contact.addresses.forEach {
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, it.value)
|
||||
withValue(CommonDataKinds.StructuredPostal.TYPE, it.type)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
// events
|
||||
contact.events.forEach {
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Event.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.Event.START_DATE, it.value)
|
||||
withValue(CommonDataKinds.Event.TYPE, it.type)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
// notes
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, Note.CONTENT_ITEM_TYPE)
|
||||
withValue(Note.NOTE, contact.notes)
|
||||
operations.add(build())
|
||||
}
|
||||
|
||||
// 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)
|
||||
var fullSizePhotoData: ByteArray? = null
|
||||
var scaledSizePhotoData: ByteArray?
|
||||
if (contact.photoUri.isNotEmpty()) {
|
||||
val photoUri = Uri.parse(contact.photoUri)
|
||||
val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, photoUri)
|
||||
|
||||
val thumbnailSize = activity.getPhotoThumbnailSize()
|
||||
val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false)
|
||||
scaledSizePhotoData = scaledPhoto.getByteArray()
|
||||
|
||||
fullSizePhotoData = bitmap.getByteArray()
|
||||
scaledPhoto.recycle()
|
||||
bitmap.recycle()
|
||||
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.Photo.PHOTO, scaledSizePhotoData)
|
||||
operations.add(build())
|
||||
}
|
||||
}
|
||||
|
||||
val results: Array<ContentProviderResult>
|
||||
try {
|
||||
results = activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
} finally {
|
||||
scaledSizePhotoData = null
|
||||
}
|
||||
|
||||
// fullsize photo
|
||||
val rawId = ContentUris.parseId(results[0].uri)
|
||||
if (contact.photoUri.isNotEmpty() && fullSizePhotoData != null) {
|
||||
addFullSizePhoto(rawId, fullSizePhotoData)
|
||||
}
|
||||
|
||||
// favorite
|
||||
val userId = getRealContactId(rawId)
|
||||
if (userId != 0 && contact.starred == 1) {
|
||||
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, userId.toString())
|
||||
val contentValues = ContentValues(1)
|
||||
contentValues.put(ContactsContract.Contacts.STARRED, contact.starred)
|
||||
activity.contentResolver.update(uri, contentValues, null, null)
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun insertLocalContact(contact: Contact) = activity.dbHelper.insert(contact)
|
||||
private fun insertLocalContact(contact: Contact) = activity.dbHelper.insertContact(contact)
|
||||
|
||||
private fun addFullSizePhoto(contactId: Long, fullSizePhotoData: ByteArray) {
|
||||
val baseUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, contactId)
|
||||
@ -909,11 +980,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
return ""
|
||||
}
|
||||
|
||||
fun getContactDataId(contactId: String): String {
|
||||
fun getContactMimeTypeId(contactId: String, mimeType: String): String {
|
||||
val uri = ContactsContract.Data.CONTENT_URI
|
||||
val projection = arrayOf(ContactsContract.Data._ID, ContactsContract.Data.RAW_CONTACT_ID, ContactsContract.Data.MIMETYPE)
|
||||
val selection = "${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
|
||||
val selectionArgs = arrayOf(CommonDataKinds.Email.CONTENT_ITEM_TYPE, contactId)
|
||||
val selectionArgs = arrayOf(mimeType, contactId)
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
@ -979,10 +1050,10 @@ class ContactsHelper(val activity: BaseSimpleActivity) {
|
||||
try {
|
||||
val contactIDs = HashSet<String>()
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ?"
|
||||
val selection = "${ContactsContract.Data.CONTACT_ID} = ?"
|
||||
contacts.filter { it.source != SMT_PRIVATE }.forEach {
|
||||
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
|
||||
val selectionArgs = arrayOf(it.id.toString())
|
||||
val selectionArgs = arrayOf(it.contactId.toString())
|
||||
withSelection(selection, selectionArgs)
|
||||
operations.add(this.build())
|
||||
}
|
||||
|
@ -11,8 +11,10 @@ import android.provider.MediaStore
|
||||
import android.text.TextUtils
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.extensions.getBlobValue
|
||||
import com.simplemobiletools.commons.extensions.getIntValue
|
||||
import com.simplemobiletools.commons.extensions.getLongValue
|
||||
import com.simplemobiletools.commons.extensions.getStringValue
|
||||
import com.simplemobiletools.contacts.extensions.getByteArray
|
||||
import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize
|
||||
@ -31,13 +33,17 @@ 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_GROUPS = "groups"
|
||||
|
||||
private val GROUPS_TABLE_NAME = "groups"
|
||||
private val COL_TITLE = "title"
|
||||
|
||||
private val FIRST_CONTACT_ID = 1000000
|
||||
|
||||
private val mDb = writableDatabase
|
||||
|
||||
companion object {
|
||||
private const val DB_VERSION = 2
|
||||
private const val DB_VERSION = 3
|
||||
const val DB_NAME = "contacts.db"
|
||||
var dbInstance: DBHelper? = null
|
||||
|
||||
@ -52,10 +58,12 @@ 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_ADDRESSES TEXT, $COL_NOTES TEXT, $COL_GROUPS 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)")
|
||||
|
||||
createGroupsTable(db)
|
||||
}
|
||||
|
||||
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
@ -63,15 +71,27 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_ADDRESSES TEXT DEFAULT ''")
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_NOTES TEXT DEFAULT ''")
|
||||
}
|
||||
|
||||
if (oldVersion < 3) {
|
||||
createGroupsTable(db)
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_GROUPS TEXT DEFAULT ''")
|
||||
}
|
||||
}
|
||||
|
||||
fun insert(contact: Contact): Boolean {
|
||||
private fun createGroupsTable(db: SQLiteDatabase) {
|
||||
db.execSQL("CREATE TABLE $GROUPS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_TITLE TEXT)")
|
||||
|
||||
// start autoincrement ID from FIRST_GROUP_ID to avoid conflicts
|
||||
db.execSQL("REPLACE INTO sqlite_sequence (name, seq) VALUES ('$GROUPS_TABLE_NAME', $FIRST_GROUP_ID)")
|
||||
}
|
||||
|
||||
fun insertContact(contact: Contact): Boolean {
|
||||
val contactValues = fillContactValues(contact)
|
||||
val id = mDb.insert(CONTACTS_TABLE_NAME, null, contactValues).toInt()
|
||||
return id != -1
|
||||
}
|
||||
|
||||
fun update(contact: Contact): Boolean {
|
||||
fun updateContact(contact: Contact): Boolean {
|
||||
val contactValues = fillContactValues(contact)
|
||||
val selection = "$COL_ID = ?"
|
||||
val selectionArgs = arrayOf(contact.id.toString())
|
||||
@ -97,6 +117,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
|
||||
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 }))
|
||||
|
||||
if (contact.photoUri.isNotEmpty()) {
|
||||
put(COL_PHOTO, getPhotoByteArray(contact.photoUri))
|
||||
@ -126,10 +147,87 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
|
||||
mDb.update(CONTACTS_TABLE_NAME, contactValues, selection, null)
|
||||
}
|
||||
|
||||
fun getContacts(selection: String? = null, selectionArgs: Array<String>? = null): ArrayList<Contact> {
|
||||
fun insertGroup(group: Group): Group? {
|
||||
val contactValues = fillGroupValues(group)
|
||||
val id = mDb.insert(GROUPS_TABLE_NAME, null, contactValues)
|
||||
return if (id == -1L) {
|
||||
null
|
||||
} else {
|
||||
Group(id, group.title)
|
||||
}
|
||||
}
|
||||
|
||||
fun renameGroup(group: Group): Boolean {
|
||||
val contactValues = fillGroupValues(group)
|
||||
val selection = "$COL_ID = ?"
|
||||
val selectionArgs = arrayOf(group.id.toString())
|
||||
return mDb.update(GROUPS_TABLE_NAME, contactValues, selection, selectionArgs) == 1
|
||||
}
|
||||
|
||||
fun deleteGroup(id: Long) = deleteGroups(arrayOf(id.toString()))
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun getGroups(): ArrayList<Group> {
|
||||
val groups = ArrayList<Group>()
|
||||
val projection = arrayOf(COL_ID, COL_TITLE)
|
||||
val cursor = mDb.query(GROUPS_TABLE_NAME, projection, null, null, null, null, null)
|
||||
cursor.use {
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getLongValue(COL_ID)
|
||||
val title = cursor.getStringValue(COL_TITLE)
|
||||
val group = Group(id, title)
|
||||
groups.add(group)
|
||||
}
|
||||
}
|
||||
return groups
|
||||
}
|
||||
|
||||
private fun fillGroupValues(group: Group): ContentValues {
|
||||
return ContentValues().apply {
|
||||
put(COL_TITLE, group.title)
|
||||
}
|
||||
}
|
||||
|
||||
fun addContactsToGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
contacts.forEach {
|
||||
val currentGroupIds = it.groups.map { it.id } as ArrayList<Long>
|
||||
currentGroupIds.add(groupId)
|
||||
updateContactGroups(it, currentGroupIds)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeContactsFromGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
contacts.forEach {
|
||||
val currentGroupIds = it.groups.map { it.id } as ArrayList<Long>
|
||||
currentGroupIds.remove(groupId)
|
||||
updateContactGroups(it, currentGroupIds)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateContactGroups(contact: Contact, groupIds: ArrayList<Long>) {
|
||||
val contactValues = fillContactGroupValues(groupIds)
|
||||
val selection = "$COL_ID = ?"
|
||||
val selectionArgs = arrayOf(contact.id.toString())
|
||||
mDb.update(CONTACTS_TABLE_NAME, contactValues, selection, selectionArgs)
|
||||
}
|
||||
|
||||
private fun fillContactGroupValues(groupIds: ArrayList<Long>): ContentValues {
|
||||
return ContentValues().apply {
|
||||
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_PHOTO, COL_ADDRESSES, COL_NOTES, COL_GROUPS)
|
||||
val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, selection, selectionArgs, null, null, null)
|
||||
cursor.use {
|
||||
while (cursor.moveToNext()) {
|
||||
@ -163,7 +261,11 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
|
||||
|
||||
val notes = cursor.getStringValue(COL_NOTES)
|
||||
val starred = cursor.getIntValue(COL_STARRED)
|
||||
val groups = ArrayList<Group>()
|
||||
|
||||
val groupIdsJson = cursor.getStringValue(COL_GROUPS)
|
||||
val groupIdsToken = object : TypeToken<List<Long>>() {}.type
|
||||
val groupIds = 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)
|
||||
contacts.add(contact)
|
||||
@ -172,9 +274,9 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
|
||||
return contacts
|
||||
}
|
||||
|
||||
fun getContactWithId(id: Int): Contact? {
|
||||
fun getContactWithId(activity: BaseSimpleActivity, id: Int): Contact? {
|
||||
val selection = "$COL_ID = ?"
|
||||
val selectionArgs = arrayOf(id.toString())
|
||||
return getContacts(selection, selectionArgs).firstOrNull()
|
||||
return getContacts(activity, selection, selectionArgs).firstOrNull()
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
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>)
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package com.simplemobiletools.contacts.interfaces
|
||||
|
||||
interface RefreshContactsListener {
|
||||
fun refreshContacts(refreshContactsTab: Boolean, refreshFavoritesTab: Boolean)
|
||||
|
||||
fun refreshFavorites()
|
||||
fun refreshContacts(refreshTabsMask: Int)
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.simplemobiletools.contacts.interfaces
|
||||
|
||||
import com.simplemobiletools.contacts.models.Contact
|
||||
|
||||
interface RemoveFromGroupListener {
|
||||
fun removeFromGroup(contacts: ArrayList<Contact>)
|
||||
}
|
@ -1,3 +1,16 @@
|
||||
package com.simplemobiletools.contacts.models
|
||||
|
||||
data class Group(var id: Long, var title: String)
|
||||
import com.simplemobiletools.contacts.helpers.FIRST_GROUP_ID
|
||||
import java.io.Serializable
|
||||
|
||||
data class Group(var id: Long, var title: String, var contactsCount: Int = 0) : Serializable {
|
||||
companion object {
|
||||
private const val serialVersionUID = -1384515348451345L
|
||||
}
|
||||
|
||||
fun addContact() = contactsCount++
|
||||
|
||||
fun getBubbleText() = title
|
||||
|
||||
fun isPrivateSecretGroup() = id >= FIRST_GROUP_ID
|
||||
}
|
||||
|
BIN
app/src/main/res/drawable-hdpi/ic_group_add.png
Normal file
After Width: | Height: | Size: 303 B |
BIN
app/src/main/res/drawable-xhdpi/ic_group_add.png
Normal file
After Width: | Height: | Size: 384 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_group_add.png
Normal file
After Width: | Height: | Size: 564 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_group_add.png
Normal file
After Width: | Height: | Size: 729 B |
@ -333,7 +333,7 @@
|
||||
android:layout_toRightOf="@+id/contact_name_image"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/item_group"/>
|
||||
<include layout="@layout/item_edit_group"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
70
app/src/main/res/layout/activity_group_contacts.xml
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/group_contacts_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/group_contacts_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/group_contacts_placeholder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="@dimen/activity_margin"
|
||||
android:gravity="center"
|
||||
android:paddingLeft="@dimen/activity_margin"
|
||||
android:paddingRight="@dimen/activity_margin"
|
||||
android:text="@string/no_group_participants"
|
||||
android:textSize="@dimen/bigger_text_size"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/group_contacts_placeholder_2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/group_contacts_placeholder"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="@dimen/medium_margin"
|
||||
android:paddingTop="@dimen/medium_margin"
|
||||
android:text="@string/add_contacts"
|
||||
android:textSize="@dimen/bigger_text_size"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.simplemobiletools.commons.views.MyRecyclerView
|
||||
android:id="@+id/group_contacts_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbars="none"
|
||||
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/>
|
||||
|
||||
<com.simplemobiletools.commons.views.FastScroller
|
||||
android:id="@+id/group_contacts_fastscroller"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:paddingLeft="@dimen/normal_margin"
|
||||
android:paddingStart="@dimen/normal_margin">
|
||||
|
||||
<include layout="@layout/fastscroller_handle_vertical"/>
|
||||
|
||||
</com.simplemobiletools.commons.views.FastScroller>
|
||||
</RelativeLayout>
|
||||
|
||||
<com.simplemobiletools.commons.views.MyFloatingActionButton
|
||||
android:id="@+id/group_contacts_fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="@dimen/activity_margin"
|
||||
android:src="@drawable/ic_plus"/>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
19
app/src/main/res/layout/dialog_rename_group.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/rename_group_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/activity_margin">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyEditText
|
||||
android:id="@+id/rename_group_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textCapWords"
|
||||
android:singleLine="true"
|
||||
android:textCursorDrawable="@null"
|
||||
android:textSize="@dimen/normal_text_size"/>
|
||||
|
||||
</LinearLayout>
|
@ -5,4 +5,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<include layout="@layout/fragment_layout"/>
|
||||
|
||||
</com.simplemobiletools.contacts.fragments.GroupsFragment>
|
||||
|
@ -19,6 +19,7 @@
|
||||
android:id="@+id/contact_tmb"
|
||||
android:layout_width="@dimen/normal_icon_size"
|
||||
android:layout_height="@dimen/normal_icon_size"
|
||||
android:layout_centerVertical="true"
|
||||
android:padding="@dimen/medium_margin"
|
||||
android:src="@drawable/ic_person"/>
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
android:id="@+id/contact_tmb"
|
||||
android:layout_width="@dimen/normal_icon_size"
|
||||
android:layout_height="@dimen/normal_icon_size"
|
||||
android:layout_centerVertical="true"
|
||||
android:padding="@dimen/medium_margin"
|
||||
android:src="@drawable/ic_person"/>
|
||||
|
||||
|
41
app/src/main/res/layout/item_edit_group.xml
Normal 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>
|
@ -1,41 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/contact_group_holder"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/group_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="@drawable/selector">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/contact_group"
|
||||
<RelativeLayout
|
||||
android:id="@+id/group_holder"
|
||||
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"/>
|
||||
android:paddingRight="@dimen/activity_margin">
|
||||
|
||||
<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"/>
|
||||
<ImageView
|
||||
android:id="@+id/group_tmb"
|
||||
android:layout_width="@dimen/normal_icon_size"
|
||||
android:layout_height="@dimen/normal_icon_size"
|
||||
android:layout_centerVertical="true"
|
||||
android:padding="@dimen/medium_margin"
|
||||
android:src="@drawable/ic_group"/>
|
||||
|
||||
</RelativeLayout>
|
||||
<TextView
|
||||
android:id="@+id/group_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/contact_item_height"
|
||||
android:layout_toRightOf="@+id/group_tmb"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textSize="@dimen/big_text_size"
|
||||
tools:text="Family"/>
|
||||
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
||||
|
@ -16,6 +16,11 @@
|
||||
android:icon="@drawable/ic_star_on"
|
||||
android:title="@string/add_to_favorites"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/cab_add_to_group"
|
||||
android:icon="@drawable/ic_group_add"
|
||||
android:title="@string/add_to_group"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/cab_share"
|
||||
android:icon="@drawable/ic_share"
|
||||
|
19
app/src/main/res/menu/cab_groups.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/cab_edit"
|
||||
android:icon="@drawable/ic_rename"
|
||||
android:title="@string/edit_contact"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/cab_select_all"
|
||||
android:icon="@drawable/ic_select_all"
|
||||
android:title="@string/select_all"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/cab_delete"
|
||||
android:icon="@drawable/ic_delete"
|
||||
android:title="@string/delete"
|
||||
app:showAsAction="ifRoom"/>
|
||||
</menu>
|
@ -6,8 +6,6 @@
|
||||
<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="no_groups">No groups</string>
|
||||
<string name="create_new_group">Create a new group</string>
|
||||
|
||||
<string name="new_contact">Neuer Kontakt</string>
|
||||
<string name="edit_contact">Kontakt bearbeiten</string>
|
||||
@ -17,6 +15,17 @@
|
||||
<string name="middle_name">Zweiter Vorname</string>
|
||||
<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>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">Foto machen</string>
|
||||
<string name="choose_photo">Foto auswählen</string>
|
||||
@ -80,7 +89,7 @@
|
||||
|
||||
Beinhaltet keine Werbung oder unnötige Berechtigungen. Sie ist komplett Open Source, alle verwendeten Farben sind anpassbar.
|
||||
|
||||
Diese App ist nur eine aus einer größeren Serie von schlichten Apps. Der Rest davon findet sich auf http://www.simplemobiletools.com
|
||||
Diese App ist nur eine aus einer größeren Serie von schlichten Apps. Der Rest davon findet sich auf https://www.simplemobiletools.com
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
99
app/src/main/res/values-el/strings.xml
Normal file
@ -0,0 +1,99 @@
|
||||
<resources>
|
||||
<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="phone_storage">Μνήμη τηλεφώνου</string>
|
||||
<string name="phone_storage_hidden">Μνήμη τηλεφώνου (δεν είναι ορατή από άλλες εφαρμογές)</string>
|
||||
|
||||
<string name="new_contact">Νέα επαφή</string>
|
||||
<string name="edit_contact">Επεξεργασία επαφής</string>
|
||||
<string name="select_contact">Επιλογή επαφής</string>
|
||||
<string name="select_contacts">Επιλογή επαφών</string>
|
||||
<string name="first_name">Όνομα</string>
|
||||
<string name="middle_name">Μεσαίο όνομα</string>
|
||||
<string name="surname">Επώνυμο</string>
|
||||
|
||||
<!-- Groups -->
|
||||
<string name="no_groups">Δεν υπάρχουν ομάδες</string>
|
||||
<string name="create_new_group">Δημιουργία νέας ομάδας</string>
|
||||
<string name="remove_from_group">Αφαίρεση από ομάδα</string>
|
||||
<string name="no_group_participants">Η ομάδα είναι άδεια</string>
|
||||
<string name="add_contacts">Προσθήκη επαφών</string>
|
||||
<string name="no_group_created">Δεν υπάρχουν ομάδες επαφών στη συσκευή</string>
|
||||
<string name="create_group">Δημιουργία ομάδας</string>
|
||||
<string name="add_to_group">Προσθήκη σε ομάδα</string>
|
||||
<string name="create_group_under_account">Δημιουργία ομάδας κάτω από λογαριασμό</string>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">Λήψη φωτογραφίας</string>
|
||||
<string name="choose_photo">Επιλογή φωτογραφίας</string>
|
||||
<string name="remove_photo">Αφαίρεση φωτογραφίας</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="start_name_with_surname">Το όνομα ξεκινά με το επώνυμο</string>
|
||||
<string name="show_phone_numbers">Εμφάνιση τηλεφωνικών αριθμών στην κύρια οθόνη</string>
|
||||
<string name="show_contact_thumbnails">Εμφάνιση μικρογραφιών επαφής</string>
|
||||
<string name="on_contact_click">Στην επιλογή επαφής</string>
|
||||
<string name="call_contact">Κλήση επαφής</string>
|
||||
<string name="view_contact">Εμφάνιση λεπτομερειών επαφής</string>
|
||||
<string name="show_favorites_tab">Εμφάνιση καρτέλας αγαπημένων</string>
|
||||
<string name="show_groups_tab">Εμφάνιση καρτέλας ομάδων</string>
|
||||
|
||||
<!-- Emails -->
|
||||
<string name="email">Email</string>
|
||||
<string name="home">Σπίτι</string>
|
||||
<string name="work">Εργασία</string>
|
||||
<string name="other">Άλλο</string>
|
||||
|
||||
<!-- Phone numbers -->
|
||||
<string name="number">Αριθμός</string>
|
||||
<string name="mobile">Κινητό</string>
|
||||
<string name="main_number">Κύριο</string>
|
||||
<string name="work_fax">Φαξ εργασίας</string>
|
||||
<string name="home_fax">Φαξ σπιτιού</string>
|
||||
<string name="pager">Βομβητής</string>
|
||||
<string name="no_phone_number_found">Δεν βρέθηκε τηλεφωνικός αριθμός</string>
|
||||
|
||||
<!-- Events -->
|
||||
<string name="birthday">Γενέθλια</string>
|
||||
<string name="anniversary">Επέτειος</string>
|
||||
|
||||
<!-- Favorites -->
|
||||
<string name="no_favorites">Φαίνεται ότι δεν έχεις προσθέσει αγαπημένες επαφές ακόμα.</string>
|
||||
<string name="add_favorites">Προσθήκη αγαπημένων</string>
|
||||
<string name="add_to_favorites">Προσθήκη στα αγαπημένα</string>
|
||||
<string name="remove_from_favorites">Αφαίρεση από τα αγαπημένα</string>
|
||||
|
||||
<!-- Search -->
|
||||
<string name="search_contacts">Αναζήτηση επαφών</string>
|
||||
<string name="search_favorites">Αναζήτηση αγαπημένων</string>
|
||||
|
||||
<!-- Export / Import -->
|
||||
<string name="import_contacts">Εισαγωγή επαφών</string>
|
||||
<string name="export_contacts">Εξαγωγή επαφών</string>
|
||||
<string name="import_contacts_from_vcf">Εισαγωγή επαφών από .vcf αρχείο</string>
|
||||
<string name="export_contacts_to_vcf">Εξαγωγή επαφών σε .vcf αρχείο</string>
|
||||
<string name="target_contact_source">Πηγή επαφής προορισμού</string>
|
||||
<string name="include_contact_sources">Συμπερίληψη πηγών επαφών</string>
|
||||
<string name="filename_without_vcf">Όνομα αρχείου (χωρίς .vcf)</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>
|
||||
<string name="app_long_description">
|
||||
Μια απλή εφαρμογή για δημιουργία και διαχείριση των επαφών σου από κάθε πηγή. Οι επαφές μπορεί να είναι αποθηκευμένες μόνο στη συσκευή σου, αλλά μπορούν να συγχρονίζονται στο Google, ή σε κάποιο άλλο λογαριασμό. Μπορείς να εμφανίσεις τις αγαπημένες σου επαφές σε ξεχωριστή λίστα.
|
||||
|
||||
Μπορείς να τη χρησιμοποιήσεις για τη διαχείριση των email των χρηστών και τα γεγονότα. Έχει τη δυνατότητα ταξινόμησης/φιλτραρίσματος με διάφορες παραμέτρους, προαιρετικά να εμφανίζεται το επώνυμο σαν όνομα.
|
||||
|
||||
Δεν περιέχει διαφημίσεις ή περιττές άδειες. Είναι πλήρως ανοικτού κώδικα, παρέχει δυνατότητα προσαρμογής των χρωμάτων.
|
||||
|
||||
Αυτή η εφαρμογή είναι ένα μικρό κομμάτι μιας μεγαλύτερης συλλογής εφαρμογών. Μπορείς να βρεις τις υπόλοιπες στο https://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>
|
@ -6,8 +6,6 @@
|
||||
<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="no_groups">No groups</string>
|
||||
<string name="create_new_group">Create a new group</string>
|
||||
|
||||
<string name="new_contact">Nouveau contact</string>
|
||||
<string name="edit_contact">Modifier contact</string>
|
||||
@ -17,6 +15,17 @@
|
||||
<string name="middle_name">Nom</string>
|
||||
<string name="surname">Surnom</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>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">Prendre une photo</string>
|
||||
<string name="choose_photo">Choisir une photo</string>
|
||||
@ -80,7 +89,7 @@
|
||||
|
||||
Aucune publicité ni de permission inutile. Elle est entièrement open source et vous permet de personnaliser les couleurs.
|
||||
|
||||
Cette application fait parti d\'un groupe d\'applications. Vous pouvez trouver le reste des applis sur http://www.simplemobiletools.com
|
||||
Cette application fait parti d\'un groupe d\'applications. Vous pouvez trouver le reste des applis sur https://www.simplemobiletools.com
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
@ -6,8 +6,6 @@
|
||||
<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="no_groups">No groups</string>
|
||||
<string name="create_new_group">Create a new group</string>
|
||||
|
||||
<string name="new_contact">새로운 연락처</string>
|
||||
<string name="edit_contact">연락처 수정</string>
|
||||
@ -17,6 +15,17 @@
|
||||
<string name="middle_name">중간 이름</string>
|
||||
<string name="surname">성</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>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">사진 촬영</string>
|
||||
<string name="choose_photo">사진 선택</string>
|
||||
@ -80,7 +89,7 @@
|
||||
|
||||
광고가 포함되어 있거나, 불필요한 권한을 요청하지 않습니다. 이 앱의 모든 소스는 오픈소스이며, 사용자가 직접 애플리케이션의 컬러를 설정 할 수 있습니다.
|
||||
|
||||
이 앱은 다양한 시리즈의 모바일앱 중 하나입니다. 나머지는 http://www.simplemobiletools.com 에서 찾아 보실 수 있습니다.
|
||||
이 앱은 다양한 시리즈의 모바일앱 중 하나입니다. 나머지는 https://www.simplemobiletools.com 에서 찾아 보실 수 있습니다.
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
99
app/src/main/res/values-lt/strings.xml
Normal file
@ -0,0 +1,99 @@
|
||||
<resources>
|
||||
<string name="app_name">Paprasti kontaktai</string>
|
||||
<string name="app_launcher_name">Kontaktai</string>
|
||||
<string name="address">Adresas</string>
|
||||
<string name="inserting">Įterpiama…</string>
|
||||
<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="new_contact">Naujas kontaktas</string>
|
||||
<string name="edit_contact">Redaguoti kontaktą</string>
|
||||
<string name="select_contact">Pasirinkti kontaktą</string>
|
||||
<string name="select_contacts">pasirinkti kontaktus</string>
|
||||
<string name="first_name">Vardas</string>
|
||||
<string name="middle_name">Antras vardas</string>
|
||||
<string name="surname">Pavardė</string>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">Nufotografuoti</string>
|
||||
<string name="choose_photo">Pasirinkti nuotrauką</string>
|
||||
<string name="remove_photo">Pašalinti nuotrauką</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="start_name_with_surname">Pavardė rodoma pirma</string>
|
||||
<string name="show_phone_numbers">Rodyti telefono numerius pagrindiniame programos ekrane</string>
|
||||
<string name="show_contact_thumbnails">Rodyti kontaktų miniatiūras</string>
|
||||
<string name="on_contact_click">Ant kontakto paspaudimo</string>
|
||||
<string name="call_contact">Skambinti kontaktui</string>
|
||||
<string name="view_contact">Žiūrėti kontakto detales</string>
|
||||
<string name="show_favorites_tab">Rodyti mėgiamiausiųjų skirtuką</string>
|
||||
<string name="show_groups_tab">Rodyti grupių skirtuką</string>
|
||||
|
||||
<!-- Emails -->
|
||||
<string name="email">Elektroninis paštas</string>
|
||||
<string name="home">Namų</string>
|
||||
<string name="work">Darbo</string>
|
||||
<string name="other">Kitas</string>
|
||||
|
||||
<!-- Phone numbers -->
|
||||
<string name="number">Numeris</string>
|
||||
<string name="mobile">Mobilus</string>
|
||||
<string name="main_number">Pagrindinis</string>
|
||||
<string name="work_fax">Darbo faksas</string>
|
||||
<string name="home_fax">Namų faksas</string>
|
||||
<string name="pager">Pranešimų gaviklis</string>
|
||||
<string name="no_phone_number_found">Nerasta telefono numerio</string>
|
||||
|
||||
<!-- Events -->
|
||||
<string name="birthday">Gimtadienis</string>
|
||||
<string name="anniversary">Sukaktis</string>
|
||||
|
||||
<!-- Favorites -->
|
||||
<string name="no_favorites">Atrodo jog Jūs dar neįvedėte nė vieno mėgiamiausiojo kontakto.</string>
|
||||
<string name="add_favorites">Pridėti mėgiamiausiuosius</string>
|
||||
<string name="add_to_favorites">Pridėti į mėgiamiausiuosius</string>
|
||||
<string name="remove_from_favorites">Pašalinti iš mėgiamiausiųjų</string>
|
||||
|
||||
<!-- Search -->
|
||||
<string name="search_contacts">Ieškoti kontaktų</string>
|
||||
<string name="search_favorites">Ieškoti mėgiamiausiųjų</string>
|
||||
|
||||
<!-- Export / Import -->
|
||||
<string name="import_contacts">Importuoti kontaktus</string>
|
||||
<string name="export_contacts">Eksportuoti kontaktus</string>
|
||||
<string name="import_contacts_from_vcf">Importuoti kontaktus iš .vcf bylos</string>
|
||||
<string name="export_contacts_to_vcf">Eksportuoti kontaktus į .vcf bylą</string>
|
||||
<string name="target_contact_source">Tikslinis kontakto šaltinis</string>
|
||||
<string name="include_contact_sources">Įtraukti kontaktų šaltinius</string>
|
||||
<string name="filename_without_vcf">Bylos vardas (be .vcf)</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>
|
||||
<string name="app_long_description">
|
||||
Paprasta programėlė įrenginio kontaktų kūrimui ir tvarkymui iš įvairių šaltinių. Kontaktai gali būti saugomi Jūsų įrenginyje, taip pat sinchronizuojami per Google, ar kitas paskyras. Jūs galite matyti mėgiamiausiuosius kontaktus atskirame sąraše.
|
||||
|
||||
Jūs taip pat galite naudoti programėlę elektroninių paštų adresų tvarkymui. Programėlė turi galimybę rikiuoti/filtruoti pagal įvairius parametrus, taip pat rodyti pavardę pirma vardo.
|
||||
|
||||
Neturi reklamų ar nereikalingų leidimų. Programėlė visiškai atviro kodo, yra galimybė keisti spalvas.
|
||||
|
||||
Ši programėle yra vienintelė iš keletos mūsų programėlių. Likusias Jūs galite rasti čia https://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>
|
@ -6,8 +6,6 @@
|
||||
<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="no_groups">No groups</string>
|
||||
<string name="create_new_group">Create a new group</string>
|
||||
|
||||
<string name="new_contact">Novo contacto</string>
|
||||
<string name="edit_contact">Editar contacto</string>
|
||||
@ -17,6 +15,17 @@
|
||||
<string name="middle_name">Segundo nome</string>
|
||||
<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>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">Tirar foto</string>
|
||||
<string name="choose_photo">Escolher foto</string>
|
||||
@ -80,7 +89,7 @@
|
||||
|
||||
Contains no ads or unnecessary permissions. It is fully opensource, provides customizable colors.
|
||||
|
||||
This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
|
||||
This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
@ -6,8 +6,6 @@
|
||||
<string name="updating">Обновление…</string>
|
||||
<string name="phone_storage">Память устройства</string>
|
||||
<string name="phone_storage_hidden">Память устройства (не видна другим приложениям)</string>
|
||||
<string name="no_groups">Нет групп</string>
|
||||
<string name="create_new_group">Создать новую группу</string>
|
||||
|
||||
<string name="new_contact">Новый контакт</string>
|
||||
<string name="edit_contact">Редактировать контакт</string>
|
||||
@ -17,6 +15,17 @@
|
||||
<string name="middle_name">Отчество</string>
|
||||
<string name="surname">Фамилия</string>
|
||||
|
||||
<!-- Groups -->
|
||||
<string name="no_groups">Нет групп</string>
|
||||
<string name="create_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>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">Снять фото</string>
|
||||
<string name="choose_photo">Выбрать фото</string>
|
||||
@ -80,7 +89,7 @@
|
||||
|
||||
Не содержит рекламы или ненужных разрешений, полностью с открытым исходным кодом. Есть возможность настраивать цвета.
|
||||
|
||||
Это приложение — всего лишь частица из большой серии приложений. Вы можете найти остальные на http://www.simplemobiletools.com
|
||||
Это приложение — всего лишь частица из большой серии приложений. Вы можете найти остальные на https://www.simplemobiletools.com
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
@ -6,8 +6,6 @@
|
||||
<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="no_groups">Žiadne skupiny</string>
|
||||
<string name="create_new_group">Vytvoriť novú skupinu</string>
|
||||
|
||||
<string name="new_contact">Nový kontakt</string>
|
||||
<string name="edit_contact">Upraviť kontakt</string>
|
||||
@ -17,6 +15,17 @@
|
||||
<string name="middle_name">Stredné meno</string>
|
||||
<string name="surname">Priezvisko</string>
|
||||
|
||||
<!-- Groups -->
|
||||
<string name="no_groups">Žiadne skupiny</string>
|
||||
<string name="create_new_group">Vytvoriť novú skupinu</string>
|
||||
<string name="remove_from_group">Odstrániť zo skupiny</string>
|
||||
<string name="no_group_participants">Skupina je prázdna</string>
|
||||
<string name="add_contacts">Pridať kontakty</string>
|
||||
<string name="no_group_created">Nemáte v zariadení vytvorené žiadne skupiny kontaktov</string>
|
||||
<string name="create_group">Vytvoriť skupinu</string>
|
||||
<string name="add_to_group">Pridať do skupiny</string>
|
||||
<string name="create_group_under_account">Vytvoriť skupinu pod účet</string>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">Vytvoriť foto</string>
|
||||
<string name="choose_photo">Zvoliť foto</string>
|
||||
@ -80,7 +89,7 @@
|
||||
|
||||
Neobsahuje žiadne reklamy a nepotrebné oprávnenia. Je opensource, poskytuje možnosť zmeny farieb.
|
||||
|
||||
Táto aplikácia je iba jednou zo skupiny aplikácií. Ostatné viete nájsť na http://www.simplemobiletools.com
|
||||
Táto aplikácia je iba jednou zo skupiny aplikácií. Ostatné viete nájsť na https://www.simplemobiletools.com
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
@ -6,8 +6,6 @@
|
||||
<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="no_groups">No groups</string>
|
||||
<string name="create_new_group">Create a new group</string>
|
||||
|
||||
<string name="new_contact">Ny kontakt</string>
|
||||
<string name="edit_contact">Redigera kontakt</string>
|
||||
@ -17,6 +15,17 @@
|
||||
<string name="middle_name">Mellannamn</string>
|
||||
<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>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">Ta foto</string>
|
||||
<string name="choose_photo">Välj foto</string>
|
||||
@ -80,7 +89,7 @@
|
||||
|
||||
Innehåller ingen reklam eller onödiga behörigheter. Den har helt öppen källkod och anpassningsbara färger.
|
||||
|
||||
Denna app är bara en del av en större serie appar. Du hittar resten av dem på http://www.simplemobiletools.com
|
||||
Denna app är bara en del av en större serie appar. Du hittar resten av dem på https://www.simplemobiletools.com
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
@ -6,8 +6,6 @@
|
||||
<string name="updating">更新中…</string>
|
||||
<string name="phone_storage">手機空間</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="edit_contact">編輯聯絡人</string>
|
||||
@ -17,6 +15,17 @@
|
||||
<string name="middle_name">中間名</string>
|
||||
<string name="surname">姓氏</string>
|
||||
|
||||
<!-- Groups -->
|
||||
<string name="no_groups">沒有群組</string>
|
||||
<string name="create_new_group">建立一個新群組</string>
|
||||
<string name="remove_from_group">從群組內移除</string>
|
||||
<string name="no_group_participants">這群組是空白的</string>
|
||||
<string name="add_contacts">添加聯絡人</string>
|
||||
<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>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">拍照</string>
|
||||
<string name="choose_photo">選擇相片</string>
|
||||
@ -80,7 +89,7 @@
|
||||
|
||||
不包含廣告及非必要的權限,而且完全開放原始碼,並提供自訂顏色。
|
||||
|
||||
這程式只是一系列眾多應用程式的其中一項,你可以在這發現更多 http://www.simplemobiletools.com
|
||||
這程式只是一系列眾多應用程式的其中一項,你可以在這發現更多 https://www.simplemobiletools.com
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
@ -5,4 +5,6 @@
|
||||
<string name="release_11">Added Address and Notes fields</string>
|
||||
<string name="release_10">Allow storing contacts in a local database, hidden from other apps</string>
|
||||
|
||||
<string name="groups_placeholder">%1$s (%2$s)</string>
|
||||
|
||||
</resources>
|
||||
|
@ -6,8 +6,6 @@
|
||||
<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="no_groups">No groups</string>
|
||||
<string name="create_new_group">Create a new group</string>
|
||||
|
||||
<string name="new_contact">New contact</string>
|
||||
<string name="edit_contact">Edit contact</string>
|
||||
@ -17,6 +15,17 @@
|
||||
<string name="middle_name">Middle name</string>
|
||||
<string name="surname">Surname</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>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">Take photo</string>
|
||||
<string name="choose_photo">Choose photo</string>
|
||||
@ -80,7 +89,7 @@
|
||||
|
||||
Contains no ads or unnecessary permissions. It is fully opensource, provides customizable colors.
|
||||
|
||||
This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
|
||||
This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<external-path name="external_files" path="."/>
|
||||
<root-path name="external_files" path="/storage/" />
|
||||
<cache-path name="cache_files" path="my_cache/" />
|
||||
<cache-path name="shared_contacts" path="contacts/"/>
|
||||
<root-path name="external_files" path="/" />
|
||||
</paths>
|
||||
|
@ -4,4 +4,4 @@ You can use it for managing user emails and events too. It has the ability to so
|
||||
|
||||
Contains no ads or unnecessary permissions. It is fully opensource, provides customizable colors.
|
||||
|
||||
This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
|
||||
This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com
|
||||
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 90 KiB |