Merge pull request #1536 from Naveen3Singh/vcf_exporter
Add VcfExporter and some reusable Contact classes from Simple contacts
This commit is contained in:
commit
ba8ba0fd67
11 changed files with 520 additions and 22 deletions
|
@ -1,7 +1,7 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: "com.android.library"
|
||||
apply plugin: "kotlin-android"
|
||||
apply plugin: "kotlin-android-extensions"
|
||||
apply plugin: "kotlin-kapt"
|
||||
|
||||
android {
|
||||
compileSdkVersion propCompileSdkVersion
|
||||
|
@ -14,35 +14,40 @@ android {
|
|||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
consumerProguardFiles 'proguard-rules.pro'
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
consumerProguardFiles "proguard-rules.pro"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
main.java.srcDirs += "src/main/kotlin"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
|
||||
implementation "com.andrognito.patternlockview:patternlockview:1.0.0"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||
implementation "androidx.documentfile:documentfile:1.0.1"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation "androidx.exifinterface:exifinterface:1.3.3"
|
||||
implementation "androidx.biometric:biometric-ktx:1.2.0-alpha04"
|
||||
implementation "com.googlecode.ez-vcard:ez-vcard:0.11.3"
|
||||
|
||||
api 'joda-time:joda-time:2.11.0'
|
||||
api 'com.github.tibbi:RecyclerView-FastScroller:5a95285b1f'
|
||||
api 'com.github.tibbi:reprint:2cb206415d'
|
||||
api 'androidx.core:core-ktx:1.8.0'
|
||||
api 'androidx.appcompat:appcompat:1.5.0'
|
||||
api 'com.google.android.material:material:1.6.1'
|
||||
api 'com.google.code.gson:gson:2.9.1'
|
||||
api 'com.duolingo.open:rtl-viewpager:2.0.0'
|
||||
api "joda-time:joda-time:2.11.0"
|
||||
api "com.github.tibbi:RecyclerView-FastScroller:5a95285b1f"
|
||||
api "com.github.tibbi:reprint:2cb206415d"
|
||||
api "androidx.core:core-ktx:1.8.0"
|
||||
api "androidx.appcompat:appcompat:1.5.0"
|
||||
api "com.google.android.material:material:1.6.1"
|
||||
api "com.google.code.gson:gson:2.9.1"
|
||||
api "com.duolingo.open:rtl-viewpager:2.0.0"
|
||||
|
||||
api 'com.github.bumptech.glide:glide:4.13.2'
|
||||
kapt 'com.github.bumptech.glide:compiler:4.13.2'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
|
||||
api "com.github.bumptech.glide:glide:4.13.2"
|
||||
kapt "com.github.bumptech.glide:compiler:4.13.2"
|
||||
annotationProcessor "com.github.bumptech.glide:compiler:4.13.2"
|
||||
|
||||
api "androidx.room:room-runtime:2.4.3"
|
||||
kapt "androidx.room:room-compiler:2.4.3"
|
||||
annotationProcessor "androidx.room:room-compiler:2.4.3"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.simplemobiletools.commons.extensions
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
fun Bitmap.getByteArray(): ByteArray {
|
||||
var baos: ByteArrayOutputStream? = null
|
||||
try {
|
||||
baos = ByteArrayOutputStream()
|
||||
compress(Bitmap.CompressFormat.JPEG, 80, baos)
|
||||
return baos.toByteArray()
|
||||
} finally {
|
||||
baos?.close()
|
||||
}
|
||||
}
|
|
@ -38,6 +38,8 @@ const val KEY_PHONE = "phone"
|
|||
const val KEY_MAILTO = "mailto"
|
||||
const val CONTACT_ID = "contact_id"
|
||||
const val IS_PRIVATE = "is_private"
|
||||
const val SMT_PRIVATE = "smt_private" // used at the contact source of local contacts hidden from other apps
|
||||
const val FIRST_GROUP_ID = 10000L
|
||||
const val MD5 = "MD5"
|
||||
const val SHORT_ANIMATION_DURATION = 150L
|
||||
val DARK_GREY = 0xFF333333.toInt()
|
||||
|
@ -163,6 +165,24 @@ const val FAVORITES = "favorites"
|
|||
const val SHOW_CALL_CONFIRMATION = "show_call_confirmation"
|
||||
internal const val COLOR_PICKER_RECENT_COLORS = "color_picker_recent_colors"
|
||||
|
||||
// phone number/email types
|
||||
const val CELL = "CELL"
|
||||
const val WORK = "WORK"
|
||||
const val HOME = "HOME"
|
||||
const val OTHER = "OTHER"
|
||||
const val PREF = "PREF"
|
||||
const val MAIN = "MAIN"
|
||||
const val FAX = "FAX"
|
||||
const val WORK_FAX = "WORK;FAX"
|
||||
const val HOME_FAX = "HOME;FAX"
|
||||
const val PAGER = "PAGER"
|
||||
const val MOBILE = "MOBILE"
|
||||
|
||||
// IMs not supported by Ez-vcard
|
||||
const val HANGOUTS = "Hangouts"
|
||||
const val QQ = "QQ"
|
||||
const val JABBER = "Jabber"
|
||||
|
||||
// licenses
|
||||
internal const val LICENSE_KOTLIN = 1L
|
||||
const val LICENSE_SUBSAMPLING = 2L
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
package com.simplemobiletools.commons.helpers
|
||||
|
||||
import android.net.Uri
|
||||
import android.provider.ContactsContract.CommonDataKinds
|
||||
import android.provider.ContactsContract.CommonDataKinds.Event
|
||||
import android.provider.ContactsContract.CommonDataKinds.Im
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal
|
||||
import android.provider.MediaStore
|
||||
import com.simplemobiletools.commons.R
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.extensions.getByteArray
|
||||
import com.simplemobiletools.commons.extensions.getDateTimeFromDateString
|
||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||
import com.simplemobiletools.commons.extensions.toast
|
||||
import com.simplemobiletools.commons.models.contacts.Contact
|
||||
import ezvcard.Ezvcard
|
||||
import ezvcard.VCard
|
||||
import ezvcard.VCardVersion
|
||||
import ezvcard.parameter.ImageType
|
||||
import ezvcard.property.*
|
||||
import java.io.OutputStream
|
||||
import java.util.*
|
||||
|
||||
class VcfExporter {
|
||||
enum class ExportResult {
|
||||
EXPORT_FAIL, EXPORT_OK, EXPORT_PARTIAL
|
||||
}
|
||||
|
||||
private var contactsExported = 0
|
||||
private var contactsFailed = 0
|
||||
|
||||
fun exportContacts(
|
||||
activity: BaseSimpleActivity,
|
||||
outputStream: OutputStream?,
|
||||
contacts: ArrayList<Contact>,
|
||||
showExportingToast: Boolean,
|
||||
callback: (result: ExportResult) -> Unit
|
||||
) {
|
||||
try {
|
||||
if (outputStream == null) {
|
||||
callback(ExportResult.EXPORT_FAIL)
|
||||
return
|
||||
}
|
||||
|
||||
if (showExportingToast) {
|
||||
activity.toast(R.string.exporting)
|
||||
}
|
||||
|
||||
val cards = ArrayList<VCard>()
|
||||
for (contact in contacts) {
|
||||
val card = VCard()
|
||||
|
||||
val formattedName = arrayOf(contact.prefix, contact.firstName, contact.middleName, contact.surname, contact.suffix)
|
||||
.filter { it.isNotEmpty() }
|
||||
.joinToString(separator = " ")
|
||||
card.formattedName = FormattedName(formattedName)
|
||||
|
||||
StructuredName().apply {
|
||||
prefixes.add(contact.prefix)
|
||||
given = contact.firstName
|
||||
additionalNames.add(contact.middleName)
|
||||
family = contact.surname
|
||||
suffixes.add(contact.suffix)
|
||||
card.structuredName = this
|
||||
}
|
||||
|
||||
if (contact.nickname.isNotEmpty()) {
|
||||
card.setNickname(contact.nickname)
|
||||
}
|
||||
|
||||
contact.phoneNumbers.forEach {
|
||||
val phoneNumber = Telephone(it.value)
|
||||
phoneNumber.parameters.addType(getPhoneNumberTypeLabel(it.type, it.label))
|
||||
card.addTelephoneNumber(phoneNumber)
|
||||
}
|
||||
|
||||
contact.emails.forEach {
|
||||
val email = Email(it.value)
|
||||
email.parameters.addType(getEmailTypeLabel(it.type, it.label))
|
||||
card.addEmail(email)
|
||||
}
|
||||
|
||||
contact.events.forEach { event ->
|
||||
if (event.type == Event.TYPE_ANNIVERSARY || event.type == Event.TYPE_BIRTHDAY) {
|
||||
val dateTime = event.value.getDateTimeFromDateString(false)
|
||||
Calendar.getInstance().apply {
|
||||
clear()
|
||||
if (event.value.startsWith("--")) {
|
||||
set(Calendar.YEAR, 1900)
|
||||
} else {
|
||||
set(Calendar.YEAR, dateTime.year)
|
||||
|
||||
}
|
||||
set(Calendar.MONTH, dateTime.monthOfYear - 1)
|
||||
set(Calendar.DAY_OF_MONTH, dateTime.dayOfMonth)
|
||||
if (event.type == Event.TYPE_BIRTHDAY) {
|
||||
card.birthdays.add(Birthday(time))
|
||||
} else {
|
||||
card.anniversaries.add(Anniversary(time))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contact.addresses.forEach {
|
||||
val address = Address()
|
||||
address.streetAddress = it.value
|
||||
address.parameters.addType(getAddressTypeLabel(it.type, it.label))
|
||||
card.addAddress(address)
|
||||
}
|
||||
|
||||
contact.IMs.forEach {
|
||||
val impp = when (it.type) {
|
||||
Im.PROTOCOL_AIM -> Impp.aim(it.value)
|
||||
Im.PROTOCOL_YAHOO -> Impp.yahoo(it.value)
|
||||
Im.PROTOCOL_MSN -> Impp.msn(it.value)
|
||||
Im.PROTOCOL_ICQ -> Impp.icq(it.value)
|
||||
Im.PROTOCOL_SKYPE -> Impp.skype(it.value)
|
||||
Im.PROTOCOL_GOOGLE_TALK -> Impp(HANGOUTS, it.value)
|
||||
Im.PROTOCOL_QQ -> Impp(QQ, it.value)
|
||||
Im.PROTOCOL_JABBER -> Impp(JABBER, it.value)
|
||||
else -> Impp(it.label, it.value)
|
||||
}
|
||||
|
||||
card.addImpp(impp)
|
||||
}
|
||||
|
||||
if (contact.notes.isNotEmpty()) {
|
||||
card.addNote(contact.notes)
|
||||
}
|
||||
|
||||
if (contact.organization.isNotEmpty()) {
|
||||
val organization = Organization()
|
||||
organization.values.add(contact.organization.company)
|
||||
card.organization = organization
|
||||
card.titles.add(Title(contact.organization.jobPosition))
|
||||
}
|
||||
|
||||
contact.websites.forEach {
|
||||
card.addUrl(it)
|
||||
}
|
||||
|
||||
if (contact.thumbnailUri.isNotEmpty()) {
|
||||
val photoByteArray = MediaStore.Images.Media.getBitmap(activity.contentResolver, Uri.parse(contact.thumbnailUri)).getByteArray()
|
||||
val photo = Photo(photoByteArray, ImageType.JPEG)
|
||||
card.addPhoto(photo)
|
||||
}
|
||||
|
||||
if (contact.groups.isNotEmpty()) {
|
||||
val groupList = Categories()
|
||||
contact.groups.forEach {
|
||||
groupList.values.add(it.title)
|
||||
}
|
||||
|
||||
card.categories = groupList
|
||||
}
|
||||
|
||||
cards.add(card)
|
||||
contactsExported++
|
||||
}
|
||||
|
||||
Ezvcard.write(cards).version(VCardVersion.V4_0).go(outputStream)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
}
|
||||
|
||||
callback(
|
||||
when {
|
||||
contactsExported == 0 -> ExportResult.EXPORT_FAIL
|
||||
contactsFailed > 0 -> ExportResult.EXPORT_PARTIAL
|
||||
else -> ExportResult.EXPORT_OK
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun getPhoneNumberTypeLabel(type: Int, label: String) = when (type) {
|
||||
Phone.TYPE_MOBILE -> CELL
|
||||
Phone.TYPE_HOME -> HOME
|
||||
Phone.TYPE_WORK -> WORK
|
||||
Phone.TYPE_MAIN -> PREF
|
||||
Phone.TYPE_FAX_WORK -> WORK_FAX
|
||||
Phone.TYPE_FAX_HOME -> HOME_FAX
|
||||
Phone.TYPE_PAGER -> PAGER
|
||||
Phone.TYPE_OTHER -> OTHER
|
||||
else -> label
|
||||
}
|
||||
|
||||
private fun getEmailTypeLabel(type: Int, label: String) = when (type) {
|
||||
CommonDataKinds.Email.TYPE_HOME -> HOME
|
||||
CommonDataKinds.Email.TYPE_WORK -> WORK
|
||||
CommonDataKinds.Email.TYPE_MOBILE -> MOBILE
|
||||
CommonDataKinds.Email.TYPE_OTHER -> OTHER
|
||||
else -> label
|
||||
}
|
||||
|
||||
private fun getAddressTypeLabel(type: Int, label: String) = when (type) {
|
||||
StructuredPostal.TYPE_HOME -> HOME
|
||||
StructuredPostal.TYPE_WORK -> WORK
|
||||
StructuredPostal.TYPE_OTHER -> OTHER
|
||||
else -> label
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package com.simplemobiletools.commons.models.contacts
|
||||
|
||||
data class Address(var value: String, var type: Int, var label: String)
|
|
@ -0,0 +1,214 @@
|
|||
package com.simplemobiletools.commons.models.contacts
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.telephony.PhoneNumberUtils
|
||||
import com.simplemobiletools.commons.extensions.normalizePhoneNumber
|
||||
import com.simplemobiletools.commons.extensions.normalizeString
|
||||
import com.simplemobiletools.commons.helpers.*
|
||||
import com.simplemobiletools.commons.models.PhoneNumber
|
||||
|
||||
data class Contact(
|
||||
var id: Int,
|
||||
var prefix: String,
|
||||
var firstName: String,
|
||||
var middleName: String,
|
||||
var surname: String,
|
||||
var suffix: String,
|
||||
var nickname: String,
|
||||
var photoUri: String,
|
||||
var phoneNumbers: ArrayList<PhoneNumber>,
|
||||
var emails: ArrayList<Email>,
|
||||
var addresses: ArrayList<Address>,
|
||||
var events: ArrayList<Event>,
|
||||
var source: String,
|
||||
var starred: Int,
|
||||
var contactId: Int,
|
||||
var thumbnailUri: String,
|
||||
var photo: Bitmap?,
|
||||
var notes: String,
|
||||
var groups: ArrayList<Group>,
|
||||
var organization: Organization,
|
||||
var websites: ArrayList<String>,
|
||||
var IMs: ArrayList<IM>,
|
||||
var mimetype: String,
|
||||
var ringtone: String?
|
||||
) : Comparable<Contact> {
|
||||
companion object {
|
||||
var sorting = 0
|
||||
var startWithSurname = false
|
||||
}
|
||||
|
||||
override fun compareTo(other: Contact): Int {
|
||||
var result = when {
|
||||
sorting and SORT_BY_FIRST_NAME != 0 -> {
|
||||
val firstString = firstName.normalizeString()
|
||||
val secondString = other.firstName.normalizeString()
|
||||
compareUsingStrings(firstString, secondString, other)
|
||||
}
|
||||
sorting and SORT_BY_MIDDLE_NAME != 0 -> {
|
||||
val firstString = middleName.normalizeString()
|
||||
val secondString = other.middleName.normalizeString()
|
||||
compareUsingStrings(firstString, secondString, other)
|
||||
}
|
||||
sorting and SORT_BY_SURNAME != 0 -> {
|
||||
val firstString = surname.normalizeString()
|
||||
val secondString = other.surname.normalizeString()
|
||||
compareUsingStrings(firstString, secondString, other)
|
||||
}
|
||||
sorting and SORT_BY_FULL_NAME != 0 -> {
|
||||
val firstString = getNameToDisplay().normalizeString()
|
||||
val secondString = other.getNameToDisplay().normalizeString()
|
||||
compareUsingStrings(firstString, secondString, other)
|
||||
}
|
||||
else -> compareUsingIds(other)
|
||||
}
|
||||
|
||||
if (sorting and SORT_DESCENDING != 0) {
|
||||
result *= -1
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun compareUsingStrings(firstString: String, secondString: String, other: Contact): Int {
|
||||
var firstValue = firstString
|
||||
var secondValue = secondString
|
||||
|
||||
if (firstValue.isEmpty() && firstName.isEmpty() && middleName.isEmpty() && surname.isEmpty()) {
|
||||
val fullCompany = getFullCompany()
|
||||
if (fullCompany.isNotEmpty()) {
|
||||
firstValue = fullCompany.normalizeString()
|
||||
} else if (emails.isNotEmpty()) {
|
||||
firstValue = emails.first().value
|
||||
}
|
||||
}
|
||||
|
||||
if (secondValue.isEmpty() && other.firstName.isEmpty() && other.middleName.isEmpty() && other.surname.isEmpty()) {
|
||||
val otherFullCompany = other.getFullCompany()
|
||||
if (otherFullCompany.isNotEmpty()) {
|
||||
secondValue = otherFullCompany.normalizeString()
|
||||
} else if (other.emails.isNotEmpty()) {
|
||||
secondValue = other.emails.first().value
|
||||
}
|
||||
}
|
||||
|
||||
return if (firstValue.firstOrNull()?.isLetter() == true && secondValue.firstOrNull()?.isLetter() == false) {
|
||||
-1
|
||||
} else if (firstValue.firstOrNull()?.isLetter() == false && secondValue.firstOrNull()?.isLetter() == true) {
|
||||
1
|
||||
} else {
|
||||
if (firstValue.isEmpty() && secondValue.isNotEmpty()) {
|
||||
1
|
||||
} else if (firstValue.isNotEmpty() && secondValue.isEmpty()) {
|
||||
-1
|
||||
} else {
|
||||
if (firstValue.equals(secondValue, ignoreCase = true)) {
|
||||
getNameToDisplay().compareTo(other.getNameToDisplay(), true)
|
||||
} else {
|
||||
firstValue.compareTo(secondValue, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun compareUsingIds(other: Contact): Int {
|
||||
val firstId = id
|
||||
val secondId = other.id
|
||||
return firstId.compareTo(secondId)
|
||||
}
|
||||
|
||||
fun getBubbleText() = when {
|
||||
sorting and SORT_BY_FIRST_NAME != 0 -> firstName
|
||||
sorting and SORT_BY_MIDDLE_NAME != 0 -> middleName
|
||||
else -> surname
|
||||
}
|
||||
|
||||
fun getNameToDisplay(): String {
|
||||
val firstMiddle = "$firstName $middleName".trim()
|
||||
val firstPart = if (startWithSurname) {
|
||||
if (surname.isNotEmpty() && firstMiddle.isNotEmpty()) {
|
||||
"$surname,"
|
||||
} else {
|
||||
surname
|
||||
}
|
||||
} else {
|
||||
firstMiddle
|
||||
}
|
||||
val lastPart = if (startWithSurname) firstMiddle else surname
|
||||
val suffixComma = if (suffix.isEmpty()) "" else ", $suffix"
|
||||
val fullName = "$prefix $firstPart $lastPart$suffixComma".trim()
|
||||
return if (fullName.isEmpty()) {
|
||||
if (organization.isNotEmpty()) {
|
||||
getFullCompany()
|
||||
} else {
|
||||
emails.firstOrNull()?.value?.trim() ?: ""
|
||||
}
|
||||
} else {
|
||||
fullName
|
||||
}
|
||||
}
|
||||
|
||||
// photos stored locally always have different hashcodes. Avoid constantly refreshing the contact lists as the app thinks something changed.
|
||||
fun getHashWithoutPrivatePhoto(): Int {
|
||||
val photoToUse = if (isPrivate()) null else photo
|
||||
return copy(photo = photoToUse).hashCode()
|
||||
}
|
||||
|
||||
fun getStringToCompare(): String {
|
||||
val photoToUse = if (isPrivate()) null else photo
|
||||
return copy(
|
||||
id = 0,
|
||||
prefix = "",
|
||||
firstName = getNameToDisplay().toLowerCase(),
|
||||
middleName = "",
|
||||
surname = "",
|
||||
suffix = "",
|
||||
nickname = "",
|
||||
photoUri = "",
|
||||
phoneNumbers = ArrayList(),
|
||||
emails = ArrayList(),
|
||||
events = ArrayList(),
|
||||
source = "",
|
||||
addresses = ArrayList(),
|
||||
starred = 0,
|
||||
contactId = 0,
|
||||
thumbnailUri = "",
|
||||
photo = photoToUse,
|
||||
notes = "",
|
||||
groups = ArrayList(),
|
||||
websites = ArrayList(),
|
||||
organization = Organization("", ""),
|
||||
IMs = ArrayList(),
|
||||
ringtone = ""
|
||||
).toString()
|
||||
}
|
||||
|
||||
fun getHashToCompare() = getStringToCompare().hashCode()
|
||||
|
||||
fun getFullCompany(): String {
|
||||
var fullOrganization = if (organization.company.isEmpty()) "" else "${organization.company}, "
|
||||
fullOrganization += organization.jobPosition
|
||||
return fullOrganization.trim().trimEnd(',')
|
||||
}
|
||||
|
||||
fun isABusinessContact() =
|
||||
prefix.isEmpty() && firstName.isEmpty() && middleName.isEmpty() && surname.isEmpty() && suffix.isEmpty() && organization.isNotEmpty()
|
||||
|
||||
fun doesContainPhoneNumber(text: String, convertLetters: Boolean): Boolean {
|
||||
return if (text.isNotEmpty()) {
|
||||
val normalizedText = if (convertLetters) text.normalizePhoneNumber() else text
|
||||
phoneNumbers.any {
|
||||
PhoneNumberUtils.compare(it.normalizedNumber, normalizedText) ||
|
||||
it.value.contains(text) ||
|
||||
it.normalizedNumber.contains(normalizedText) ||
|
||||
it.value.normalizePhoneNumber().contains(normalizedText)
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun isPrivate() = source == SMT_PRIVATE
|
||||
|
||||
fun getSignatureKey() = if (photoUri.isNotEmpty()) photoUri else hashCode()
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package com.simplemobiletools.commons.models.contacts
|
||||
|
||||
data class Email(var value: String, var type: Int, var label: String)
|
|
@ -0,0 +1,3 @@
|
|||
package com.simplemobiletools.commons.models.contacts
|
||||
|
||||
data class Event(var value: String, var type: Int)
|
|
@ -0,0 +1,22 @@
|
|||
package com.simplemobiletools.commons.models.contacts
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import com.simplemobiletools.commons.helpers.FIRST_GROUP_ID
|
||||
import java.io.Serializable
|
||||
|
||||
@Entity(tableName = "groups", indices = [(Index(value = ["id"], unique = true))])
|
||||
data class Group(
|
||||
@PrimaryKey(autoGenerate = true) var id: Long?,
|
||||
@ColumnInfo(name = "title") var title: String,
|
||||
@ColumnInfo(name = "contacts_count") var contactsCount: Int = 0
|
||||
) : Serializable {
|
||||
|
||||
fun addContact() = contactsCount++
|
||||
|
||||
fun getBubbleText() = title
|
||||
|
||||
fun isPrivateSecretGroup() = id ?: 0 >= FIRST_GROUP_ID
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package com.simplemobiletools.commons.models.contacts
|
||||
|
||||
data class IM(var value: String, var type: Int, var label: String)
|
|
@ -0,0 +1,7 @@
|
|||
package com.simplemobiletools.commons.models.contacts
|
||||
|
||||
data class Organization(var company: String, var jobPosition: String) {
|
||||
fun isEmpty() = company.isEmpty() && jobPosition.isEmpty()
|
||||
|
||||
fun isNotEmpty() = !isEmpty()
|
||||
}
|
Loading…
Reference in a new issue