# Insert contacts into SIM card

This library provides the `SimContactsInsert` API that allows you to create/insert contacts into the
SIM card.

An instance of the `SimContactsInsert` API is obtained by,

```kotlin
val insert = Contacts(context).sim().insert()
```

Note that SIM card inserts will only work if there is a SIM card in the ready state. For more info,
read [SIM card state](./../sim/about-sim-contacts.md#sim-card-state).

## A basic insert

To create/insert a new contact into the SIM card,

```kotlin
val insertResult = Contacts(context)
    .sim()
    .insert()
    .simContact(NewSimContact(name = "Dude", number = "5555555555"))
    .commit()
```

If you need to insert multiple contacts,

```kotlin
val newContact1 = NewSimContact(name = "Dude1", number = "1234567890")
val newContact2 = NewSimContact(name = "Dude2", number = "0987654321")

val insertResult = Contacts(context)
    .sim()
    .insert()
    .simContacts(newContact1, newContact2)
    .commit()
```

## Blank contacts are not allowed

For more info, read about [SIM Contacts](./../sim/about-sim-contacts.md#blanks-are-not-allowed)

## Character limits

For more info, read about [SIM Contacts](./../sim/about-sim-contacts.md#character-limits)

## Executing the insert

To execute the insert,

```kotlin
.commit()
```

### Handling the insert result

The `commit` function returns a `Result`.

To check if all inserts succeeded,

```kotlin
val allInsertsSuccessful = insertResult.isSuccessful
```

To check if a particular insert succeeded,

```kotlin
val firstInsertSuccessful = insertResult.isSuccessful(newContact1)
```

To get all newly created SimContacts, you may use the extensions provided
in `SimContactsInsertResult`,

```kotlin
val simContacts = insertResult.simContacts(contactsApi)
```

To get a particular simContact,

```kotlin
val simContact = insertResult.simContact(contactsApi, newSimContact1)
```

> ⚠️ The `IccProvider` does not yet return the row ID of newly inserted contacts. Look at the "TODO"
> at line 259 of Android's [IccProvider](https://android.googlesource.com/platform/frameworks/opt/telephony/+/51302ef/src/java/com/android/internal/telephony/IccProvider.java#259).
> Therefore, this library's insert API can only support getting the new rows from the result with some
> limitations around duplicate entries (see documentation in `SimContactsInsertResult`).

### Handling insert failure

The insert may fail for a particular SIM contact for various reasons,

```kotlin
insertResult.failureReason(newSimContact1)?.let {
    when (it) {
        NAME_EXCEEDED_MAX_CHAR_LIMIT -> tellUserTheNameIsTooLong()
        NUMBER_EXCEEDED_MAX_CHAR_LIMIT -> tellUserTheNumberIsTooLong()
        NAME_AND_NUMBER_ARE_BLANK -> tellUserTheNameAndNumberCannotBothBeBlank()
        UNKNOWN -> showGenericErrorMessage()
    }
}
```

## Cancelling the insert

To cancel an insert amid execution,

```kotlin
.commit { returnTrueIfInsertShouldBeCancelled() }
```

The `commit` function optionally takes in a function that, if it returns true, will cancel insert
processing as soon as possible. The function is called numerous times during insert processing to
check if processing should stop or continue. This gives you the option to cancel the insert.

For example, to automatically cancel the insert inside a Kotlin coroutine when the coroutine is
cancelled,

```kotlin
launch {
    withContext(coroutineContext) {
        val insertResult = insert.commit { !isActive }
    }
}
```

## Performing the insert and result processing asynchronously

Inserts are executed when the `commit` function is invoked. The work is done in the same thread as
the call-site. This may result in a choppy UI.

To perform the work in a different thread, use the Kotlin coroutine extensions provided in
the `async` module. For more info,
read [Execute work outside of the UI thread using coroutines](./../async/async-execution-coroutines.md).

You may, of course, use other multi-threading libraries or just do it yourself =)

> ℹ️ Extensions for Kotlin Flow and RxJava are also in the project roadmap.

## Performing the insert with permission

Inserts require the `android.permission.WRITE_CONTACTS` permission. If not granted, the insert will
do nothing and return a failed result.

To perform the insert with permission, use the extensions provided in the `permissions` module.
For more info, read [Permissions handling using coroutines](./../permissions/permissions-handling-coroutines.md).

You may, of course, use other permission handling libraries or just do it yourself =)