<commit_before><template>

  <div id="audio-wrapper">
    <div id="play-and-time">
      <button
        @click="togglePlay"
        class="play-button"
      >
        <mat-svg v-if="isPlaying" class="play-icon" category="av" name="pause"/>
        <mat-svg v-else class="play-icon" category="av" name="play_arrow"/>
      </button>
      <div id="current-time">
        {{ currentMinutes }} : {{ formattedCurrentSec }}
      </div>
      <input
        ref="timebar"
        class="timeline"
        type="range"
        min="0"
        :max="max"
        :value="displayTime"
        @change="seekAudio"/>
      <div id="total-time">
        {{ totalMinutes }} : {{ formattedTotalSec }}
      </div>
    </div>
    <div>
      <button class="audio-button" @click="replay">Replay</button>
      <button class="audio-button" @click="minus20">- 20s</button>
      <button class="audio-button" @click="plus20">+ 20s</button>
    </div>
    <audio
      id="audio"
      ref="audio"
      @timeupdate="updateTime"
      @loadedmetadata="setTotalTime"
      @ended="endPlay"
      :src="defaultFile.storage_url"
    >Your browser cannot play this audio file correctly! Please consider updating your browser to the latest version.</audio>
  </div>

</template>


<script>

  require('html5media/dist/api/1.1.8/html5media');

  module.exports = {

    props: [
      'defaultFile',
    ],

    data: () => ({
      isPlaying: false,
      max: 0,
      displayTime: 0,
      progressStartingPoint: 0,
      lastUpdateTime: 0,
    }),

    computed: {
      totalMinutes() {
        return Math.floor(this.max / 60);
      },

      totalSeconds() {
        return Math.floor(this.max % 60);
      },

      currentSeconds() {
        return Math.floor(this.displayTime % 60);
      },

      currentMinutes() {
        return Math.floor(this.displayTime / 60);
      },

      formattedCurrentSec() {
        return this.formatTime(this.currentSeconds);
      },

      formattedTotalSec() {
        return this.formatTime(this.totalSeconds);
      },
    },

    beforeDestroy() {
      this.recordProgress();
      this.$emit('stopTracking');
    },

    methods: {
      play() {
        this.$refs.audio.play();
        this.isPlaying = true;
        this.recordProgress();
        this.$emit('startTracking');
      },

      pause() {
        this.$refs.audio.pause();
        this.isPlaying = false;
        this.recordProgress();
        this.$emit('stopTracking');
      },

      togglePlay() {
        if (this.$refs.audio.paused) {
          this.play();
        } else {
          this.pause();
        }
      },

      endPlay() {
        this.pause();
      },

      setTotalTime() {
        this.max = this.$refs.audio.duration;
      },

      /* Adds '0' before seconds (e.g. 1:05 instead of 1:5) */
      formatTime(sec) {
        if (sec < 10) {
          return `0${sec}`;
        }
        return sec;
      },

      replay() {
        this.pause();
        this.$refs.audio.currentTime = 0;
        this.play();
      },

      plus20() {
        const sum = this.displayTime + 20;
        /* Pauses audio at end if +20s goes over the audio duration */
        if (sum > this.max) {
          this.$refs.audio.currentTime = this.max;
          return;
        }
        this.$refs.audio.currentTime = sum;
      },

      minus20() {
        let sum = this.displayTime - 20;
        /* Makes sure minimum time is 0 after -20s */
        if (sum < 0) {
          sum = 0;
        }
        this.$refs.audio.currentTime = sum;
      },

      updateTime() {
        this.displayTime = this.$refs.audio.currentTime;
        if (this.displayTime - this.lastUpdateTime >= 5) {
          this.recordProgress();
          this.lastUpdateTime = this.displayTime;
        }
      },

      seekAudio(e) {
        this.displayTime = e.target.value;
        this.$refs.audio.currentTime = this.displayTime;
      },

      recordProgress() {
        this.$emit('updateProgress', Math.max((this.displayTime
          - this.progressStartingPoint) / Math.floor(this.max), 0));
        this.progressStartingPoint = this.$refs.audio.currentTime;
      },
    },
  };

</script>


<style lang="stylus" scoped>

  @require '~kolibri.styles.definitions'

  #audio-wrapper<commit_msg>Guard against updateTime being called after unmount<commit_after><template>

  <div id="audio-wrapper">
    <div id="play-and-time">
      <button
        @click="togglePlay"
        class="play-button"
      >
        <mat-svg v-if="isPlaying" class="play-icon" category="av" name="pause"/>
        <mat-svg v-else class="play-icon" category="av" name="play_arrow"/>
      </button>
      <div id="current-time">
        {{ currentMinutes }} : {{ formattedCurrentSec }}
      </div>
      <input
        ref="timebar"
        class="timeline"
        type="range"
        min="0"
        :max="max"
        :value="displayTime"
        @change="seekAudio"/>
      <div id="total-time">
        {{ totalMinutes }} : {{ formattedTotalSec }}
      </div>
    </div>
    <div>
      <button class="audio-button" @click="replay">Replay</button>
      <button class="audio-button" @click="minus20">- 20s</button>
      <button class="audio-button" @click="plus20">+ 20s</button>
    </div>
    <audio
      id="audio"
      ref="audio"
      @timeupdate="updateTime"
      @loadedmetadata="setTotalTime"
      @ended="endPlay"
      :src="defaultFile.storage_url"
    >Your browser cannot play this audio file correctly! Please consider updating your browser to the latest version.</audio>
  </div>

</template>


<script>

  require('html5media/dist/api/1.1.8/html5media');

  module.exports = {

    props: [
      'defaultFile',
    ],

    data: () => ({
      isPlaying: false,
      max: 0,
      displayTime: 0,
      progressStartingPoint: 0,
      lastUpdateTime: 0,
    }),

    computed: {
      totalMinutes() {
        return Math.floor(this.max / 60);
      },

      totalSeconds() {
        return Math.floor(this.max % 60);
      },

      currentSeconds() {
        return Math.floor(this.displayTime % 60);
      },

      currentMinutes() {
        return Math.floor(this.displayTime / 60);
      },

      formattedCurrentSec() {
        return this.formatTime(this.currentSeconds);
      },

      formattedTotalSec() {
        return this.formatTime(this.totalSeconds);
      },
    },

    beforeDestroy() {
      this.recordProgress();
      this.$emit('stopTracking');
    },

    methods: {
      play() {
        this.$refs.audio.play();
        this.isPlaying = true;
        this.recordProgress();
        this.$emit('startTracking');
      },

      pause() {
        this.$refs.audio.pause();
        this.isPlaying = false;
        this.recordProgress();
        this.$emit('stopTracking');
      },

      togglePlay() {
        if (this.$refs.audio.paused) {
          this.play();
        } else {
          this.pause();
        }
      },

      endPlay() {
        this.pause();
      },

      setTotalTime() {
        this.max = this.$refs.audio.duration;
      },

      /* Adds '0' before seconds (e.g. 1:05 instead of 1:5) */
      formatTime(sec) {
        if (sec < 10) {
          return `0${sec}`;
        }
        return sec;
      },

      replay() {
        this.pause();
        this.$refs.audio.currentTime = 0;
        this.play();
      },

      plus20() {
        const sum = this.displayTime + 20;
        /* Pauses audio at end if +20s goes over the audio duration */
        if (sum > this.max) {
          this.$refs.audio.currentTime = this.max;
          return;
        }
        this.$refs.audio.currentTime = sum;
      },

      minus20() {
        let sum = this.displayTime - 20;
        /* Makes sure minimum time is 0 after -20s */
        if (sum < 0) {
          sum = 0;
        }
        this.$refs.audio.currentTime = sum;
      },

      updateTime(e) {
        // guard against the function being called after component is unmounted
        if (this.$refs.audio === undefined) return;
        this.displayTime = this.$refs.audio.currentTime;
        if (this.displayTime - this.lastUpdateTime >= 5) {
          this.recordProgress();
          this.lastUpdateTime = this.displayTime;
        }
      },

      seekAudio(e) {
        this.displayTime = e.target.value;
        this.$refs.audio.currentTime = this.displayTime;
      },

      recordProgress() {
        this.$emit('updateProgress', Math.max((this.displayTime
          - this.progressStartingPoint) / Math.floor(this.max), 0));
        this.progressStartingPoint = this.$refs.audio.currentTime;
      },
    },
  };

</script>


<style lang="stylus" scoped>

  @require '~kolibri.styles.definitions'

  #audio-wrapper
{'fraction_non_alphanumeric': 0.14903351252430516, 'fraction_numerical': 0.01212398490220748, 'mean_word_length': 1.8810543657331136, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2012215', 'n_tokens_mistral': 2805, 'n_tokens_neox': 2634, 'n_words': 499}