Contacts history for Xojo

As you may know we need to get rid of the older Addressbook framework and move everyone to newer Contacts framework. One of the feature we missed so far was querying history of contacts, so we can synchronise our database in the application with the system contacts database.

For the upcoming version 22.0 of MBS Xojo Plugins we add the CNChangeHistoryFetchRequestMBS class. This class allows you to build a request with various options like whether to include groups or whether to unify results. Here is some sample code:

Sub QueryHistory()
	// prepare request
	Dim request As New CNChangeHistoryFetchRequestMBS
	
	request.shouldUnifyResults = True
	request.includeGroupChanges = true
	request.startingToken = LastTimeToken // nil for all, old token to find new stuff
	
	// ask for more keys, so we have data to display
	dim keys() as CNKeyDescriptorMBS
	
	keys.Append CNContactMBS.CNContactOrganizationNameKey
	keys.Append CNContactMBS.CNContactGivenNameKey
	keys.Append CNContactMBS.CNContactFamilyNameKey
	keys.Append CNContactMBS.CNContactTypeKey
	request.setAdditionalContactKeyDescriptors keys
	
	dim error as NSErrorMBS
	dim result as CNFetchResultMBS = m.enumeratorForChangeHistoryFetchRequest(request, error)
	
	if error <> nil then
		MessageBox error.LocalizedDescription
	else
		
		ShowHistory result
		
		LastTimeToken = result.currentHistoryToken
		
	end if
End Sub

If you like to show the results, you loop over the array and then check what subclass you got. All the changes have explicit subclasses and we got CNChangeHistoryRemoveSubgroupFromGroupEventMBS, CNChangeHistoryAddSubgroupToGroupEventMBS, CNChangeHistoryRemoveMemberFromGroupEventMBS, CNChangeHistoryAddMemberToGroupEventMBS, CNChangeHistoryDeleteGroupEventMBS, CNChangeHistoryUpdateGroupEventMBS, CNChangeHistoryAddGroupEventMBS, CNChangeHistoryDeleteContactEventMBS, CNChangeHistoryUpdateContactEventMBS, CNChangeHistoryAddContactEventMBS, CNChangeHistoryDropEverythingEventMBS and CNChangeHistoryFetchRequestMBS sub classes for CNFetchResultMBS class. In our example we check them like this:

Sub ShowHistory(result as CNFetchResultMBS)
	dim list as listbox = self.List
	dim items() as CNChangeHistoryEventMBS = result.ChangeHistoryEvents
	
	for each item as Variant in items
		
		if item isa CNChangeHistoryAddContactEventMBS then
			dim his as CNChangeHistoryAddContactEventMBS = item
			
			list.AddRow "Add contact "+his.contact.displayName
			
		elseif item isa CNChangeHistoryAddGroupEventMBS then
			dim his as CNChangeHistoryAddGroupEventMBS = item
			
			list.AddRow "Add group "+his.group.Name
			
		elseif item isa CNChangeHistoryAddSubgroupToGroupEventMBS then
			dim his as CNChangeHistoryAddSubgroupToGroupEventMBS = item
			
			list.AddRow "Add sub group "+his.subgroup.Name+" to "+his.group.Name
			
		elseif item isa CNChangeHistoryAddMemberToGroupEventMBS then
			dim his as CNChangeHistoryAddMemberToGroupEventMBS = item
			
			list.AddRow "Add member "+his.member.displayName+" to "+his.group.Name
			
		elseif item isa CNChangeHistoryDeleteContactEventMBS then
			dim his as CNChangeHistoryDeleteContactEventMBS = item
			
			list.AddRow "Delete contact "+his.contactIdentifier
			
		elseif item isa CNChangeHistoryDeleteGroupEventMBS then
			dim his as CNChangeHistoryDeleteGroupEventMBS = item
			
			list.AddRow "Delete group "+his.groupIdentifier
			
		elseif item isa CNChangeHistoryDropEverythingEventMBS then
			dim his as CNChangeHistoryDropEverythingEventMBS = item
			
			list.AddRow "Drop everything."
			
		elseif item isa CNChangeHistoryRemoveMemberFromGroupEventMBS then
			dim his as CNChangeHistoryRemoveMemberFromGroupEventMBS = item
			
			list.AddRow "Remove member "+his.member.displayName+" to "+his.group.Name
			
		elseif item isa CNChangeHistoryRemoveSubgroupFromGroupEventMBS then
			dim his as CNChangeHistoryRemoveSubgroupFromGroupEventMBS = item
			
			list.AddRow "Remove sub group "+his.subgroup.Name+" to "+his.group.Name
			
		elseif item isa CNChangeHistoryUpdateContactEventMBS then
			dim his as CNChangeHistoryUpdateContactEventMBS = item
			
			list.AddRow "Update contact "+his.contact.displayName
			
		elseif item isa CNChangeHistoryUpdateGroupEventMBS then
			dim his as CNChangeHistoryUpdateGroupEventMBS = item
			
			list.AddRow "Update group "+his.group.Name
			
		else
			Break
		end if
		
	next
End Sub

Please try and see whether this works for you. Be aware that you can store a token for the last state you get via currentHistoryToken property in CNFetchResultMBS class to make another query later to find only newer changes. Our example app makes the initial query and then waits for DidChange event in CNContactStoreMBS subclass to make newer queries to update. Example and new classes are included in 22.0pr7 download.

2 Likes