Scheduler Sample Overview
The Scheduler sample demonstrates how to schedule calendar events, change and configure their status, and set reminders. Additionally, the Scheduler sample shows daily and monthly calendar views and navigates between them to display lists of scheduled events.
The following figure illustrates the main views of the Scheduler application and the Details event view.
Figure : Scheduler main views
Each form contains appropriate UI components to enter required data, such as the event title, date and time, time zone, location, recurrence, priority, and sensitivity and buttons to create or save events.
Implementation
To manage events:
- Navigate between lists of events in a daily or monthly order, navigate between lists of events, display event details, and access editing options. When the application starts, it enumerates events and displays them in a selected order.
static void tabbar_daily_clicked_cb(void *data, Evas_Object *obj, void *event_info) { main_view_data *ad = (main_view_data *)data; if (data && ad->gl_allday) { ad->added_rec_pos = 0; get_daily_events(data, ad->gl_allday, EINA_FALSE, EINA_TRUE); get_daily_events(data, ad->gl_events, EINA_TRUE, EINA_TRUE); } ad->current_view = DAILY; }
The lists of events can be retrieved from the calendar database:
static void get_daily_events(void *data, Evas_Object *gen_list, Eina_Bool no_all_day, Eina_Bool daily) { calendar_error_e error = CALENDAR_ERROR_NONE; error = calendar_connect(); WARN_IF(error != CALENDAR_ERROR_NONE, "calendar_connect() is failed(%x)", error); // remove all events from genlist main_view_data *ad = (main_view_data *)data; elm_genlist_clear(gen_list); // create new genlist if (!ad->itc) { ad->itc = elm_genlist_item_class_new(); ad->itc->item_style = "default"; ad->itc->func.text_get = _item_label_get; ad->itc->func.content_get = NULL; ad->itc->func.state_get = NULL; ad->itc->func.del = NULL; } // add new events calendar_list_h list = NULL; error = calendar_db_get_all_records(_calendar_event._uri, 0, 0, &list); WARN_IF(error != CALENDAR_ERROR_NONE, "calendar_db_get_all_records() is failed(%x)", error); int count = 0; error = calendar_list_get_count(list, &count); WARN_IF(error != CALENDAR_ERROR_NONE, "calendar_list_get_count() is failed(%x)", error); calendar_record_h record = NULL; int index = 0; Eina_List *index_list = NULL; if (ad->added_rec_pos == 0 && ad->index_array) { free(ad->index_array); ad->index_array = calloc(count, sizeof(int)); } else if (!ad->index_array) { ad->index_array = calloc(count, sizeof(int)); } ad->max_records = count; for (int i = 0; i < count; i++) { ... // fill in list here ad->added_rec_pos++; } eina_list_free(index_list); calendar_list_destroy(list, true); calendar_disconnect(); elm_genlist_item_class_free(ad->itc); ad->itc = NULL; }
- View event details.
When an event is clicked on the list, the _item_sel_cb callback is called and the details_view_add() function is executed:
void details_view_add(window_obj *win, Evas_Object *parent, int index) { RETM_IF(!win || !parent, "Passed NULL input data"); details_view_data *data = calloc(1, sizeof(details_view_data)); RETM_IF(!data, "Cannot allocate memory"); data->win = win; data->navi = parent; data->event_record_index = index; calendar_connect(); if (CALENDAR_ERROR_NONE != calendar_db_get_record(_calendar_event._uri, index, &data->event_record)) { calendar_disconnect(); free(data); return; } calendar_db_get_record(_calendar_alarm._uri, index, &data->alarm_record); data->layout = ui_utils_layout_add(data->navi, details_view_destroy_cb, data); evas_object_size_hint_weight_set(data->layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(data->layout, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_layout_file_set(data->layout, GET_PATH(EDJ_CREATEVIEW), "create_view_layout"); // Header for naviframe data->navi_item = elm_naviframe_item_push(data->navi, "Details", NULL, NULL, data->layout, NULL); elm_naviframe_item_pop_cb_set(data->navi_item, _details_view_navi_pop_cb, data); evas_object_show(data->layout); // Footer for naviframe Evas_Object * toolbar = ui_utils_toolbar_add(data->navi, data->navi_item); elm_toolbar_item_append(toolbar, NULL, button_edit, edit_button_cb, data); elm_toolbar_item_append(toolbar, NULL, button_delete, _delete_button_cb, data); // Create genlist for Events control _genlist_add(data); _genlist_items_append(data); calendar_disconnect(); }
- Create new events.
When all the fields are filled, and the user has clicked the Save button, the _save_btn_clicked_cb callback is called and the new event is created:
Figure: Adding events and modifying event details
static void save_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info) { create_view_data *ad = (create_view_data *)data; RETM_IF(!ad, "Passed NULL input data"); const char *title = elm_entry_entry_get(ad->title_entry); RETM_IF(!title, "title string NULL"); if (strlen(title) == 0) { create_warning_popup(ad, WARNING_POPUP_TEXT); return; } calendar_error_e error = CALENDAR_ERROR_NONE; error = calendar_connect(); RETM_IF(error != CALENDAR_ERROR_NONE, "calendar_connect() is failed(%x)", error); calendar_record_h record = create_record_with_presets(); set_record_title(record, ad->record_title); set_record_time(&ad->stm, &ad->etm, record, ad->is_all_day); set_record_timezone_city(record); set_record_location(record, ad->record_location, CALENDAR_RECORD_NO_COORDINATE, CALENDAR_RECORD_NO_COORDINATE); set_record_note(record, ad->record_description); set_record_priority(record, ad->priority); set_record_sensitivity(record, ad->sensitivity); set_record_status(record, ad->status); set_record_reminder(record, ad->reminder, ad->reminder_type); set_record_recurrence(record, ad->recurrence_data.id); if (ad->recurrence_data.id != REPEAT_NONE) { set_record_repeat_count(record, ad->recurrence_data.count); set_record_repeat_until_time(record, &ad->recurrence_data.tm); } int record_index = 0; error = calendar_db_insert_record(record, &record_index); WARN_IF(error != CALENDAR_ERROR_NONE, "calendar_db_insert_record() is failed(%x)", error); if (record) { calendar_record_destroy(record, EINA_FALSE); } error = calendar_disconnect(); WARN_IF(error != CALENDAR_ERROR_NONE, "calendar_disconnect() is failed(%x)", error); elm_naviframe_item_pop(ad->navi); }
- Modify the extended options of adding an event.
There is a series of popup windows with options to choose from.
static void _show_btn_context_popup(void *data, Evas_Smart_Cb func, int n_labels, char **label, EVENT_PARAM_TYPE type) { RETM_IF(!data, "Passed NULL input data"); create_view_data *ad = (create_view_data *)data; Evas_Object *popup = elm_ctxpopup_add(ad->layout); evas_object_data_set(popup, KEY_PRIORITY_DATA, ad); Evas_Object *btn = NULL; int param = 0; switch (type) { case PARAM_REMINDER: param = REMINDER_MINUTES; btn = ad->reminder_btn; ad->reminder_ctxpopup = popup; break; case PARAM_PRIORITY: param = PRIORITY_LOW; btn = ad->priority_btn; ad->priority_ctxpopup = popup; break; case PARAM_SENSITIVITY: param = SENSITIVITY_PUBLIC; btn = ad->sensitivity_btn; ad->sensitivity_ctxpopup = popup; break; case PARAM_STATUS: param = STATUS_NONE; btn = ad->status_btn; ad->status_ctxpopup = popup; break; default: break; } for (int i = 0; i < n_labels; i++, param++) { elm_ctxpopup_item_append(popup, label[i], NULL, func, (void *)param); } evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); int x = 0; int y = 0; evas_object_geometry_get(btn, &x, &y, NULL, NULL); evas_object_move(popup, x, y); evas_object_smart_callback_add(popup, "dismissed", func, NULL); evas_object_show(popup); }
Figure: Customizing options
- Edit a previously created event.
When all the fields are filled or edited, and the Save button is pressed, the save_button_clicked_cb callback is called:
Figure: Customizing editing and recurrence
void save_button_clicked_cb(void *data, Evas_Object *obj, void *event_info) { RETM_IF(!data, "Passed NULL input data"); edit_view_data *view_data = (edit_view_data *)data; int error = calendar_connect(); RETM_IF(error != CALENDAR_ERROR_NONE, "calendar_connect() is failed(%x)", error); const char *title = elm_entry_entry_get(view_data->title_entry); set_record_title(view_data->event_record, title); struct tm *start_time = NULL; elm_datetime_value_get(view_data->start_datetime, start_time); struct tm *end_time = NULL; elm_datetime_value_get(view_data->end_datetime, end_time); bool is_all_day = elm_check_state_get(view_data->check_object); set_record_time(start_time, end_time, view_data->event_record, is_all_day); set_record_timezone_city(view_data->event_record); const char *location = elm_entry_entry_get(view_data->location_entry); set_record_location(view_data->event_record, location, CALENDAR_RECORD_NO_COORDINATE, CALENDAR_RECORD_NO_COORDINATE); const char *description = elm_entry_entry_get(view_data->description_entry); set_record_note(view_data->event_record, description); set_record_priority(view_data->event_record, view_data->priority); set_record_sensitivity(view_data->event_record, view_data->sensitivity); set_record_status(view_data->event_record, view_data->status); set_record_recurrence(view_data->event_record, view_data->recurrence_data.id); set_record_repeat_count(view_data->event_record, view_data->recurrence_data.count); set_record_repeat_until_time(view_data->event_record, &view_data->recurrence_data.tm); calendar_db_update_record(view_data->event_record); calendar_disconnect(); elm_naviframe_item_pop(view_data->navi_frame); }