Releases: vestrel00/contacts-android
v0.4.0 - New APIs, a minor bugfix, and some deprecations plus a breaking change due to big build/dependency updates
It's been almost a year since the last release. How time flies when life and work gets busy 😅 I'm super hyped to have found some time to get some work done on this precious library 🔥
The main intent with this release was to get the build and dependencies up-to-date so this library does not get left behind in the dust with the fast pace of tech. We are now once again using the cutting-edge versions of AGP, KGP, Gradle, target/compileSdk, coroutines, tedpermissions, mkdocs, and mkdocs material 😁
Aside from that, there's some new features, a minor bugfix, and deprecations and breaking changes that resulted from the big build/dep updates.
⚠️ Proper semantic versioning is not being followed prior to version 1.0.0. This means that minor version bumps may contain breaking changes. More context in #284 (comment)
💡 New features & improvements
- Dedicated API for querying contacts using lookup keys #364, documentation
- Allow overriding common (builtin) data kinds via custom data integration #344, documentation
- Support multiple Notes per RawContact #343, documentation
🐞 Bug fixes
ContactRefresh
util may return null if local contact lookup key changes due to primary display name source update #365
🗝️ Deprecations
- Deprecate Im entity, fields, and related functions (deprecated in Android API 35) #361
- Deprecate SipAddress entity, fields, and related functions (deprecated in Android API 35) #362
💣 Breaking changes
- API's data class' 'copy' methods no longer have public visibility #358
♻️ Build/Dependency updates
- December 2024 Build & Dependency Updates #356
- AGP 8.7.3
- KGP 2.1.0
- Gradle 8.9
- target/compileSdk 35
- coroutines 1.10.1
- tedpermissions 3.4.2
- mkdocs 1.6.1
- mkdocs material 9.5.41
🧗 Migrating from 0.3.2
-> 0.4.0
API's data class' 'copy' methods no longer have public visibility #358
You should not be affected by this, at least that is my hope 🤞
However, for those of you that have been using the copy
method of some data classes such as Contact
, MutableContact
, RawContact
, MutableRawContact
, Address
, MutableAddress
, Email
, MutableEmail
, Phone
, MutablePhone
, etc... you will no longer be allowed to do that 😅
There is no actual "migration guide". You simply cannot do it anymore. The API has always been designed for this to be the case. Vandolf apologizes if this was not made clear anywhere 🙇. It was simply not strictly enforceable at the language level prior to Kotlin version 2. If you want more context, read the Side note section of #358 🙏
It is recommended to rethink your approach to using this API. You should not need to or be doing it (using copy
method).
If you believe that the API should provide a copy
method for certain data classes with internal constructors, feel free to start a discussion.
🗒️ Full Changelog
🗣️ Discuss this release
Head on over to the v0.4.0 Release Checklist and leave a comment and/or some reactions 🙏 😄
v0.3.2 - New features for disabling validation checks in read/write APIs, improvements for Insert API, bug fixes, and a small breaking change
This release contains functions that give you more control over Account, Group, and Include field validation checks in read/write APIs. Apart from that, this comes with related improvements and some bug fixes. There's a minor breaking change that might affect you if you have created your own custom data.
💡 New features
- Implement a new
Insert
API function (commitInChunks
) that allows users to insert large numbers of new RawContacts much faster thancommit
#329, documentation - Add option to disable Account validation checks in
Insert
andProfileInsert
APIs #318, documentation - Add option to disable Account validation checks in
MoveRawContactsAcrossAccounts
API #319, documentation - Add option to disable GroupMembership validation checks in
Insert
andProfileInsert
APIs #320, documentation - Add option to disable included field validation checks in all insert, update, and query APIs #321, documentation
🛠️ Improvements
- The
Insert
API now only queries Groups internally at most once regardless of the quantity of RawContacts being inserted #330 - The
Insert
API now only queries Accounts internally at most once regardless of the quantity of RawContacts being inserted #332 - The
Insert
API now skips processing GroupMemberships of RawContacts that specified no GroupMemberships #331 - The
Insert
API no longer adds an update Options operation for RawContacts that has null Options #333 - Allow
SimContactsInsert
andSimContactsUpdate
to be cancelled during calculation of max character limits #327
🐞 Bug fixes
Insert
API includesRawContactsFields
(AccountName, AccountType, SourceId) even when not included #325AccountQuery
API returns all available/visible accounts ifandroid.permission.GET_ACCOUNTS
is NOT explicitly granted, regardless of values passed towithTypes
#338
💣 Breaking changes
- Included custom data field sets are now nullable #324
Refactors
- Refactor
Contacts.insertSimContact
function inSimContactsInsert.kt
from public to internal #328
🧗 Migrating from 0.3.1
-> 0.3.2
Included custom data field sets are now nullable #324
Fix compile errors by making Set<AbstractCustomDataField>
nullable -> Set<AbstractCustomDataField>?
For example, change this...
internal class HandleNameMapperFactory {
override fun create(
... includeFields: Set<HandleNameField>
) = HandleNameMapper(HandleNameDataCursor(cursor, includeFields))
}
to this...
internal class HandleNameMapperFactory {
override fun create(
... includeFields: Set<HandleNameField>?
) = HandleNameMapper(HandleNameDataCursor(cursor, includeFields))
}
🗒️ Full Changelog
🗣️ Discuss this release
Head on over to the v0.3.2 Release Checklist and leave a comment and/or some reactions 🙏 😄
v0.3.1 - New features for sync adapter use cases (SOURCE_ID, Data IS_READ_ONLY, CALLER_IS_SYNC_ADAPTER), bug fixes, improvements, and some breaking changes
There's a LOT of new useful stuff here for folks interested in using this library for sync adapter use cases! Thanks to @marrale for starting these discussions (which led to the addition of a bunch of useful new stuff);
I was not planning for these features to be added to the library but I do see value in them, especially for folks needing to implement a sync adapter.
Apart from that, there is also a handful of bug fixes, improvements, and tiny bit of breaking changes (with migration guide).
💡 New features
- Add support for
ContactsContract.RawContacts.SOURCE_ID
#300, documentation - Add support for
ContactsContract.Groups.SOURCE_ID
#303, documentation - Add extensions for getting all data kinds of a Contact or RawContact as a list #312, documentation
- Support setting
ContactsContract.DataColumns.IS_READ_ONLY
when inserting anyNewDataEntity
(e.g. name, email, phone, etc) #306, documentation - Add extensions for checking the value of
ContactsContract.DataColumns.IS_READ_ONLY
for anyExistingDataEntity
#307, documentation - Support setting
ContactsContract.CALLER_IS_SYNCADAPTER
in all CRUD APIs #308, documentation
🐞 Bug fixes
- ExistingContactEntity.setPhotoDirect fails when there is no previous photo #289
- Potential ArrayIndexOutOfBoundsException when querying contacts (and Fields.Event.Date is included) #291
- Query APIs do not return local contacts in Xiaomi devices when passing null to accounts functions #296
AccountsQuery
API returns Accounts with no sync adapters for Contacts #298ProfileUpdate
API fails when Contact is provided but not RawContact(s) #302GroupsUpdate
API allows updating read-only groups, which results in a falsely successful operation #305- Extension
fun Activity.selectPhoto()
in PhotoPicker.kt does not work in APIs 30 and up #314
🛠️ Improvements
- Update documentation for
contacts.ui.util.requestToBeTheDefaultDialerApp
to include additional instructions for API 33 (Tiramisu) and higher #315 - Allow updating and deleting read-only groups when
ContactsContract.CALLER_IS_SYNCADAPTER
is set to true #309
💣 Breaking changes
- Remove the
associatedWith
andassociatedWithRawContactIds
functions from theAccountsQuery
API andprofile
from theAccounts
API #297 - Group
mutableCopy
function should not return null even if readOnly is true in order to support usages by sync adapters #304 - Rename
readOnly
property ofGroupEntity
toisReadOnly
andReadOnly
ofGroupsFields
toGroupIsReadOnly
#310 NewCustomDataEntity
implementations now require additional propertyisReadOnly
#311- Custom data integrations now require
callerIsSyncAdapter: Boolean
parameter #313
🧗 Migrating from 0.3.0
-> 0.3.1
Remove the associatedWith
and associatedWithRawContactIds
functions from the AccountsQuery
API and profile
from the Accounts
API #297
PREVIOUSLY, the AccountsQuery
API provided functions to filter Accounts based on RawContacts via the associatedWith
and associatedWithRawContactIds
functions.
NOW, those API functions have been removed. Reasons for removal are stated in #297
Additionally, the profile
function of the Accounts
API have been removed because the sole reason it existed was for use with associatedWith
and associatedWithRawContactIds
functions of the AccountsQuery
API.
If you need to get the Account of a RawContact based on just an ID, use the RawContactsQuery
API instead.
🗒️ Read the new documentation for the full guide!
Group mutableCopy
function should not return null even if readOnly is true in order to support usages by sync adapters #304
PREVIOUSLY, the Group.mutableCopy()
function may return null if the group is read-only.
NOW, it will no longer return null even if the group is read-only.
🗒️ Read the new documentation for the full guide!
Rename readOnly
property of GroupEntity
to isReadOnly
and ReadOnly
of GroupsFields
to GroupIsReadOnly
#310
Rename the following usages;
GroupEntity.readOnly
->GroupEntity.isReadOnly
GroupsFields.ReadOnly
->GroupsFields.GroupIsReadOnly
NewCustomDataEntity
implementations now require additional property isReadOnly
#311
If you have an implementation of NewCustomDataEntity
, you will have to implement a new property which you should set to false by default.
override var isReadOnly: Boolean = false
🗒️ Read the new documentation for more info about this new property!
Custom data integrations now require callerIsSyncAdapter: Boolean
parameter #313
Add callerIsSyncAdapter: Boolean
as the first parameter to your AbstractCustomDataOperation.Factory.create
functions and AbstractCustomDataOperation
constructors.
🗒️ Full Changelog
🗣️ Discuss this release
Head on over to the v0.3.1 Release Checklist and leave a comment and/or some reactions 🙏 😄
v0.3.0 - Lots of improvements, with some breaking changes, and bug fixes
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
- Enhanced API for moving any RawContacts to different Accounts (or null account);
MoveRawContactsAcrossAccounts
#168, documentation
🐞 Bug fixes
- When updating groups, the title is always redacted (replaced with asterisks "*") #281
- Null pointer exception in Fields.all (on first use in multi-threaded API usage) #286
🛠️ Improvements
- Add display name, account, and options properties to RawContactEntity #268
- Support for RawContact IDs in AccountsQuery #276
💣 Improvements with breaking changes
- Replace AccountsLocalRawContactsUpdate API with a better one #282
- Remove Account restrictions for Group, GroupMembership, Relation, and Event #167
- Support setting/removing Contact/RawContact Photos as part of Insert and Update API calls #119
- Allow different Accounts for each RawContact in insert APIs #270
- Move set Contact/RawContact Options functions to be part of Insert and Update APIs #120
- Remove BlankRawContact entity #269
- Generalize AccountsRawContactsQuery to RawContactsQuery #271
- Move Contact link/unlink extensions to a dedicated API #138
♻️ Dependency upgrades
These should not affect you...
- 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 groupsGroupsQuery
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.
v0.2.4 - New PhoneLookup API, SIM card functions, and lots of improvements and bug fixes!
This release contains a brand new API for matching contacts, a bunch of SIM card improvements and bug fixes, and the long awaited fix for permissions
extension crashes 🔥 🥂 🥳 ⭐ ❤️
There is a potential one-line breaking change, which you probably don't have to worry about 🤞
💡 New features
- New API for specialized matching of phone numbers;
PhoneLookupQuery
#259, documentation - Detect SIM card availability #212, documentation
- Detect SIM card name and number max character limits #201, documentation
- Extensions for getting successfully inserted SimContacts #260, documentation
🛠️ Improvements
- Optimize
Query
andBroadQuery
when not including data fields #249 - Add
Account
toBlankRawContactEntity
#254 - Apply offset and limit manually in all query APIs for devices that do not support them #253
🐞 Bug fixes
- Permissions module extension
xxxWithPermission()
may crash app #143 - Query APIs do not return local contacts in Samsung devices when passing null to
accounts
functions #257 - Unable to delete multiple duplicate SIM contacts in one delete operation #261
- Deleting SIM contacts with name but no number or with number but no name always fails #263
💣 Breaking changes
- Remove
includeBlanks
function fromQuery
,BroadQuery
, andProfileQuery
APIs #251
♻️ Internal refactors
- Replace permissions library Dexter with TedPermissions #101
🧗 Migrating from 0.2.0
, 0.2.1
, 0.2.2
, or 0.2.3
-> 0.2.4
If you use the includeBlanks
function of Query
, BroadQuery
, or ProfileQuery
APIs, all you would need to do is delete that line of code and you are done!
If you used to set
includeBlanks
totrue
, then nothing will change for you because it is now hard coded to true. If you used to set it tofalse
, also nothing will change for you because it was never working correctly anyways.
🗒️ Full Changelog
🗣️ Discuss this release
Head on over to the v0.2.4 Release Checklist and leave a comment or some reactions 🙏
v0.2.3 - Enhanced delete APIs (PART 2)!
This release contains more new features for delete APIs, some minor improvements, and an internal refactor that could increase performance.
I'm once again happy to announce that this release has no breaking changes!
New features
- Delete Blocked Numbers by ID #234
- Delete BlockedNumbers using a WHERE clause #236
- Delete Group by ID #235
- Delete Groups using a WHERE clause #237
- Delete SimContacts by Name and Number #238
Improvements
- Allow BlankRawContacts to be used in most APIs #232
- Add property to all query API results that indicate if the limit is breached #243
Internal refactors
- Prevent non-fatal error logs; "SQLiteLog: (1) no such column:" when using the Query API with a non-null WHERE and includeBlanks set to true #231
Full Changelog
Want to discuss this release?
Head on over to the v0.2.3 Release Checklist and leave a comment!
v0.2.2 - Enhanced delete APIs!
This release contains several new features, an improvement, and a critical bug fix to delete APIs.
I'm once again happy to announce that this release has no breaking changes and that we have another new contributor ❤️
New features
- Delete Contacts and RawContacts using a WHERE clause #158
- Delete Data using a WHERE clause #225
- Delete Contacts and RawContacts by ID #222
- Delete Data by ID #227
Improvements
- Allow BlankRawContacts to be used in the Delete API #220
Bugfixes
- Delete, ProfileDelete, and DataDelete API results isSuccessful is true even though delete failed #223
New Contributors!
- @yuanhoujun made their first contribution in #221
Full Changelog
Want to discuss this release?
Head on over to the v0.2.2 Release Checklist and leave a comment!
v0.2.1 - New features, improvements, and bug fixes!
This release contains some new good stuff 🍪, some nice-to-have improvements 🍬, and some critical bug fixes 🐞🔨!
I'm also happy to announce that this release has no breaking changes and that we have another new contributor ❤️
New features
- Share existing contacts #211
Improvements
- Update APIs include function overhaul #209
- Add Java interop for EventDate companion functions #215
- Log execution time of all CRUD APIs #214
- Provide the the RawContact whose photo is used as the primary Contact photo #205
Bugfixes
- Query and BroadQuery APIs' LIMIT and OFFSET functions are not working #217
- RawContactPhoto thumbnail extensions always returns null #204
- Removing a RawContact's Group memberships may not work and may result in the deletion of incorrect arbitrary data #208
New Contributors!!!
Full Changelog
Want to discuss this release?
Head on over to the v0.2.1 Release Checklist and leave a comment!
v0.2.0 - Colossal milestone reached ❤️🔥
It's been half a year since the initial release of this project... Now, through (more) hard work, ❤️, 🔥, and dedication, the biggest project milestone has been reached ⭐️
🖼 Release overview
⚠️ WARNING: This release may potentially trigger seizures for people with photosensitive epilepsy. Viewer discretion is advised.
This release contains...
💡New features💡 | ⚒️Improvements⚒️ |
---|---|
🐞Bug fixes🐞 | 🚨Breaking changes🚨 |
This release marks the completion of the first and biggest milestone in the 🗺Project Roadmap! At this point, most of the core features have been implemented with complete 📜Documentation.
There is still a lot of work to do to reach v1.0.0, the first true semantic version of this library. Note that versions prior to v1.0.0 does not follow semantic versioning ✌️
💡 New features
Blocked phone numbers
You now have read & write access to blocked numbers 🛑
SIM card access
You are now able to read & write contacts from the SIM card 📱
Contact LOOKUP_KEY
Lookup keys allow you to load contacts even if they get linked/unlinked, perfect for creating shortcuts to contacts from the launcher 🔍
Google Contacts app custom data
The customdata-googlecontacts
module gives you read & write access to custom data managed by the Google Contacts app 🌈
Pokemon custom data
The customdata-pokemon
module allows you to give your contacts their favorite Pokemons 🔥
Role Playing Game (RPG) custom data
The customdata-rpg
module allows you to assign a profession and stats to your contacts ⚔️
⚒️ Improvements
Revamped documentation with MkDocs
Didn't like the old documentation website? Me neither. Now, it's prettified, structured, and searchable using Material for MkDocs 🏆
BroadQuery
matching for phone and email
Narrow down your broad search to just phone or email instead of all data kinds 🍥
Get contacts with matching data of any kind (default, unchanged),
val contacts = Contacts(context)
.broadQuery()
.wherePartiallyMatches(searchText)
.find()
Get contacts with matching phone,
.match(Match.PHONE)
Get contacts with matching email,
.match(Match.EMAIL)
Of course, you can use the Query
API to make your own advanced, custom matching criteria.
GroupsDelete
is now available for all supported API versions (19 to 31+)
The library now allows you to delete groups starting with KitKat (API 19) 👍
val deleteResult = Contacts(context).groups().delete().groups(groups).commit()
🐞 Bug fixes
Fixed Query
returning no results when AND'ing fields of different mime types in WHERE clause
This is one of those rare occasions when binary trees and recursion saves the day. Traversing the binary tree structure of the Where
clause in post order, simplifying as needed, enables you to AND fields of different mime types together 🤯
val contacts = Contacts(context)
.query()
.where { Email.Address.isNotNull() and Phone.Number.isNotNull() and Name.DisplayName.isNotNull() and Organization.Company.isNotNull() }
// Or for shorthand...
// .where(listOf(Email.Address, Phone.Number, Name.DisplayName, Organization.Company) whereAnd { isNotNull() })
.find()
Fixed Query
and BroadQuery
returning RawContacts that are pending deletion when includeBlanks(true)
RawContacts that have been marked for deletion but not yet deleted (perhaps because of no network connectivity preventing a sync) are no longer returned in queries of any configuration 🤗
val contacts = Contacts(context)
.query()
// or .broadQuery()
.includeBlanks(true)
.find()
Fixed GroupsQuery
returning Groups that are pending deletion
Groups that have been marked for deletion but not yet deleted (perhaps because of no network connectivity preventing a sync) are no longer returned in queries 🤗
val groups = Contacts(context).groups().find()
v0.1.10 - Improved DSL for Fields, Redaction, Logging, and Accounts API simplification!
This release contains some new nice-to-have goodies and simplifications in several APIs. This may have some breaking changes for you if you use Accounts APIs. Don't worry it's not much! Just read the Migration guide section at the bottom of this page ❤️
New nice-to-have goodies! 😋 😋 😋
- #147 Redacted APIs and Entities 🍧
- Howto page: howto-redact-apis-and-entities.md
- #144 Logging support 🍪
- Howto page: howto-log-api-input-output.md
API improvements 🍬
- #152 Simplified API for attaching local RawContacts to an Account (breaking change)
- #153 Simplified API for querying for Accounts (breaking change)
- #150 Improved syntactic Kotlin sugar (DSL) for constructing Where clauses using Fields 🍰🍰
- This is a minor improvement but very cool nonetheless! Essentially, you don't need to import or write the
Fields
inwhere
,include
, andorderBy
functions anymore if you choose not to. There is a separate function now that takes in a function that hasFields
as the receiver. More details in #150 - Howto page: howto-query-contacts-advanced.md#an-advanced-query
- This is a minor improvement but very cool nonetheless! Essentially, you don't need to import or write the
Please keep in mind that releases below the semantic version v1.0.0 may contain breaking changes!!! Anything below the semantic version v1.0.0 are implicitly experimental/non-stable. Backwards compatibility and deprecations will not be exercised until after v1.0.0 (the first true production release version) in order to keep the library clean and easy to change. TLDR; I'm not really following semantic versioning
major.minor.patch
for any releases below v1.0.0. 😅
Upgrades
- #164 Set target and compile SDK version from 30 to 31.
Internal refactors
Just thought you should know about these in case you experience regression when updating to this version. These should not affect you at all. But just in case, you know about these 🎺
- #148 Lazily evaluating WHERE clause.
- #154 Standardized interface for all CRUD APIs accessible via Contacts instance.
Note for #154. You can actually use the
CrudApiListenerRegistry
as an advanced feature if you want. I don't recommend it though, which is why I am not announcing it as a new feature. I also did not write a howto page for it. The library is currently using this mechanism for logging but you may find some advanced use for it. If you do, let me know how you end up using it! We may find some other use for it than attaching our logger.
New Contributors!!!
- @alorma made their first contribution in #145
- The initial implementation of our logger is nice and sweet! Thank you and welcome to the will-be-legendary Android library 🔥
- @jayasuryat made their first contribution in #163
- This genius from Reddit reduced 500 lines of code down to 2 lines 🤯 🤯🤯 Truly amazing! This library is lucky to have him as a contributor 🔥 🔥 🔥
Full Changelog
Want to discuss this release?
Head on over to the v0.1.10 Release Checklist and leave a comment!
Migration guide (from v0.1.9 to v0.1.10)
This should cover everything that could affect you. Let me know if I missed anything! If you don't care to look at the before-and-after, then go straight into the howto pages. I also made sure to update all documentation in code
I. Simplified API for attaching local RawContacts to an Account
Previously, in order to attach a set of local RawContacts to an Account, you would do...
val isSuccessful: Boolean = Contacts(context)
.accounts()
.updateRawContactsAssociations()
.associateAccountWithLocalRawContacts(account, rawContacts)
This really deviated from the API design of using commit
as the terminal operator and everything prior as argument specifications. So, I decided to simplify it and also follow the design of the other update APIs!
Now, to do the same thing as the above example...
val result: Result = Contacts(context)
.accounts()
.updateLocalRawContactsAccount()
.addToAccount(account)
.localRawContacts(rawContacts)
.commit()
val isSuccessful = result. isSuccessful
This is more future-proof and just looks nicer 😄
I have not written the howto page for this but the documentation in code should be enough for now. The issue for the howto page is #1. Leave a comment there if you want to push me to write it sooner 🤣
II. Simplified API for querying for Accounts
Previously, in order to query for android.accounts.Account
...
Contacts(context).accounts().query().apply {
val allAccounts : List<Account> = allAccounts(context)
val googleAccounts : List<Account> = accountsWithType(context, "com.google")
val accountsForRawContacts: Result = accountsFor(rawContacts)
}
The problem was similar to the previous refactor. This API derails from the design of the other APIs! This was the last one that had to be fixed to come up with a standard for all APIs in the library... So I cleaned it up!!! 🔥
Now...
Contacts(context).accounts().query().apply {
val allAccounts : List<Account> = find()
val googleAccounts : List<Account> = withTypes("com.google").find()
val accountsForRawContacts: Result = associatedWith(rawContacts).find()
}
This also enables you to use withTypes
and associatedWith
together in different combinations, giving you more flexibility and control!
I updated the howto page for this, howto-query-accounts.md, so you can take a look at it for usage guides if the in-code documentation is not good enough for you 😁