Voice Memo UI Sample Overview

The Voice Memo sample application demonstrates how you can create a voice memo application with the formal Tizen UI/UX using TAU (Tizen Advanced UI Framework).

The application opens with the main screen, which shows a recording button in the middle:

  1. When the recording button is clicked, the recording view opens, showing a stop button with cancel and pause buttons. It also displays a circular progress bar around the edge of the screen.
  2. When the stop button is clicked, the application automatically saves what has been recorded and displays a view where you can play the recording. Since the gear device does not provide a physical speaker, it requires you to connect the device to a Bluetooth headset to hear the recording.

The application provides a list view which can be accessed from the main screen by clicking the more options button with 3 dots on the right. It lists the recorded files in a reverse chronological order. You can also play the recordings from the list.

The following figure illustrates the main screens of the Voice Memo application.

Figure: Voice Memo screens

Voice Memo screen Voice Memo screen

Voice Memo screen Voice Memo screen

Source Files

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

File name Description
config.xml This file contains the application information for the platform to install and launch the application.
css/style.css This file contains the CSS styling for the application UI.
img/ This directory contains the images used in the application.
index.html This is a starting file from which the application starts loading. It contains the layout of the application screens.
js/app.js This file contains the code for the main functionalities of the application.
js/list.js This file contains the code for customizing the TAU list component.
js/moreoptions.js This file contains the code for customizing the TAU more options component.
js/progress.js This file contains the code for customizing the TAU progress bar component.

Implementation

To define the application layout and initialize the application view:

  1. The basic application layout is defined in the index.html file.

    The application is composed of 3 different pages:

    • Main page for the recording and standby mode
    • List page for the list of voice recordings
    • Play page for the play mode

    Each page is created as a <div> element with the ui-page class using TAU.

    <!--index.html-->
    <body>
       <!--Main page-->
       <div class="ui-page" id="main" data-enable-page-scroll="false">
       </div>
    
       <!--List page-->
       <div class="ui-page" id="list" data-enable-page-scroll="true">
       </div>
    
       <!--Play page-->
       <div class="ui-page" id="play" data-enable-page-scroll="false">
       </div>
    </body>
    
  2. The buttons on the main page are created using the -webkit-mask CSS property.

    For example, the standby button is created as shown in the following example. The -webkit-mask-image property clips the visible portion of an element according to the mask image transparency.

    <!--index.html-->
    <!--Main page: Content: Standby-->
    <div id="voice-recorder-start" class="stand-by">
       <div id="voice-recorder-stop-bg"></div>
       <div id="voice-recorder-stop-icon"></div>
    </div>
    
    <!--css/style.css-->
    <!-------MAIN PAGE: STANDBY------->
    #voice-recorder-stop-bg
    {
       position: absolute;
       top: 0;
       width: 100%;
       height: 100%;
       background-color: rgb(255, 255, 255);
       -webkit-mask-image: url("../image/voicerecorder_stop_bg.png");
       -webkit-mask-size: 126px 126px;
       -webkit-mask-repeat: no-repeat;
       z-index: 1;
    }
    
    #voice-recorder-stop-icon
    {
       position: absolute;
       top: 0;
       width: 100%;
       height: 100%;
       background-color: rgb(224, 4, 4);
       -webkit-mask-image: url("../image/voicerecorder_stop_icon.png");
       -webkit-mask-size: 126px 126px;
       -webkit-mask-repeat: no-repeat;
       z-index: 2;
    }
    
  3. The more options button is created in the header section of the page using a <button> element with the ui-more ui-icon-overflow class.

    The more options pop-up page is created using a <div> element with the ui-popup class and moreoptionsPopupCircle ID name. The ID is used later in the moreoption.js file to identify the pop-up page to customize it.

    <!--index.html-->
    <!--Main page: Popup: More options-->
    <div id="moreoptionsPopupCircle" class="ui-popup">
       <div id="selector" class="ui-selector">
          <div id="to-list" class="ui-item list-icon" data-title="List"></div>
       </div>
    </div>
    
    <!--Main page: Header-->
    <header class="ui-header ui-has-more">
       <h2 id="recording-title" class="ui-title">Voice Memo</h2>
       <button id="main-moreoptions" type="button" class="ui-more ui-icon-overflow">More Options</button>
    </header>
    

    The actual view of the more options pop-up page is created and destroyed dynamically as the main page appears and disappears:

    /* js/app.js */
    function init()
    {
       /* Add event listeners for tauMoreOptions components */
       document.querySelector("#main").addEventListener("pagebeforeshow", function()
       {
          tauMoreOptions.pageBeforeShowHandler("#main");
       });
       document.querySelector("#main").addEventListener("pagebeforehide", tauMoreOptions.pageHideHandler);
    }
    
    /* js/moreoptions.js */
    /*
       Handle events before the more options page shows
       @public
       @param {String} pageId - ID of the page with the more options component
    */
    tauMoreOptions.pageBeforeShowHandler = function(pageId)
    {
       var radius = window.innerHeight / 2 * 0.8;
    
       page = document.querySelector(pageId);
       popup = page.querySelector("#moreoptionsPopup");
       handler = page.querySelector(".ui-more");
       popupCircle = page.querySelector("#moreoptionsPopupCircle");
       elSelector = page.querySelector("#selector");
    
       clickHandlerBound = clickHandler.bind(null);
       clickElSelectorBound = clickElSelector.bind(null);
    
       handler.addEventListener("click", clickHandlerBound);
       elSelector.addEventListener("click", clickElSelectorBound);
    
       if (tau.support.shape.circle)
       {
          selector = tau.widget.Selector(elSelector,
          {
             itemRadius: radius
          });
       }
    };
    
    /*
       Handle events before the more options page hides
       @public
    */
    tauMoreOptions.pageHideHandler = function()
    {
       handler.removeEventListener("click", clickHandlerBound);
       elSelector.removeEventListener("click", clickElSelectorBound);
       if (tau.support.shape.circle)
       {
          selector.destroy();
       }
    };
    
  4. The circle progress bar is also created and destroyed dynamically as the recording starts and ends:

    /* js/app.js */
    /*
       Change the view when recording starts
       @public
    */
    uiEvents.startRecording = function()
    {
       tauProgress.pageBeforeShowHandler();
    };
    
    /*
       Change the view when recording stops
       @public
    */
    uiEvents.stopRecording = function()
    {
       tauProgress.pageHideHandler();
    };
    

    After figuring out the shape of the screen, the progress bar component is created accordingly:

    /* js/progress.js */
    /*
       Handle events before the progress bar page shows
       @public
    */
    tauProgress.pageBeforeShowHandler = function()
    {
       if (tau.support.shape.circle)
       {
          /* Make a circle progress bar object */
          if (!progressBar)
          {
             progressBar = document.getElementById("circleprogress");
          }
    
          /* Make a circle progress bar object (tau) */
          progressBarWidget = new tau.widget.CircleProgressBar(progressBar,
          {
             size: "full"
          });
       }
    };
    
    /*
       Handle events before the progress bar page hides
       @public
    */
    tauProgress.pageHideHandler = function()
    {
       /* Release the progress bar object */
       if (progressBarWidget)
       {
          clearVariables();
          progressBarWidget.destroy();
       }
    };
    

    The method for changing the status of the progress bar is also handled in the progress.js file:

    /* js/progress.js */
    /*
       Fill in the progress bar as time passes
       @public
    */
    tauProgress.changeProgressValue = function()
    {
       /* Get the current value of progress bar and convert it into float */
       var value = parseFloat(progressBarWidget.value());
    
       /* Circle must be filled full when it reaches the max amount of recording time */
       /* Value increases by 100 / MAX_DURATION SEC every 1 second */
       if (value < app.MAX_DURATION_SEC)
       {
          value += (100 / app.MAX_DURATION_SEC);
       }
       else
       {
          value = app.MAX_DURATION_SEC;
       }
    
       /* Set the new value of the progress bar */
       progressBarWidget.value(value);
    };