Page Example

(Circle) Voice Memo Sample Overview

Wearable native

The (Circle) Voice Memo sample application demonstrates how you can manage several views using a naviframe, and add a More option (3 dots) button to a view. Using a genlist for several items gives you an insight on how to handle saved data and the life-cycle of data from saving to showing and deletion.

For information on creating the sample application project in the IDE, see Creating Sample Applications.

The following figure illustrates the main screens of the (Circle) Voice Memo.

Figure: (Circle) Voice Memo screens

(Circle) Voice Memo screens

The user can record voice by clicking the record button. To listen to the recorded voice memo, click the play button.

To listen to voice memos recorded earlier, click the More option button, select the list option, scroll to the wanted memo, and select it.

Source Files

You can create and view the sample application project including the source files in the IDE.

Table: Source files
File name Description
edje/images This directory contains the image files used in the main.edc file.
inc/data.h This file contains information and definition of the variables and functions used in the C files, especially in the data.c file.
inc/view.h This file contains information and definition of the variables and functions used in the C files, especially in the view.c file.
inc/voicememo.h This file contains information and definition of the variables and functions used in the C files, especially in the main.c file.
res/edje/main.edc This file is for the UI and contains style, image, and position of the sample application.
res/image This directory contains the image files used in the C files.
src/data.c This file contains the functions for retrieving and making data for the application.
src/main.c This file contains the functions related to the application life-cycle, callback functions, and view control.
src/view.c This file contains the functions for implementing the views and handling events.

Implementation

Application Layout

The view_create() function creates the view frame that consists of the window and conformant. These components are essential in creating the application UI.

void 
view_create(void)
{
   // Create a window
   s_info.win = view_create_win(PACKAGE);
   if (s_info.win == NULL) 
   {
      dlog_print(DLOG_ERROR, LOG_TAG, "failed to create a window.");

      return;
   }

   // Create a conformant
   s_info.conform = view_create_conformant_without_indicator(s_info.win);
   if (s_info.conform == NULL) 
   {
      dlog_print(DLOG_ERROR, LOG_TAG, "failed to create a conformant");

      return;
   }

   // Show the window after the main view is set up
   evas_object_show(s_info.win);
}

To manage multiple views efficiently (change between views, access view resources, and show effects), you need a naviframe component. To create the naviframe and a circular layout, use the view_voice_memo_create() function:

void 
view_voice_memo_create(void)
{
   // Create a circle surface to be able to show a circular layout
   s_info.circle_surface = eext_circle_surface_conformant_add(s_info.conform);

   // Create a circular layout to be able to use circular APIs
   s_info.layout = view_create_layout_for_conformant_by_theme(s_info.conform, "layout", "application", "default");
   if (s_info.layout == NULL) 
   {
      evas_object_del(s_info.win);
      dlog_print(DLOG_ERROR, LOG_TAG, "failed to create a base_layout.");

      return;
   }

   // Create a naviframe
   view_create_naviframe(s_info.layout);
}

Main View Layout

The following figure illustrates the main view layout.

Figure: Voice Memo main view

Voice Memo main view

To create the main view:

  1. Create the main view frame with the view_create_layout() function in the app_create() function:
    main_view = view_create_layout(view_get_win(), edj_path, "main.view", NULL, NULL);
    

    Figure: Voice Memo main view frame

    Voice Memo main view frame

  2. Fill out the text and button parts:
    • If you change the third parameter of the view_set_text() function, the title or time of the view changes.
    • The fourth parameter of the view_set_button() function is the button icon image. In this sample, to use the background image under the icon, set the button to be transparent, and use the background image set with the EDJ file. The transparent button is set with the focus theme.
    • To do something when the button is clicked, customize the _main_clicked_cb() callback.
    view_set_text(main_view, "main.view.title", "Voice Memo");
    view_set_text(main_view, "main.view.time", "00:00");
    view_set_button(main_view, "main.view.rec", "focus", NULL, NULL, NULL, NULL, _main_clicked_cb, NULL);
    
  3. To create the More option button, a certain theme must be set like in the following example. In this sample application, the theme is created with the view_create_layout_for_conformant_by_theme() function.
    elm_layout_theme_set(layout, "layout", "application", "default");
    

    To make the sample application show the More option button, call the view_set_more_button() function with the _main_more_item_clicked_cb() callback to do something when the more option item is clicked in the selector view.

    You can customize the number of more option items, and their name, sub text, and icon. The last parameter in the view_create_more_item() function is the path of the icon.

    main_more = view_set_more_button(main_view, "main.view.more",
                                     _main_more_item_clicked_cb, NULL);
    
    for (i = 0; i < MAIN_MORE_ITEM_MAX; ++i) 
    {
       data_get_resource(main_more_item[i].icon, full_path, sizeof(full_path));
       view_create_more_item(main_more, i, main_more_item[i].name, main_more_item[i].sub_name, full_path);
    }
    

    Figure: More option selector view

    More option selector view

  4. To manage the main view easily, push the main view into the naviframe:
    s_info.main_view_item = view_push_item_to_naviframe(view_get_naviframe(), main_view, _naviframe_main_view_pop_cb, NULL);
    

    You can customize the _naviframe_main_view_pop_cb() callback to do something when the main view is popped (a back key is pressed on the main view).

Record View Layout

The following figure illustrates the record view when recording is in progress.

Figure: Record view

Record view

When the record button (main.view.rec part) is clicked on the main view, the _main_clicked_cb() callback is triggered, the record view elements are created, and the record view is pushed to the naviframe to show it on the screen:

static void 
_main_clicked_cb(void *data, Evas_Object *obj, void *event_info)
{
   record_view = view_create_layout(view_get_win(), edj_path, "record.view", NULL, NULL);
   view_set_text(record_view, "rec.view.title", file_title);
   view_set_text(record_view, "rec.view.time", "00:00");

   view_set_button(record_view, "rec.view.btn", "focus", 
                   NULL, NULL, NULL, NULL, _rec_clicked_cb, NULL);
   view_set_button(record_view, "rec.view.cancel", "focus", 
                   NULL, NULL, NULL, NULL, _rec_cancel_clicked_cb, NULL);
   view_set_button(record_view, "rec.view.pause", "focus", 
                   NULL, NULL, NULL, NULL, _rec_pause_clicked_cb, record_view);

   s_info.record_view_item = view_push_item_to_naviframe(view_get_naviframe(), record_view, 
                                                         _naviframe_record_view_pop_cb, NULL);
}

The above code creates the following record view frame.

Figure: Record view frame

Record view frame

You can customize a callback to determine an action for a clicked event for each button (record, cancel, and pause) using the eighth parameter of the view_set_button() function (_rec_clicked_cb(), _rec_cancel_clicked_cb(), and _rec_pause_clicked_cb() in the above code).

List View Layout

When the list item (3 horizontal lines) in the more option selector view is clicked, the view_create_voice_list_genlist() function is called to create a list view. The list view shows the previously recorded memos.

Figure: More option selector and the list view

More option selector and the list view

To create the list view:

  1. Create a circular genlist with the view_create_circle_genlist() function:
    voice_list_genlist = view_create_circle_genlist(view_get_naviframe());
    
  2. To create a list item, use the view_append_item_to_genlist() function. The _set_genlist_item_class() sets the list item's functions according to the style.

    // Get the list of the saved voice memos
    Eina_List *voice_list = data_get_voice_list();
    // Append the voice memo to the genlist 
    EINA_LIST_FOREACH(voice_list, l, list_data) 
    {
       view_append_item_to_genlist(voice_list_genlist, list_data->style, list_data, _voice_list_item_clicked_cb, NULL);
    }
    
    void 
    view_append_item_to_genlist(Evas_Object *genlist, const char *style, const void *data, 
                                Evas_Smart_Cb _clicked_cb, const void *cb_data)
    {
       Elm_Genlist_Item_Class *item_class = NULL;
    
       if (genlist == NULL) 
       {
          dlog_print(DLOG_ERROR, LOG_TAG, "genlist is NULL.");
    
          return;
       }
    
       if (style == NULL) 
       {
          dlog_print(DLOG_ERROR, LOG_TAG, "item style is NULL.");
    
          return;
       }
    
       item_class = _set_genlist_item_class(style);
    
       elm_genlist_item_append(genlist, item_class, data, NULL, ELM_GENLIST_ITEM_NONE, _clicked_cb, cb_data);
    
       elm_genlist_item_class_free(item_class);
    }
    

    You can customize the _clicked_cb() callback passed from the view_append_item_to_genlist() function for the action to do when the listed item is clicked. In this sample, the detail view of the clicked item is shown when the listed item is clicked.

  3. You can customize the function to be called when the list item is shown on the screen:
    • You can select the view of the list item shown in the genlist, such as 2text or 1text.1icon.
    • According to the style of the list item, you can set the function to each list item, such as _get_menu_title_text(). This means that at the moment when the item must be shown, to get the title of the item, the _get_menu_title_text() function is called.
    if (!strcmp(style, "menu.title")) 
    {
       item_class->item_style = "title";
       item_class->func.text_get = _get_menu_title_text;
    } 
    else if (!strcmp(style, "1text.1icon.1")) 
    {
       item_class->item_style = "1text.1icon";
    } 
    else if (!strcmp(style, "2text")) 
    {
       item_class->item_style = "2text";
    } 
    else if (!strcmp(style, "3text")) 
    {
       item_class->item_style = "3text";
       item_class->func.text_get = _get_item_text;
    } 
    else if (!strcmp(style, "padding"))
    {
       // "padding" style does nothing but places the genlist item in the middle of the screen
    }
    
  4. After setting the view style and functions for getting the item, such as text or icon, push the item to the genlist:
    elm_genlist_item_append(genlist, item_class, data, NULL, ELM_GENLIST_ITEM_NONE, _clicked_cb, cb_data);
    

Detail View Layout

When the user clicks an item in the list view, the detail view with the voice memo information is shown.

Figure: Detail view

Detail view

To create the detail view layout:

  • You can set the button style by passing bottom as a third parameter of the view_set_button() function. This sets the button to the bottom and uses a circular style.
  • If you want to do something, like playing a voice memo, customize the _detail_play_clicked_cb() callback for the button click event.
  • To delete the voice memo, set the detail.view.more part as a More option button.

    Create 1 more option item with the view_create_more_item() function. It is named detail_more_item[i].name, and its icon file path is the fifth parameter, full_path. Set the _detail_more_item_clicked_cb() callback to be called when the more option item is clicked. Delete the voice memo in the callback.

    Figure: More option of the detail view

    More option of the detail view

static void 
_voice_list_item_clicked_cb(void *data, Evas_Object *obj, void *event_info)
{
   data_get_resource(EDJ_FILE, edj_path, sizeof(edj_path));
   detail_view = view_create_layout(view_get_naviframe(), edj_path, "detail.view", NULL, NULL);
   view_set_text(detail_view, "detail.view.title", item_info->title);
   view_set_text(detail_view, "detail.view.date", item_info->detail_date);
   view_set_text(detail_view, "detail.view.time", item_info->detail_time);
   view_set_button(detail_view, "detail.view.play", "bottom", NULL, NULL, NULL, NULL, _detail_play_clicked_cb, NULL);

   // Create a more option button
   detail_more = view_set_more_button(detail_view, "detail.view.more", _detail_more_item_clicked_cb, NULL);
   // Create as many more option items as you need
   // In this case, only one item to delete the memo is needed
   for (i = 0; i < DETAIL_MORE_ITEM_MAX; i++) 
   {
      data_get_resource(detail_more_item[i].icon, full_path, sizeof(full_path));
      view_create_more_item(detail_more, i, detail_more_item[i].name, 
      detail_more_item[i].sub_name, full_path);
   }
   data_set_selected_item(item_info);

   view_push_item_to_naviframe(view_get_naviframe(), detail_view, NULL, NULL);
};

The following figure shows the view frame created by the above code.

Figure: Detail view frame

Detail view frame

Empty List View Layout

If there are no voice memos in the database, when you call the view_create_voice_list_genlist() function to make a list view, an empty list view is created instead.

Unlike with the other views of this sample, it is not necessary to use an EDJ file to get a frame for the empty list view. Tizen supplies the theme for the empty list view, and you only have to call the view_create_layout_no_content function with a title, detail text, and image file.

item_count = data_get_voice_list_item_count();

// If there are no voice memos, show the empty list view
if (item_count == 0) 
{
   Evas_Object *novoice_view = NULL;

   novoice_view = view_create_layout_no_content(view_get_naviframe(), "Recordings", 
                                                "No recordings", full_path);
} 

The above code creates a view that consists of a title, center image, and bottom detail text, as illustrated in the following figure.

Figure: Empty list view

Empty list view

Initializing and Preparing Voice Recording

To use the recorder for a voice recording, you must initialize the recorder and create the recorder handle, encoder, and file format. All the necessary details are initialized in the _voice_memo_initialize_recorder() function. For more information on initializing the recorder, see the Recorder Tutorial.

After initializing, call the following function to prepare the recorder and set the recorder state to READY:

_voice_memo_control_recorder(PREPARE);

Managing Voice Recording

To manage voice recording:

  • Start recording

    When the recording button in the main view is clicked, the recorder sets the file name to be recorded with the index of the recording file.

    Recording is started with the _voice_memo_control_recorder() function, and the recorder state changes to RECORDING.

    char *file_name = data_get_filename_according_to_count();
    _voice_memo_set_filename_to_recorder(file_name);
    
    _voice_memo_control_recorder(START);
    
  • Cancel recording

    When the cancel button in the record view is clicked, the following function is called:

    _voice_memo_control_recorder(CANCEL);
    

    This changes the recorder state to READY, and a file name must be set again.

  • Pause recording

    When the pause button in the record view is clicked, the following function is called:

    _voice_memo_control_recorder(PAUSE);
    

    This changes the recorder state to PAUSE. Call the _voice_memo_control_recorder() function to resume recording.

  • Stop and save recording

    When the stop button in the record view is clicked, the recording is stopped and the recording file is saved.

    _voice_memo_control_recorder(SAVE);
    

    This changes the recorder state to READY, and the recorded data is saved and named using the data_set_filename_according_to_count() function.

Managing the Recorded Files

To manage the recorded files:

  • Get the file

    To get the information of the recorded file, there are 2 functions:

    • Right after saving the recorded file, you can use the following function to get the file name from the recorder handle:
      char *file_path = _voice_memo_get_filepath_from_recorder();
      
    • Right after launching the application, you can use the following function to get the file name from the database using opendir:
      data_create_voice_list_from_db();
      
  • Convert to a structure

    In both of the 2 functions described above, the following function is called to retrieve the information of the recorded file and convert to a structure that has members you want to use:

    record_info = data_get_recording_info_from_file_path(NULL, file_path);
    

    This function uses Metadata Extractor APIs to get the information of the recorded file and convert to the structure you want to use. For more information, see the Metadata Extractor Tutorial.

  • Remove a file

    When the remove button in the more option view is clicked, the recorded file must be removed not only from the list view but also from the database using the data_remove_selected_item_from_list_and_db() function. Use the view_pop_item_from_naviframe() function to pop the selected item's detail view from the naviframe.

    data_remove_selected_item_from_list_and_db();
    view_pop_item_from_naviframe();