iRec guardar cambios entrevista - CGastrell/phonegap GitHub Wiki

Otro de los problemas detectados es que no estamos guardando cambios en una revision, es decir, agregamos tags pero estos no quedan guardados. Esto es porque, si bien agregamos los tags en la entrevista que es un item del array entrevistas.lista, nunca volvemos a guardar este array en el archivo entrevistas.json. Para corregir esto vamos a volver a modificar el comportamiento del boton volver de la pagina #revision.

Funcionalidad

Para lograr la funcionalidad que queremos debemos, primero, decidir como y cuando guardaremos la entrevista. Nuestras opciones son:

  • de prepo: es decir, si hacemos click/tap sobre el boton volver guardamos los cambios y luego nos dirijiremos a #home
  • preguntaremos al usuario si desea guardar los cambios

Particularmente me gusta mas darle la opcion al usuario, asi que en este caso vamos a confirmar si desea guardar los cambios. Sientanse libres de no darle la opcion y guardar los cambios en cuanto toquemos el boton de volver.

Casos

Ahora bien, entre los casos que se me ocurren estan estos:

  • el usuario hace click/tap sobre el boton volver y:
    • no hay cambios en la entrevista: redirigimos a #home (esto ya lo hicimos)
    • hay cambios en la entrevista, preguntamos al usuario si desea guardar los cambios:
      • el usuario acepta:
        • guardamos las entrevistas
        • redirigimos a #home
      • el usuario cancela:
        • redirigimos a #home

Con esto en mente vamos a necesitar saber cuando hubo un cambio en la entrevista durante la revision. Para esto vamos a tener que modificar revisionApi. Entre las propiedades de revisionApi vamos a agregar una variable que solo sera true cuando haya una modificacion. Usualmente se denomina dirty a este tipo de marcas, asi que entre las propiedades que tiene revisionApi vamos a agregar (muestro todas las propiedades iniciales, solo deben agregar la que se llama dirty):

  playTime: 0,
  mediaStartDate: 0,
  dirty: false, // <-- esta
  mediaDuration: 0,
  entrevista: null,
  colorTagPasado: '#84EC61',
  colorTagPendiente: '#f6f6f6',
  isPlaying: false,
  interval: null,
  currentTime: $('#currentTime').text("00:00"),

Tambien la vamos a volver a false en la funcion revisionApi.reset():

  reset: function(){
    if(revisionApi.isPlaying) {
      revisionApi.pausa();
    }
    if(revisionApi.audio) {
      revisionApi.audio.release();
    }
    revisionApi.mediaStartDate = 0;
    revisionApi.mediaDuration = 0;
    revisionApi.playTime = 0;
    revisionApi.interval = null;
    revisionApi.audio = null;
    revisionApi.playTime = 0;
    revisionApi.entrevista = null;
    revisionApi.isPlaying = false;
    revisionApi.dirty = false; // <-- aca!
    revisionApi.currentTime.text("00:00");
  },

Ahora solo resta convertirla en true.

Cuando?

En el momento en que agreguemos un tag, es decir, en el click handler del boton de agregar un tag.

Donde?

La funcionalidad del boton de agregar un tag esta en la funcion revisionApi.createTagButton(), recuerdan?

  createTagButton: function(ref) {
    var button = $('<button />')
      .addClass("ui-btn ui-btn-inline ui-mini")
      .text('+')
      .click(function(e){
        var d = new Date(revisionApi.entrevista.start);
        d.setSeconds(d.getSeconds() + revisionApi.playTime);
        revisionApi.entrevista.tags.push({ref: ref, time: d});
        $(this).parent().append(revisionApi.createSeekButton(d));
      });
    return button;
  },

Fijense como creamos el elemento y le damos la funcionalidad que tendra cuando agregamos el click handler en la llamada click(). Entonces vamos a agregar (nuevamente, incluyo todo el codigo, solo agreguen la linea que corresponde):

  createTagButton: function(ref) {
    var button = $('<button />')
      .addClass("ui-btn ui-btn-inline ui-mini")
      .text('+')
      .click(function(e){
        var d = new Date(revisionApi.entrevista.start);
        d.setSeconds(d.getSeconds() + revisionApi.playTime);
        revisionApi.dirty = true; // <-- aca!
        revisionApi.entrevista.tags.push({ref: ref, time: d});
        $(this).parent().append(revisionApi.createSeekButton(d));
      });
    return button;
  },

A partir de este cambio, cuando agreguemos un tag en una revision, ya sabremos si la revision tuvo un cambio o no. Volvamos a la funcionalidad del boton volver (redundancy check).

Asi lo dejamos hace unos minutos:

  $('a[href="#home"]', '#revision').on('click',function(e){
    e.preventDefault();

    if(revisionApi.isPlaying) {
      revisionApi.pausa();
      revisionApi.reset();
    }
  });

Ahora podemos empezar a reflejar los casos que definimos antes y, como vamos a trabajar con algo que no sabemos cuanto puede tardar, lo primero sera mostrar el spinner:

  $('a[href="#home"]', '#revision').on('click',function(e){
    e.preventDefault();
    $.mobile.loading('show'); // <-- spinner

    if(revisionApi.isPlaying) {
      revisionApi.stop();
    }

    if(revisionApi.dirty) {
      // codigo si hubo cambios
    }else{
      // codigo si NO hubo cambios
    }
  });

La parte facil es el codigo sin cambios:

  $('a[href="#home"]', '#revision').on('click',function(e){
    e.preventDefault();
    $.mobile.loading('show'); // <-- spinner

    if(revisionApi.isPlaying) {
      revisionApi.stop();
    }

    if(revisionApi.dirty) {
      // codigo si hubo cambios
    }else{
      // codigo si NO hubo cambios
      revisionApi.reset(); // <-- reset, ya que estamos
      $.mobile.navigate('#home'); // <-- vamos a #home
      $.mobile.loading('hide'); // <-- fuera el spinner
    }
  });

Pero si hubo cambios queremos confirmar con el usuario, entonces usamos confirm que, si recuerdan, es como alert() y detiene el codigo hasta obtener un resultado. Entonces, si revisionApi.dirty es true, usamos confirm y almacenamos la respuesta en una variable r:

  $('a[href="#home"]', '#revision').on('click',function(e){
    e.preventDefault();
    $.mobile.loading('show'); // <-- spinner

    if(revisionApi.isPlaying) {
      revisionApi.stop();
    }

    if(revisionApi.dirty) {
      // codigo si hubo cambios
      var r = confirm('Hay cambios sin guardar en la entrevista, desea guardarlos?');
      if(r) {
        // el usuario quiere guardar los cambios
      }else{
        // el usuario quiere DESCARTAR los cambios
      }
    }else{
      // codigo si NO hubo cambios
      revisionApi.reset(); // <-- reset, ya que estamos
      $.mobile.navigate('#home'); // <-- vamos a #home
      $.mobile.loading('hide'); // <-- fuera el spinner
    }
  });

Ya casi estamos. Ahora es tiempo de usar nuestras API's. Cuando hicimos entrevistas hicimos un metodo entrevistas.guardarEntrevistas(), que toma el array entrevistas.lista y lo guarda en el archivo de entrevistas entrevistas.json. Como los cambios que hacemos en la entrevista los hacemos por referencia significa que en entrevistas.lista ya tenemos los cambios, solo hay que guardarlos. Y como nos adelantamos y supusimos que esta podia ser una operacion que demore, entrevistas.guardarEntrevistas() es una funcion asincronica. Entonces, vamos a llamar a entrevistas.guardarEntrevistas() y le vamos a pasar un callback para ejecutar cuando termine:

  $('a[href="#home"]', '#revision').on('click',function(e){
    e.preventDefault();
    $.mobile.loading('show'); // <-- spinner

    if(revisionApi.isPlaying) {
      revisionApi.stop();
    }

    if(revisionApi.dirty) {
      // codigo si hubo cambios
      var r = confirm('Hay cambios sin guardar en la entrevista, desea guardarlos?');
      if(r) {
        // el usuario quiere guardar los cambios
        entrevistas.guardarEntrevistas(function(){
          revisionApi.reset(); // <-- reset, ya que estamos
          $.mobile.navigate('#home'); // <-- vamos a #home
          $.mobile.loading('hide'); // <-- fuera el spinner
        });
      }else{
        // el usuario quiere DESCARTAR los cambios
      }
    }else{
      // codigo si NO hubo cambios
      revisionApi.reset(); // <-- reset, ya que estamos
      $.mobile.navigate('#home'); // <-- vamos a #home
      $.mobile.loading('hide'); // <-- fuera el spinner
    }
  });

Y por ultimo, si el usuario quiere descartar los cambios, debemos re-inicializar entrevistas. Por que? Porque la entrevista que estabamos revisionando ya esta modificada y habra que cargarla de nuevo desde el archivo, entonces:

  $('a[href="#home"]', '#revision').on('click',function(e){
    e.preventDefault();
    $.mobile.loading('show'); // <-- spinner

    if(revisionApi.isPlaying) {
      revisionApi.stop();
    }

    if(revisionApi.dirty) {
      // codigo si hubo cambios
      var r = confirm('Hay cambios sin guardar en la entrevista, desea guardarlos?');
      if(r) {
        // el usuario quiere guardar los cambios
        entrevistas.guardarEntrevistas(function(){
          revisionApi.reset(); // <-- reset, ya que estamos
          $.mobile.navigate('#home'); // <-- vamos a #home
          $.mobile.loading('hide'); // <-- fuera el spinner
        });
      }else{
        // el usuario quiere DESCARTAR los cambios
        entrevistas.initialize(); // <-- reinit
        revisionApi.reset();
        $.mobile.navigate('#home');
        $.mobile.loading('hide');
      }
    }else{
      // codigo si NO hubo cambios
      revisionApi.reset(); // <-- reset, ya que estamos
      $.mobile.navigate('#home'); // <-- vamos a #home
      $.mobile.loading('hide'); // <-- fuera el spinner
    }
  });

El codigo podria estar mejor optimizado, pero vale igual.

Luego de esto vamos a agregar la funcionalidad que faltaba en el boton de stop de la revision

⚠️ **GitHub.com Fallback** ⚠️