mirror of
https://github.com/SimpleMobileTools/Simple-Contacts.git
synced 2025-06-05 21:59:27 +02:00
imports contacts helper & extensions
This commit is contained in:
@@ -5,6 +5,7 @@ import org.jetbrains.kotlin.konan.properties.Properties
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android)
|
alias(libs.plugins.android)
|
||||||
alias(libs.plugins.kotlinAndroid)
|
alias(libs.plugins.kotlinAndroid)
|
||||||
|
alias(libs.plugins.kotlinSerialization)
|
||||||
alias(libs.plugins.ksp)
|
alias(libs.plugins.ksp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +89,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(libs.kotlinx.serialization.json)
|
||||||
implementation(libs.simple.tools.commons)
|
implementation(libs.simple.tools.commons)
|
||||||
implementation(libs.androidx.swiperefreshlayout)
|
implementation(libs.androidx.swiperefreshlayout)
|
||||||
implementation(libs.autofittextview)
|
implementation(libs.autofittextview)
|
||||||
|
@@ -24,6 +24,7 @@ import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
|||||||
import com.simplemobiletools.commons.dialogs.FilePickerDialog
|
import com.simplemobiletools.commons.dialogs.FilePickerDialog
|
||||||
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
|
//import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.*
|
import com.simplemobiletools.commons.helpers.*
|
||||||
import com.simplemobiletools.commons.models.FAQItem
|
import com.simplemobiletools.commons.models.FAQItem
|
||||||
import com.simplemobiletools.commons.models.PhoneNumber
|
import com.simplemobiletools.commons.models.PhoneNumber
|
||||||
@@ -38,11 +39,16 @@ import com.simplemobiletools.contacts.pro.dialogs.ChangeSortingDialog
|
|||||||
import com.simplemobiletools.contacts.pro.dialogs.ExportContactsDialog
|
import com.simplemobiletools.contacts.pro.dialogs.ExportContactsDialog
|
||||||
import com.simplemobiletools.contacts.pro.dialogs.FilterContactSourcesDialog
|
import com.simplemobiletools.contacts.pro.dialogs.FilterContactSourcesDialog
|
||||||
import com.simplemobiletools.contacts.pro.dialogs.ImportContactsDialog
|
import com.simplemobiletools.contacts.pro.dialogs.ImportContactsDialog
|
||||||
import com.simplemobiletools.contacts.pro.extensions.config
|
import com.simplemobiletools.contacts.pro.extensions.*
|
||||||
import com.simplemobiletools.contacts.pro.extensions.handleGenericContactClick
|
import com.simplemobiletools.contacts.pro.extensions.getTempFile
|
||||||
|
import com.simplemobiletools.contacts.pro.extensions.isPackageInstalled
|
||||||
|
import com.simplemobiletools.contacts.pro.extensions.showErrorToast
|
||||||
|
import com.simplemobiletools.contacts.pro.extensions.toast
|
||||||
|
import com.simplemobiletools.contacts.pro.extensions.updateBottomTabItemColors
|
||||||
import com.simplemobiletools.contacts.pro.fragments.FavoritesFragment
|
import com.simplemobiletools.contacts.pro.fragments.FavoritesFragment
|
||||||
import com.simplemobiletools.contacts.pro.fragments.MyViewPagerFragment
|
import com.simplemobiletools.contacts.pro.fragments.MyViewPagerFragment
|
||||||
import com.simplemobiletools.contacts.pro.helpers.ALL_TABS_MASK
|
import com.simplemobiletools.contacts.pro.helpers.ALL_TABS_MASK
|
||||||
|
import com.simplemobiletools.contacts.pro.helpers.ContactsHelper
|
||||||
import com.simplemobiletools.contacts.pro.helpers.VcfExporter
|
import com.simplemobiletools.contacts.pro.helpers.VcfExporter
|
||||||
import com.simplemobiletools.contacts.pro.helpers.tabsList
|
import com.simplemobiletools.contacts.pro.helpers.tabsList
|
||||||
import com.simplemobiletools.contacts.pro.interfaces.RefreshContactsListener
|
import com.simplemobiletools.contacts.pro.interfaces.RefreshContactsListener
|
||||||
@@ -624,44 +630,48 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
|||||||
binding.viewPager.currentItem = getDefaultTab()
|
binding.viewPager.currentItem = getDefaultTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
val initToLoad = System.currentTimeMillis() - timeInMs
|
|
||||||
ContactsHelper(this).getContacts { contacts ->
|
|
||||||
val diff = System.currentTimeMillis() - timeInMs
|
|
||||||
val msg = "loaded ${contacts.size} in $diff ms (init: $initToLoad + load: ${diff - initToLoad})";
|
|
||||||
Log.e("TAGG", msg)
|
|
||||||
toast(msg)
|
|
||||||
isGettingContacts = false
|
|
||||||
if (isDestroyed || isFinishing) {
|
|
||||||
return@getContacts
|
|
||||||
}
|
|
||||||
|
|
||||||
if (refreshTabsMask and TAB_CONTACTS != 0) {
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
findViewById<MyViewPagerFragment<*>>(R.id.contacts_fragment)?.apply {
|
val initToLoad = System.currentTimeMillis() - timeInMs
|
||||||
skipHashComparing = true
|
ContactsHelper(this).getContacts { contacts ->
|
||||||
refreshContacts(contacts)
|
val diff = System.currentTimeMillis() - timeInMs
|
||||||
|
val msg = "loaded ${contacts.size} in $diff ms (init: $initToLoad + load: ${diff - initToLoad})";
|
||||||
|
Log.e("TAGG", msg)
|
||||||
|
toast(msg)
|
||||||
|
isGettingContacts = false
|
||||||
|
if (isDestroyed || isFinishing) {
|
||||||
|
return@getContacts
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (refreshTabsMask and TAB_FAVORITES != 0) {
|
if (refreshTabsMask and TAB_CONTACTS != 0) {
|
||||||
findViewById<MyViewPagerFragment<*>>(R.id.favorites_fragment)?.apply {
|
findViewById<MyViewPagerFragment<*>>(R.id.contacts_fragment)?.apply {
|
||||||
skipHashComparing = true
|
|
||||||
refreshContacts(contacts)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (refreshTabsMask and TAB_GROUPS != 0) {
|
|
||||||
findViewById<MyViewPagerFragment<*>>(R.id.groups_fragment)?.apply {
|
|
||||||
if (refreshTabsMask == TAB_GROUPS) {
|
|
||||||
skipHashComparing = true
|
skipHashComparing = true
|
||||||
|
refreshContacts(contacts)
|
||||||
}
|
}
|
||||||
refreshContacts(contacts)
|
}
|
||||||
|
|
||||||
|
if (refreshTabsMask and TAB_FAVORITES != 0) {
|
||||||
|
findViewById<MyViewPagerFragment<*>>(R.id.favorites_fragment)?.apply {
|
||||||
|
skipHashComparing = true
|
||||||
|
refreshContacts(contacts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refreshTabsMask and TAB_GROUPS != 0) {
|
||||||
|
findViewById<MyViewPagerFragment<*>>(R.id.groups_fragment)?.apply {
|
||||||
|
if (refreshTabsMask == TAB_GROUPS) {
|
||||||
|
skipHashComparing = true
|
||||||
|
}
|
||||||
|
refreshContacts(contacts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binding.mainMenu.isSearchOpen) {
|
||||||
|
getCurrentFragment()?.onSearchQueryChanged(binding.mainMenu.getCurrentQuery())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (binding.mainMenu.isSearchOpen) {
|
}, 3000)
|
||||||
getCurrentFragment()?.onSearchQueryChanged(binding.mainMenu.getCurrentQuery())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun contactClicked(contact: Contact) {
|
override fun contactClicked(contact: Contact) {
|
||||||
|
@@ -20,6 +20,7 @@ import com.simplemobiletools.commons.dialogs.CallConfirmationDialog
|
|||||||
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
||||||
import com.simplemobiletools.commons.dialogs.SelectAlarmSoundDialog
|
import com.simplemobiletools.commons.dialogs.SelectAlarmSoundDialog
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
|
import com.simplemobiletools.contacts.pro.helpers.*
|
||||||
import com.simplemobiletools.commons.helpers.*
|
import com.simplemobiletools.commons.helpers.*
|
||||||
import com.simplemobiletools.commons.models.PhoneNumber
|
import com.simplemobiletools.commons.models.PhoneNumber
|
||||||
import com.simplemobiletools.commons.models.contacts.*
|
import com.simplemobiletools.commons.models.contacts.*
|
||||||
@@ -32,6 +33,7 @@ import com.simplemobiletools.contacts.pro.extensions.editContact
|
|||||||
import com.simplemobiletools.contacts.pro.extensions.getPackageDrawable
|
import com.simplemobiletools.contacts.pro.extensions.getPackageDrawable
|
||||||
import com.simplemobiletools.contacts.pro.extensions.startCallIntent
|
import com.simplemobiletools.contacts.pro.extensions.startCallIntent
|
||||||
import com.simplemobiletools.contacts.pro.helpers.*
|
import com.simplemobiletools.contacts.pro.helpers.*
|
||||||
|
import com.simplemobiletools.contacts.pro.helpers.ContactsHelper
|
||||||
|
|
||||||
class ViewContactActivity : ContactActivity() {
|
class ViewContactActivity : ContactActivity() {
|
||||||
private var isViewIntent = false
|
private var isViewIntent = false
|
||||||
|
@@ -0,0 +1,400 @@
|
|||||||
|
package com.simplemobiletools.contacts.pro.extensions
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.provider.ContactsContract
|
||||||
|
import android.telephony.PhoneNumberUtils
|
||||||
|
import com.simplemobiletools.commons.R
|
||||||
|
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||||
|
import com.simplemobiletools.commons.databases.ContactsDatabase
|
||||||
|
import com.simplemobiletools.commons.dialogs.CallConfirmationDialog
|
||||||
|
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||||
|
import com.simplemobiletools.commons.extensions.getIntValue
|
||||||
|
import com.simplemobiletools.commons.extensions.getLongValue
|
||||||
|
import com.simplemobiletools.commons.extensions.getStringValue
|
||||||
|
import com.simplemobiletools.commons.helpers.*
|
||||||
|
import com.simplemobiletools.commons.interfaces.ContactsDao
|
||||||
|
import com.simplemobiletools.commons.interfaces.GroupsDao
|
||||||
|
import com.simplemobiletools.commons.models.RadioItem
|
||||||
|
import com.simplemobiletools.commons.models.contacts.Contact
|
||||||
|
import com.simplemobiletools.commons.models.contacts.ContactSource
|
||||||
|
import com.simplemobiletools.commons.models.contacts.Organization
|
||||||
|
import com.simplemobiletools.commons.models.contacts.SocialAction
|
||||||
|
import com.simplemobiletools.contacts.pro.helpers.ContactsHelper
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
val Context.contactsDB: ContactsDao get() = ContactsDatabase.getInstance(applicationContext).ContactsDao()
|
||||||
|
|
||||||
|
val Context.groupsDB: GroupsDao get() = ContactsDatabase.getInstance(applicationContext).GroupsDao()
|
||||||
|
|
||||||
|
fun Context.getEmptyContact(): Contact {
|
||||||
|
val originalContactSource = if (hasContactPermissions()) baseConfig.lastUsedContactSource else SMT_PRIVATE
|
||||||
|
val organization = Organization("", "")
|
||||||
|
return Contact(
|
||||||
|
0, "", "", "", "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), originalContactSource, 0, 0, "",
|
||||||
|
null, "", ArrayList(), organization, ArrayList(), ArrayList(), DEFAULT_MIMETYPE, null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.sendAddressIntent(address: String) {
|
||||||
|
val location = Uri.encode(address)
|
||||||
|
val uri = Uri.parse("geo:0,0?q=$location")
|
||||||
|
|
||||||
|
Intent(Intent.ACTION_VIEW, uri).apply {
|
||||||
|
launchActivityIntent(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.openWebsiteIntent(url: String) {
|
||||||
|
val website = if (url.startsWith("http")) {
|
||||||
|
url
|
||||||
|
} else {
|
||||||
|
"https://$url"
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent(Intent.ACTION_VIEW).apply {
|
||||||
|
data = Uri.parse(website)
|
||||||
|
launchActivityIntent(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getLookupUriRawId(dataUri: Uri): Int {
|
||||||
|
val lookupKey = getLookupKeyFromUri(dataUri)
|
||||||
|
if (lookupKey != null) {
|
||||||
|
val uri = lookupContactUri(lookupKey, this)
|
||||||
|
if (uri != null) {
|
||||||
|
return getContactUriRawId(uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getContactUriRawId(uri: Uri): Int {
|
||||||
|
val projection = arrayOf(ContactsContract.Contacts.NAME_RAW_CONTACT_ID)
|
||||||
|
var cursor: Cursor? = null
|
||||||
|
try {
|
||||||
|
cursor = contentResolver.query(uri, projection, null, null, null)
|
||||||
|
if (cursor!!.moveToFirst()) {
|
||||||
|
return cursor.getIntValue(ContactsContract.Contacts.NAME_RAW_CONTACT_ID)
|
||||||
|
}
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
} finally {
|
||||||
|
cursor?.close()
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// from https://android.googlesource.com/platform/packages/apps/Dialer/+/68038172793ee0e2ab3e2e56ddfbeb82879d1f58/java/com/android/contacts/common/util/UriUtils.java
|
||||||
|
fun getLookupKeyFromUri(lookupUri: Uri): String? {
|
||||||
|
return if (!isEncodedContactUri(lookupUri)) {
|
||||||
|
val segments = lookupUri.pathSegments
|
||||||
|
if (segments.size < 3) null else Uri.encode(segments[2])
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isEncodedContactUri(uri: Uri?): Boolean {
|
||||||
|
if (uri == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val lastPathSegment = uri.lastPathSegment ?: return false
|
||||||
|
return lastPathSegment == "encoded"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun lookupContactUri(lookup: String, context: Context): Uri? {
|
||||||
|
val lookupUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookup)
|
||||||
|
return try {
|
||||||
|
ContactsContract.Contacts.lookupContact(context.contentResolver, lookupUri)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getCachePhoto(): File {
|
||||||
|
val imagesFolder = File(cacheDir, "my_cache")
|
||||||
|
if (!imagesFolder.exists()) {
|
||||||
|
imagesFolder.mkdirs()
|
||||||
|
}
|
||||||
|
|
||||||
|
val file = File(imagesFolder, "Photo_${System.currentTimeMillis()}.jpg")
|
||||||
|
file.createNewFile()
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getPhotoThumbnailSize(): Int {
|
||||||
|
val uri = ContactsContract.DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI
|
||||||
|
val projection = arrayOf(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM)
|
||||||
|
var cursor: Cursor? = null
|
||||||
|
try {
|
||||||
|
cursor = contentResolver.query(uri, projection, null, null, null)
|
||||||
|
if (cursor?.moveToFirst() == true) {
|
||||||
|
return cursor.getIntValue(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM)
|
||||||
|
}
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
} finally {
|
||||||
|
cursor?.close()
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.hasContactPermissions() = hasPermission(PERMISSION_READ_CONTACTS) && hasPermission(PERMISSION_WRITE_CONTACTS)
|
||||||
|
|
||||||
|
fun Context.getPublicContactSource(source: String, callback: (String) -> Unit) {
|
||||||
|
when (source) {
|
||||||
|
SMT_PRIVATE -> callback(getString(R.string.phone_storage_hidden))
|
||||||
|
else -> {
|
||||||
|
ContactsHelper(this).getContactSources {
|
||||||
|
var newSource = source
|
||||||
|
for (contactSource in it) {
|
||||||
|
if (contactSource.name == source && contactSource.type == TELEGRAM_PACKAGE) {
|
||||||
|
newSource = getString(R.string.telegram)
|
||||||
|
break
|
||||||
|
} else if (contactSource.name == source && contactSource.type == VIBER_PACKAGE) {
|
||||||
|
newSource = getString(R.string.viber)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
callback(newSource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getPublicContactSourceSync(source: String, contactSources: ArrayList<ContactSource>): String {
|
||||||
|
return when (source) {
|
||||||
|
SMT_PRIVATE -> getString(R.string.phone_storage_hidden)
|
||||||
|
else -> {
|
||||||
|
var newSource = source
|
||||||
|
for (contactSource in contactSources) {
|
||||||
|
if (contactSource.name == source && contactSource.type == TELEGRAM_PACKAGE) {
|
||||||
|
newSource = getString(R.string.telegram)
|
||||||
|
break
|
||||||
|
} else if (contactSource.name == source && contactSource.type == VIBER_PACKAGE) {
|
||||||
|
newSource = getString(R.string.viber)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newSource
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.sendSMSToContacts(contacts: ArrayList<Contact>) {
|
||||||
|
val numbers = StringBuilder()
|
||||||
|
contacts.forEach {
|
||||||
|
val number = it.phoneNumbers.firstOrNull { it.type == ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE }
|
||||||
|
?: it.phoneNumbers.firstOrNull()
|
||||||
|
if (number != null) {
|
||||||
|
numbers.append("${Uri.encode(number.value)};")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val uriString = "smsto:${numbers.toString().trimEnd(';')}"
|
||||||
|
Intent(Intent.ACTION_SENDTO, Uri.parse(uriString)).apply {
|
||||||
|
launchActivityIntent(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.sendEmailToContacts(contacts: ArrayList<Contact>) {
|
||||||
|
val emails = ArrayList<String>()
|
||||||
|
contacts.forEach {
|
||||||
|
it.emails.forEach {
|
||||||
|
if (it.value.isNotEmpty()) {
|
||||||
|
emails.add(it.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent(Intent.ACTION_SEND_MULTIPLE).apply {
|
||||||
|
type = "message/rfc822"
|
||||||
|
putExtra(Intent.EXTRA_EMAIL, emails.toTypedArray())
|
||||||
|
launchActivityIntent(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getTempFile(filename: String = DEFAULT_FILE_NAME): File? {
|
||||||
|
val folder = File(cacheDir, "contacts")
|
||||||
|
if (!folder.exists()) {
|
||||||
|
if (!folder.mkdir()) {
|
||||||
|
toast(R.string.unknown_error_occurred)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return File(folder, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.addContactsToGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||||
|
val publicContacts = contacts.filter { !it.isPrivate() }.toMutableList() as ArrayList<Contact>
|
||||||
|
val privateContacts = contacts.filter { it.isPrivate() }.toMutableList() as ArrayList<Contact>
|
||||||
|
if (publicContacts.isNotEmpty()) {
|
||||||
|
ContactsHelper(this).addContactsToGroup(publicContacts, groupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (privateContacts.isNotEmpty()) {
|
||||||
|
LocalContactsHelper(this).addContactsToGroup(privateContacts, groupId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.removeContactsFromGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||||
|
val publicContacts = contacts.filter { !it.isPrivate() }.toMutableList() as ArrayList<Contact>
|
||||||
|
val privateContacts = contacts.filter { it.isPrivate() }.toMutableList() as ArrayList<Contact>
|
||||||
|
if (publicContacts.isNotEmpty() && hasContactPermissions()) {
|
||||||
|
ContactsHelper(this).removeContactsFromGroup(publicContacts, groupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (privateContacts.isNotEmpty()) {
|
||||||
|
LocalContactsHelper(this).removeContactsFromGroup(privateContacts, groupId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getContactPublicUri(contact: Contact): Uri {
|
||||||
|
val lookupKey = if (contact.isPrivate()) {
|
||||||
|
"local_${contact.id}"
|
||||||
|
} else {
|
||||||
|
SimpleContactsHelper(this).getContactLookupKey(contact.id.toString())
|
||||||
|
}
|
||||||
|
return Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getVisibleContactSources(): ArrayList<String> {
|
||||||
|
val sources = getAllContactSources()
|
||||||
|
val ignoredContactSources = baseConfig.ignoredContactSources
|
||||||
|
return ArrayList(sources).filter { !ignoredContactSources.contains(it.getFullIdentifier()) }
|
||||||
|
.map { it.name }.toMutableList() as ArrayList<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getAllContactSources(): ArrayList<ContactSource> {
|
||||||
|
val sources = ContactsHelper(this).getDeviceContactSources()
|
||||||
|
sources.add(getPrivateContactSource())
|
||||||
|
return sources.toMutableList() as ArrayList<ContactSource>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getPrivateContactSource() = ContactSource(SMT_PRIVATE, SMT_PRIVATE, getString(R.string.phone_storage_hidden))
|
||||||
|
|
||||||
|
fun Context.getSocialActions(id: Int): ArrayList<SocialAction> {
|
||||||
|
val uri = ContactsContract.Data.CONTENT_URI
|
||||||
|
val projection = arrayOf(
|
||||||
|
ContactsContract.Data._ID,
|
||||||
|
ContactsContract.Data.DATA3,
|
||||||
|
ContactsContract.Data.MIMETYPE,
|
||||||
|
ContactsContract.Data.ACCOUNT_TYPE_AND_DATA_SET
|
||||||
|
)
|
||||||
|
|
||||||
|
val socialActions = ArrayList<SocialAction>()
|
||||||
|
var curActionId = 0
|
||||||
|
val selection = "${ContactsContract.Data.RAW_CONTACT_ID} = ?"
|
||||||
|
val selectionArgs = arrayOf(id.toString())
|
||||||
|
queryCursor(uri, projection, selection, selectionArgs, null, true) { cursor ->
|
||||||
|
val mimetype = cursor.getStringValue(ContactsContract.Data.MIMETYPE)
|
||||||
|
val type = when (mimetype) {
|
||||||
|
// WhatsApp
|
||||||
|
"vnd.android.cursor.item/vnd.com.whatsapp.profile" -> SOCIAL_MESSAGE
|
||||||
|
"vnd.android.cursor.item/vnd.com.whatsapp.voip.call" -> SOCIAL_VOICE_CALL
|
||||||
|
"vnd.android.cursor.item/vnd.com.whatsapp.video.call" -> SOCIAL_VIDEO_CALL
|
||||||
|
|
||||||
|
// Viber
|
||||||
|
"vnd.android.cursor.item/vnd.com.viber.voip.viber_number_call" -> SOCIAL_VOICE_CALL
|
||||||
|
"vnd.android.cursor.item/vnd.com.viber.voip.viber_out_call_viber" -> SOCIAL_VOICE_CALL
|
||||||
|
"vnd.android.cursor.item/vnd.com.viber.voip.viber_out_call_none_viber" -> SOCIAL_VOICE_CALL
|
||||||
|
"vnd.android.cursor.item/vnd.com.viber.voip.viber_number_message" -> SOCIAL_MESSAGE
|
||||||
|
|
||||||
|
// Signal
|
||||||
|
"vnd.android.cursor.item/vnd.org.thoughtcrime.securesms.contact" -> SOCIAL_MESSAGE
|
||||||
|
"vnd.android.cursor.item/vnd.org.thoughtcrime.securesms.call" -> SOCIAL_VOICE_CALL
|
||||||
|
|
||||||
|
// Telegram
|
||||||
|
"vnd.android.cursor.item/vnd.org.telegram.messenger.android.call" -> SOCIAL_VOICE_CALL
|
||||||
|
"vnd.android.cursor.item/vnd.org.telegram.messenger.android.call.video" -> SOCIAL_VIDEO_CALL
|
||||||
|
"vnd.android.cursor.item/vnd.org.telegram.messenger.android.profile" -> SOCIAL_MESSAGE
|
||||||
|
|
||||||
|
// Threema
|
||||||
|
"vnd.android.cursor.item/vnd.ch.threema.app.profile" -> SOCIAL_MESSAGE
|
||||||
|
"vnd.android.cursor.item/vnd.ch.threema.app.call" -> SOCIAL_VOICE_CALL
|
||||||
|
else -> return@queryCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
val label = cursor.getStringValue(ContactsContract.Data.DATA3)
|
||||||
|
val realID = cursor.getLongValue(ContactsContract.Data._ID)
|
||||||
|
val packageName = cursor.getStringValue(ContactsContract.Data.ACCOUNT_TYPE_AND_DATA_SET)
|
||||||
|
val socialAction = SocialAction(curActionId++, type, label, mimetype, realID, packageName)
|
||||||
|
socialActions.add(socialAction)
|
||||||
|
}
|
||||||
|
return socialActions
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BaseSimpleActivity.initiateCall(contact: Contact, onStartCallIntent: (phoneNumber: String) -> Unit) {
|
||||||
|
val numbers = contact.phoneNumbers
|
||||||
|
if (numbers.size == 1) {
|
||||||
|
onStartCallIntent(numbers.first().value)
|
||||||
|
} else if (numbers.size > 1) {
|
||||||
|
val primaryNumber = contact.phoneNumbers.find { it.isPrimary }
|
||||||
|
if (primaryNumber != null) {
|
||||||
|
onStartCallIntent(primaryNumber.value)
|
||||||
|
} else {
|
||||||
|
val items = ArrayList<RadioItem>()
|
||||||
|
numbers.forEachIndexed { index, phoneNumber ->
|
||||||
|
items.add(RadioItem(index, "${phoneNumber.value} (${getPhoneNumberTypeText(phoneNumber.type, phoneNumber.label)})", phoneNumber.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioGroupDialog(this, items) {
|
||||||
|
onStartCallIntent(it as String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BaseSimpleActivity.tryInitiateCall(contact: Contact, onStartCallIntent: (phoneNumber: String) -> Unit) {
|
||||||
|
if (baseConfig.showCallConfirmation) {
|
||||||
|
CallConfirmationDialog(this, contact.getNameToDisplay()) {
|
||||||
|
initiateCall(contact, onStartCallIntent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
initiateCall(contact, onStartCallIntent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.isContactBlocked(contact: Contact, callback: (Boolean) -> Unit) {
|
||||||
|
val phoneNumbers = contact.phoneNumbers.map { PhoneNumberUtils.stripSeparators(it.value) }
|
||||||
|
getBlockedNumbersWithContact { blockedNumbersWithContact ->
|
||||||
|
val blockedNumbers = blockedNumbersWithContact.map { it.number }
|
||||||
|
val allNumbersBlocked = phoneNumbers.all { it in blockedNumbers }
|
||||||
|
callback(allNumbersBlocked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.N)
|
||||||
|
fun Context.blockContact(contact: Contact): Boolean {
|
||||||
|
var contactBlocked = true
|
||||||
|
ensureBackgroundThread {
|
||||||
|
contact.phoneNumbers.forEach {
|
||||||
|
val numberBlocked = addBlockedNumber(PhoneNumberUtils.stripSeparators(it.value))
|
||||||
|
contactBlocked = contactBlocked && numberBlocked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contactBlocked
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.N)
|
||||||
|
fun Context.unblockContact(contact: Contact): Boolean {
|
||||||
|
var contactUnblocked = true
|
||||||
|
ensureBackgroundThread {
|
||||||
|
contact.phoneNumbers.forEach {
|
||||||
|
val numberUnblocked = deleteBlockedNumber(PhoneNumberUtils.stripSeparators(it.value))
|
||||||
|
contactUnblocked = contactUnblocked && numberUnblocked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contactUnblocked
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,4 +2,6 @@ plugins {
|
|||||||
alias(libs.plugins.android).apply(false)
|
alias(libs.plugins.android).apply(false)
|
||||||
alias(libs.plugins.kotlinAndroid).apply(false)
|
alias(libs.plugins.kotlinAndroid).apply(false)
|
||||||
alias(libs.plugins.ksp).apply(false)
|
alias(libs.plugins.ksp).apply(false)
|
||||||
|
alias(libs.plugins.kotlinSerialization).apply(false)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,8 @@
|
|||||||
kotlin = "1.9.0"
|
kotlin = "1.9.0"
|
||||||
#KSP
|
#KSP
|
||||||
ksp = "1.9.0-1.0.12"
|
ksp = "1.9.0-1.0.12"
|
||||||
|
kotlinxSerializationJson = "1.5.1"
|
||||||
|
|
||||||
#AndroidX
|
#AndroidX
|
||||||
androidx-swiperefreshlayout = "1.1.0"
|
androidx-swiperefreshlayout = "1.1.0"
|
||||||
#AutoFitTextView
|
#AutoFitTextView
|
||||||
@@ -30,6 +32,8 @@ app-version-versionName = "6.22.7"
|
|||||||
[libraries]
|
[libraries]
|
||||||
#AndroidX
|
#AndroidX
|
||||||
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidx-swiperefreshlayout" }
|
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidx-swiperefreshlayout" }
|
||||||
|
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||||
|
|
||||||
#AutoFitTextView
|
#AutoFitTextView
|
||||||
autofittextview = { module = "me.grantland:autofittextview", version.ref = "autofittextview" }
|
autofittextview = { module = "me.grantland:autofittextview", version.ref = "autofittextview" }
|
||||||
#EzVcard
|
#EzVcard
|
||||||
@@ -51,3 +55,4 @@ room = [
|
|||||||
android = { id = "com.android.application", version.ref = "gradlePlugins-agp" }
|
android = { id = "com.android.application", version.ref = "gradlePlugins-agp" }
|
||||||
kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
||||||
|
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||||
|
Reference in New Issue
Block a user