Skip to content

iRec guardar cambios entrevista

Christian Gastrell edited this page Jul 7, 2015 · 2 revisions

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

  1. Repaso y conceptos basicos
  2. Ejercicios para repasar
  3. Problematica de desarrollo mobile
  4. Phonegap
  5. Requerimientos e instalacion
  6. Phonegap CLI
  7. [Primeros ejercicios con Phonegap](Ejercicio Phonegap)
  8. Plugins
  9. Hello world
  10. Estructura de un proyecto Phonegap
  11. Plugin Device
  12. Debugging
  13. Incorporando un framework CSS
  14. Plugin Vibration
  15. Sumando partes
  16. Plugin Battery Status
  17. Un poco de jQuery
  18. jQuery Mobile
  19. Navegacion
  20. Plugin Dashboard
  21. Revision de Plugin Dashboard
  22. Paginas extra
  23. ToDo
  24. Persistencia
  25. ToDo Persistente
  26. Plugin Camera
  27. Opciones de camara
  28. App Mi Galeria
  29. Revision de Galeria
  30. Plugin File
  31. Escribir y leer texto
  32. Escribir archivos binarios
  33. Guardando fotos
  34. Debugger: weinre
  35. Inspeccionar con weinre
  36. Phonegap Developer App
  37. Refactor de apps
  38. Plugin Media
  39. Pruebas con audio
  40. Control y monitoreo de audio
  41. Encapsular play/pausa
  42. Hacks
  43. Formato de tiempos
  44. Grabar y reproducir
  45. Proyecto Integrador
  46. Revision de interfaz
  47. Interfaz basica
  48. Entrevista: modelo
  49. Funcionalidad: revision
  50. Seleccion de framework
  51. iRec: navegacion
  52. iRec: fileApi
  53. iRec: guias
  54. iRec: entrevistas
  55. iRec: recordApi
  56. iRec: helpers
  57. iRec: mediaApi
  58. iRec: inicializar paginas
  59. iRec: refactor
  60. iRec: mediaApi refactor
  61. iRec: recordApi refactor
  62. iRec: helpers
  63. iRec: guias.js
  64. iRec: entrevistas.js
  65. iRec: crear guias
  66. iRec: re-inicializando
  67. iRec: re-ordenando
  68. iRec: pendientes
  69. iRec: reporte ux
  70. iRec:revision: volver
  71. iRec:entrevista: volver
  72. iRec:revision: cambios
  73. iRec:revision: stop
  74. iRec:revision: Rew 10"
  75. iRec:revision: tag Go
  76. iRec: limpieza
  77. Firma de apps
  78. Android
  79. Generacion de key
  80. Firma de apk
  81. Alineacion de zip
  82. Firmar con Phonegap
  83. iOS
  84. Detalles finales
  85. Config.xml
  86. Iconos
  87. Splash
Clone this wiki locally