Skip to content

v0.3.0 - Lots of improvements, with some breaking changes, and bug fixes

Compare
Choose a tag to compare
@vestrel00 vestrel00 released this 01 Jul 01:39
· 55 commits to main since this release

There are quite a bit of improvements and bug fixes in this release. Unfortunately, as a result, there are a handful of breaking changes... Fortunately, migrations are simple and documented 😁

💡 New features

  1. Enhanced API for moving any RawContacts to different Accounts (or null account); MoveRawContactsAcrossAccounts #168, documentation

🐞 Bug fixes

  1. When updating groups, the title is always redacted (replaced with asterisks "*") #281
  2. Null pointer exception in Fields.all (on first use in multi-threaded API usage) #286

🛠️ Improvements

  1. Add display name, account, and options properties to RawContactEntity #268
  2. Support for RawContact IDs in AccountsQuery #276

💣 Improvements with breaking changes

  1. Replace AccountsLocalRawContactsUpdate API with a better one #282
  2. Remove Account restrictions for Group, GroupMembership, Relation, and Event #167
  3. Support setting/removing Contact/RawContact Photos as part of Insert and Update API calls #119
  4. Allow different Accounts for each RawContact in insert APIs #270
  5. Move set Contact/RawContact Options functions to be part of Insert and Update APIs #120
  6. Remove BlankRawContact entity #269
  7. Generalize AccountsRawContactsQuery to RawContactsQuery #271
  8. Move Contact link/unlink extensions to a dedicated API #138

♻️ Dependency upgrades

These should not affect you...

  1. 2023 June Dependency Upgrades (most notably AS Flamingo + AGP 8 + Gradle 8 + JDK 17 + SDK 33 + JitCI -> Circle CI) #274

🧗 Migrating from 0.2.4 -> 0.3.0

Replace AccountsLocalRawContactsUpdate API with a better one #282

PREVIOUSLY, to move local RawContacts (those with null Account), you would use the AccountsLocalRawContactsUpdate API.

val updateResult = Contacts(context)
     .accounts()
     .updateLocalRawContactsAccount()
     .addToAccount(account)
     .localRawContacts(rawContacts)
     .commit()

NOW, the above API has been replaced with MoveRawContactsAcrossAccounts. It is a much more powerful API that allows you to move local and non-local RawContacts across Accounts.

val moveResult = Contacts(context)
     .accounts()
     .move()
     .rawContactsTo(account, rawContacts)
     .commit()

🗒️ Read the new documentation for the full guide!

Remove Account restrictions for Group, GroupMembership, Relation, and Event #167

PREVIOUSLY, the following data kinds were ignored during insert and update operations for local RawContacts (those that are not associated with an Account);

  • GroupMembership
  • Event
  • Relation

This meant that the insert and update APIs would not let you set the values of the above data kinds for local RawContacts... You might have noticed this and thought it was a bug. However, it was intentional 😅

Another artificially imposed "restriction" that existed was that GroupEntity.account was NOT nullable. This meant that the library did not allow you to insert new groups that were not associated with an account. You were also not able to use the GroupsQuery API to fetch only groups that had no account (local groups). Furthermore, groups that were fetched that did have a null account in the database table were assigned a non-null account with the value Account("null", "null) (that is bad).

NOW,

  • the aforementioned data kinds are no longer ignored during insert and update operations for local RawContacts
  • GroupEntity.account is nullable, allowing you to insert local groups
  • GroupsQuery API now supports fetching only local groups
  • Groups that have a null account in the database table are properly assigned a null account value

🗒️ Read the new documentation for the full guide!

Support setting/removing Contact/RawContact Photos as part of Insert and Update API calls #119

PREVIOUSLY, to set /remove the Contact or RawContact photo, you would use one of these extension functions that immediately commits the changes directly into the database. These can only be used for Contact and RawContacts that are already inserted.

[contact|rawContact].setPhoto(
    contactsApi, 
    [photoInputStream|photoBytes|photoBitmap|photoBitmapDrawable]
)
[contact|rawContact].removePhoto(contactsApi)

NOW, the above functions still exist with a different name and parameter types.

[contact|rawContact].setPhotoDirect(
    contactsApi, 
    PhotoData.from([photoInputStream|photoBytes|photoBitmap|photoBitmapDrawable])
)
[contact|rawContact].removePhotoDirect(contactsApi)

More importantly, you are now also able to set/remove Contact and RawContact photos as part of insert and update API calls!

Contacts(context).insert().rawContact { setPhoto(PhotoData.from(...)) }.commit()
Contacts(context)
    .update()
    .contacts(contact.mutableCopy { setPhoto(PhotoData.from(...)) })
    .contacts(contact.mutableCopy { removePhoto() })
    .rawContacts(rawContact.mutableCopy { setPhoto(PhotoData.from(...)) })
    .rawContacts(rawContact.mutableCopy { removePhoto() })
    .commit()

🗒️ Read the new documentation for the full guide!

Allow different Accounts for each RawContact in insert APIs #270

PREVIOUSLY, to set the Account of NewRawContact(s) to be inserted, you would use the forAccount function of the Insert and ProfileInsert APIs,

insert
    .forAccount(account)
    .rawContacts(rawContact)
    .commit()

NOW, the forAccount functions have been removed but you are able to specify the account of each NewRawContact,

rawContact.account = account
insert
    .rawContacts(rawContact)
    .commit()

🗒️ Read the new documentation for the full guide!

Move set Contact/RawContact Options functions to be part of Insert and Update APIs #120

PREVIOUSLY, to get/set Contact/RawContact options, you would use the extension functions provided in contacts.core.util.ContactOptions and contacts.core.util.RawContactOptions,

val contactOptions = contact.options(contactsApi)
val rawContactOptions = rawContact.options(contactsApi)

contact.setOptions(contactsApi, contactOptions.mutableCopy{ ... })
rawContact.options(contactsApi, rawContactOptions{ ... })

The above extension functions read/write directly from the database and blocked the UI thread. Those functions no longer exist.

NOW, you can directly get/set options through the Contact/RawContact entities and read/write APIs;

val contactOptions = contact.options // yes, this also existed prior to this version
val rawContactOptions = rawContact.options

Contacts(context)
    .update()
    .contacts(
        contact.mutableCopy {
            setOptions { ... }
        }
    )
    .rawContacts(
        rawContact.mutableCopy {
            setOptions { ... }
        }
    )
    .commit()

You are now also able to set the options of a new RawContact for insert APIs,

Contacts(context)
    .insert()
    .rawContact {
        setOptions { ... }
    }
    .commit()

🗒️ Read the new documentation for the full guide!

Remove BlankRawContact entity #269

Now that BlankRawContact no longer exists, all you have to do is replace any references you may have to it with references to RawContact.

Generalize AccountsRawContactsQuery to RawContactsQuery #271

PREVIOUSLY, the AccountsRawContactsQuery had a very limited set of functions. Its sole purpose was to provide a way to get RawContacts directly via the BlankRawContact entity. It did not allow you to specify fields to include as it had a predefined set of included fields.

You may have used it like so,

val rawContacts = Contacts(context).accounts().queryRawContacts().find()

NOW, it has been refactored to the more powerful RawContactsQuery,

val rawContacts = Contacts(context).rawContactsQuery().find()

🗒️ Read the new documentation for the full guide!

Move Contact link/unlink extensions to a dedicated API #138

PREVIOUSLY, to link/unlink Contacts, you would use one of these extension functions that immediately commits the changes directly into the database.

contact1.link(contactsApi, contact2, contact3)
contact.unlink(contactsApi)

NOW, the above functions still exist with different names.

contact1.linkDirect(contactsApi, contact2, contact3)
contact.unlinkDirect(contactsApi)

More importantly, you are now also able to link/unlink using new APIs that match the design of all other existing APIs provided in the library!

contactsApi
  .aggregationExceptions()
  .link()
  .contacts(contact1, contact2, contact3)
  .commit()

contactsApi
  .aggregationExceptions()
  .unlink()
  .contact(contact)
  .commit()

The advantage of using the new ContactLink and ContactUnlink APIs is that it allows you to use [link|unlink]WithPermission and commit[WithContext|Async] extensions in the same call =)

🗒️ Read the new documentation for the full guide!

🗒️ Full Changelog

0.2.4...0.3.0

🗣️ Discuss this release

Head on over to the v0.3.0 Release Checklist and leave a comment or some reactions 🙏