Читайте день рождения и имя из контактов Google в Kotlin - PullRequest
0 голосов
/ 29 апреля 2020

Я разрабатываю приложение для хранения информации о событиях, в частности о днях рождения. Интересной функцией будет импортировать каждый день рождения, найденный в контактах Google, и отображать его немедленно. Приложение использует Room DB для хранения контактов в объектах событий (в основном, событие определяется именем, фамилией [необязательно] и датой рождения, а также некоторыми другими необязательными параметрами)

Поскольку я являюсь немного смущен поставщиками контактов (не каждый производитель использует поставщика контактов Google, верно?), и каждый найденный мной ответ был довольно старым и не использует Kotlin, я хотел бы знать, как в основном выполнить эту функцию (расположен в моя основная деятельность, где я могу легко получить доступ к модели представления и ко всему прочему)

  // Import the contacts from Google Contacts
    fun importContacts(): Boolean {
        // No permission. For now, just send an explanation toast
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, getString(R.string.missing_permission), Toast.LENGTH_SHORT).show()
            return false
        }

        // Phase 1: get every contact having at least a name and a birthday
        val contacts = getContacts()

        // Phase 2: convert the extracted data in an Event List, verify duplicates
        val events = mutableListOf<Event>()
        loop@ for (contact in contacts) {
            val splitterName = contact.key.split(",")
            var name: String
            var surname = ""
            var date = LocalDate.of(1970,1,1)
            when (splitterName.size) {
                // Not considering surname only contacts
                1 -> name = splitterName[0].trim()
                2 -> {
                    name = splitterName[1].trim()
                    surname = splitterName[0].trim()
                }
                else -> continue@loop
            }
            try { date = LocalDate.parse(contact.value) }
            catch (e: Exception) { continue }
            val event = Event(id = 0, name = name, surname = surname, originalDate = date)

            // Check if the event is duplicate with a query
            if (!homeViewModel.checkExisting(it.key, it.value) == 0) events.add(event)

        }

        // Phase 3: insert the remaining events in the db
        events.forEach {
            homeViewModel.insert(it)
        }

        return true
    }

    // Get the contacts and save them in a list
    private fun getContacts(): Map<String, String> {
        val nameBirth = mutableMapOf<String, String>()
        val resolver: ContentResolver = contentResolver;
        val cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null)

        if (cursor != null) {
            if (cursor.count > 0) {
                while (cursor.moveToNext()) {
                    val name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_ALTERNATIVE))
                    val birth = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.))
                    nameBirth[name] = "???"
                }
            }
        }
        cursor?.close()
        return nameBirth
    }

Хотя я могу легко писать фазы 2 и 3, я довольно озадачен лучшим способом справиться с первой фазой. Вы можете предположить, что у меня уже есть разрешение на контакты, и все, что мне нужно, это список имен, фамилий и дат, которые я могу использовать для создания объектов.


РЕДАКТИРОВАТЬ: так я изменил приведенный выше код с моим прогрессом. Теперь я могу взять имена, разделить имена по имени и фамилии, проверить дубликаты и вставить контакт в мою базу данных. Осталось только извлечь день рождения и управлять тем, что год не может быть указан. Я использую объект LocalDate, чтобы сохранить дату, как вы видите.

1 Ответ

0 голосов
/ 30 апреля 2020
// Import the contacts from Google Contacts
fun importContacts(): Boolean {
    // No permission. For now, just send an explanation toast
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
        Toast.makeText(this, getString(R.string.missing_permission), Toast.LENGTH_SHORT).show()
        return false
    }

    // Phase 1: get every contact having at least a name and a birthday
    val contacts = getContacts()

    // Phase 2: convert the extracted data in an Event List, verify duplicates
    val events = mutableListOf<Event>()
    loop@ for (contact in contacts) {
        // Take the name and split it to separate name and surname
        val splitterName = contact.value[0].split(",")
        var name: String
        var surname = ""
        var date = LocalDate.of(1970,1,1)
        when (splitterName.size) {
            // Not considering surname only contacts, but considering name only
            1 -> name = splitterName[0].trim()
            2 -> {
                name = splitterName[1].trim()
                surname = splitterName[0].trim()
            }
            else -> continue@loop
        }

        try {
            // Missing year, put 2020 as a placeholder
            var parseDate = contact.value[1]
            if (contact.value[1].length < 8) parseDate = contact.value[1].replaceFirst("-", "2020")
            date = LocalDate.parse(parseDate)
        }
        catch (e: Exception) { continue }
        val event = Event(id = 0, name = name, surname = surname, originalDate = date)

        // The duplicate check is performed at entity level
        events.add(event)
    }

    // Phase 3: insert the remaining events in the db
    events.forEach {
        homeViewModel.insert(it)
    }

    return true
}

// Get the contacts and save them in a map
private fun getContacts(): Map<String, List<String>> {
    val nameBirth = mutableMapOf<String, List<String>>()

    // Retrieve name and id
    val resolver: ContentResolver = contentResolver
    val cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null)
    if (cursor != null) {
        if (cursor.count > 0) {
            while (cursor.moveToNext()) {
                val id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))
                val name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_ALTERNATIVE))
                // Retrieve the birthday
                val bd = contentResolver
                val bdc: Cursor? = bd.query(ContactsContract.Data.CONTENT_URI, arrayOf(ContactsContract.CommonDataKinds.Event.DATA),
                    ContactsContract.Data.CONTACT_ID + " = " + id + " AND " + ContactsContract.Data.MIMETYPE + " = '" +
                            ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE + "' AND " + ContactsContract.CommonDataKinds.Event.TYPE +
                            " = " + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY, null, ContactsContract.Data.DISPLAY_NAME
                )

                if (bdc != null) {
                    if (bdc.count > 0) {
                        while (bdc.moveToNext()) {
                            // Using a list as key will prevent collisions on same name
                            val birthday: String = bdc.getString(0)
                            val person = listOf<String>(name, birthday)
                            nameBirth[id] = person
                        }
                    }
                    bdc.close()
                }
            }
        }
    }
    cursor?.close()
    return nameBirth
}

Так что это в основном функция, которую я искал. Я уверен, что это можно сделать лучше, но у меня не было конкретных ссылок в Kotlin. Он берет контакты, проверяет их имя и день рождения и управляет делом пропавшего года. Кроме того, я просто управляю делом «только имя», но не делом «только фамилия».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...