Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(android): added new methods in Ti.Calendar.Calendar module for bulk operations #14149

Merged
merged 12 commits into from
Dec 12, 2024

Conversation

prashantsaini1
Copy link
Contributor

This PR brings major improvements to deal with bulk operations in Ti.Calendar.Calendar module. Test results are below in this PR.

1. createEvents(args)

  1. args - an array of Ti.Calendar.Event properties, same as createEvent signature in an array.
  2. Returns - an array containing Ti.Calendar.Event for successfully created events, or null for failed events, on same position as passed in args so that the results can be properly used.

2. deleteEvents(ids)

  1. ids - an array of Ti.Calendar.Event.id value, both int/string are accepted.
    1. If ids are known upfront without having to create a calendar event, same can be passed directly, thus removing the need to first create an event and then call remove() method on it.
  2. Returns - an integer value denoting how many events were deleted. If 0, either it was a failed operation, or there were actually no events associated with the passed ids. Can be <= ids.length.
    1. This is by design in native SDK which only returns the count, not the success result in delete operation. For single event delete operation, a check of == 1 can be applied to know if it was a successful deletion or not.

3. getEventsById(ids)

  1. ids - same as in deleteEvents() above.
  2. Returns - an array containing Ti.Calendar.Event for successfully created events.
    1. The returned array length can be <= ids.length if some events are not created. Generally the id property of created events can be used to compare with the passed ids array to know which events got successfully created.

Test results to show approx time taken for 100 events operations.

- Creation Deletion Fetch
createEvent() loop 2500 ms
createEvents() 500 ms
remove() loop 3800 ms
deleteEvents() 22 ms
getEventById() loop 3200 ms
getEventsById() 25 ms

@prashantsaini1 prashantsaini1 changed the title feat(android): added new methods in CalendarProxy for bulk operations feat(android): added new methods in Ti.Calendar.Calendar module for bulk operations Dec 2, 2024
Copy link
Collaborator

@hansemannn hansemannn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you can add docs and an example test to test, this should work out.

@hansemannn hansemannn requested a review from m1ga December 2, 2024 19:08
Copy link
Contributor

@m1ga m1ga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a small change as we have TiC properties for those parts

@m1ga
Copy link
Contributor

m1ga commented Dec 2, 2024

will there be iOS parity? Guess it would be nice to have those methods there too

@prashantsaini1
Copy link
Contributor Author

@m1ga This PR came as a result of seeing super slow operations on Android with ANR logs sometimes. iOS seems already faster than current Android ones.

It's definitely great to have iOS parity, but I suspect it might take a bit more time to come from my end :).

@m1ga
Copy link
Contributor

m1ga commented Dec 2, 2024

Got it 👍 I didn't test it yet but sounds great that it is a performance boost!

@prashantsaini1
Copy link
Contributor Author

@m1ga Could you please review the format of docs added in yaml if they are fine?

@m1ga
Copy link
Contributor

m1ga commented Dec 4, 2024

@m1ga Could you please review the format of docs added in yaml if they are fine?

you can run npm run lint:docs to see the errors

@prashantsaini1 prashantsaini1 requested a review from m1ga December 4, 2024 10:02
Copy link
Contributor

@m1ga m1ga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some minor code changes. Builds fine

@m1ga
Copy link
Contributor

m1ga commented Dec 4, 2024

SDK builds fine. If you can create a simple test for the new methods I could quickly check the functionality too. Guess you have it running in your app already so I'm sure it will be fine

@prashantsaini1
Copy link
Contributor Author

@m1ga This should help you test the changes:

const eventPayload = {
	name: "Test Event",
	startDate: "2024-12-24",
	endDate: "2024-12-25",
	location: "Titanium SDK"
};

var window = Ti.UI.createWindow();
var view = Ti.UI.createView({ layout: 'vertical', height: Ti.UI.SIZE });

var b1 = Ti.UI.createButton({
	top: 60,
	title: 'Calendar: Run Bulk Ops'
});
b1.addEventListener('click', runBulkOps);

var b2 = Ti.UI.createButton({
	top: 60,
	title: 'Calendar: Run Single Ops'
});
b2.addEventListener('click', runSingleOps);


var l1 = Ti.UI.createLabel({
	top: 60,
	left: 40,
	right: 40,
	text: 'Make sure to run this action to cleanup all test events.'
});
var b3 = Ti.UI.createButton({
	top: 20,
	title: 'Calendar: Clear All'
});
b3.addEventListener('click', clearAll);

view.add(b1);
view.add(b2);
view.add(l1);
view.add(b3);

window.add(view);

window.open();

function permissionAllowed() {
	return new Promise(resolve => {
		Ti.Calendar.requestCalendarPermissions(event => resolve(event.success));
	});
}

function storeIDs(ids) {
	// Store very first event ID only for once.
	const firstEventId = Ti.App.Properties.getInt('first_event_id', 0);
	if (firstEventId === 0) {
		Ti.App.Properties.setInt('first_event_id', ids[0]);
	}

	// Update last event id on every ops.
	Ti.App.Properties.setInt('last_event_id', ids[ids.length - 1]);
}

async function runBulkOps() {
	if (!await permissionAllowed()) {
		alert('allow calendar permissions');
		return;
	}

	const calendar = Ti.Calendar.defaultCalendar;
	const ids = createEventsInBulk(calendar);
	storeIDs(ids);
	getEventsInBulk(calendar, ids);
	deleteEventsInBulk(calendar, ids);
}

async function runSingleOps() {
	if (!await permissionAllowed()) {
		alert('allow calendar permissions');
		return;
	}
	
	const calendar = Ti.Calendar.defaultCalendar;
	const ids = createEventsOneByOne(calendar);
	storeIDs(ids);
	getEventOneByOne(calendar, ids);
	deleteEventOneByOne(calendar, ids);
}

// Single Ops.
function createEventsOneByOne(calendar) {
	const ids = [];
	for (let i = 1; i <= 10; i++) {
		const event = calendar.createEvent( createCalendarEventPayload(eventPayload, i) );
		ids.push(event.id);
	}
	return ids;
}

function getEventOneByOne(calendar, ids) {
	return ids.map(id => calendar.getEventById(id));
}

function deleteEventOneByOne(calendar, ids) {
	ids.forEach(id => calendar.getEventById(id)?.remove());
}


// Bulk Ops.
function createEventsInBulk(calendar) {
	const eventsData = [];
	for (let i = 1; i <= 10; i++) {
		eventsData.push( createCalendarEventPayload(eventPayload, i) );
	}
	
	return calendar.createEvents(eventsData).map(event => event.id);
}

function getEventsInBulk(calendar, ids) {
	return calendar.getEventsById(ids);
}

function deleteEventsInBulk(calendar, ids) {
	return calendar.deleteEvents(ids);
}

function createCalendarEventPayload(calendarItem, count) {
	return {
		title: calendarItem.name + ' : Count ' + count,
		begin: new Date(calendarItem.startDate),
		end: new Date(calendarItem.endDate),
		allDay: true,
		location: calendarItem.location
	};
}

// Clear all test events.
function clearAll() {
	const calendar = Ti.Calendar.defaultCalendar;

	const firstEventId = Ti.App.Properties.getInt('first_event_id', 0);
	const lastEventId = Ti.App.Properties.getInt('last_event_id', 0);

	const ids = Array.from({ length: lastEventId - firstEventId + 1 }, (_, i) => firstEventId + i);
	const deletedCount = deleteEventsInBulk(calendar, ids);

	if (deletedCount > 0) {
		// Reset IDs.
		Ti.App.Properties.setInt('first_event_id', 0);
		Ti.App.Properties.setInt('last_event_id', 0);
	}
}

@m1ga
Copy link
Contributor

m1ga commented Dec 4, 2024

Function test:
working fine. Adding (normal and bulk) work fine and all is removed when clicking the button. I've adjusted the example code so it won't remove them right away so I could test it :)

@hansemannn
Copy link
Collaborator

@prashantsaini1 Please remove the docs that are unrelated to this PR and make sure the action passes. You can also test api docs locally

@prashantsaini1
Copy link
Contributor Author

@m1ga As I was doing lots of lots of testing with 100/200+ events, my device feels a hang on syncing events from Google, so I do not see events added by either way now 😄 . Sometimes the event data is null in single update methods also, sometimes it's available. So I suspect it has something to do with syncing.

@m1ga
Copy link
Contributor

m1ga commented Dec 4, 2024

@m1ga As I was doing lots of lots of testing with 100/200+ events, my device feels a hang on syncing events from Google, so I do not see events added by either way now 😄 . Sometimes the event data is null in single update methods also, sometimes it's available. So I suspect it has something to do with syncing.

yeah, I think if you delete it while it is syncing it will get that event from the cloud again. Happens sometimes when you do stuff quickly.

But it looks fine with the 10 events:

Bildschirmaufnahme_20241204_141118.webm

@hansemannn hansemannn merged commit dfb6a82 into tidev:master Dec 12, 2024
6 checks passed
hansemannn added a commit that referenced this pull request Dec 12, 2024
…ulk operations (#14149)

* feat(android): added new methods in CalendarProxy for bulk operations

* chore: use constant properties

* fix: add missing properties of `scrolling` event

* chore(android): add docs to new methods for Ti.Calendar.Calendar module

* fix(android): set exitOnClose defaults to true on root window if not set already

* Revert "fix(android): set exitOnClose defaults to true on root window if not set already"

This reverts commit e2c4bb9.

* fix: fix docs formatting

* Update android/modules/calendar/src/java/ti/modules/titanium/calendar/CalendarProxy.java

Co-authored-by: Michael Gangolf <[email protected]>

* Update android/modules/calendar/src/java/ti/modules/titanium/calendar/CalendarProxy.java

Co-authored-by: Michael Gangolf <[email protected]>

* Update android/modules/calendar/src/java/ti/modules/titanium/calendar/CalendarProxy.java

Co-authored-by: Michael Gangolf <[email protected]>

* fix: fix docs

---------

Co-authored-by: Michael Gangolf <[email protected]>
Co-authored-by: Hans Knöchel <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants