Page Example

Scheduler Sample Overview

Mobile native

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

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:

  1. 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() 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() failed (%x)", error);
    
       int count = 0;
       error = calendar_list_get_count(list, &count);
       WARN_IF(error != CALENDAR_ERROR_NONE, "calendar_list_get_count() 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;
    }
    
  2. 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();
    }
    
  3. 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

    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() 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() failed (%x)", error);
    
       if (record)
       {
          calendar_record_destroy(record, EINA_FALSE);
       }
    
       error = calendar_disconnect();
       WARN_IF(error != CALENDAR_ERROR_NONE, "calendar_disconnect() failed (%x)", error);
       elm_naviframe_item_pop(ad->navi);
    }
    
  4. 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

    Customizing options

  5. 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

    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() 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);
    }