mirror of
				https://github.com/bra1n/townsquare.git
				synced 2025-10-21 16:55:12 +00:00 
			
		
		
		
	Add a timer
This commit is contained in:
		
							parent
							
								
									9bafcc2c61
								
							
						
					
					
						commit
						045f7112e0
					
				
					 9 changed files with 330 additions and 38 deletions
				
			
		| 
						 | 
					@ -1,5 +1,8 @@
 | 
				
			||||||
# Release Notes
 | 
					# Release Notes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Version 2.15.4
 | 
				
			||||||
 | 
					- add timer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Version 2.15.3
 | 
					### Version 2.15.3
 | 
				
			||||||
- add Huntsman/Damsel to list of available characters
 | 
					- add Huntsman/Damsel to list of available characters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,6 +121,10 @@ export default {
 | 
				
			||||||
          if (this.session.isSpectator) return;
 | 
					          if (this.session.isSpectator) return;
 | 
				
			||||||
          this.$refs.menu.toggleNight();
 | 
					          this.$refs.menu.toggleNight();
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
 | 
					        case "t":
 | 
				
			||||||
 | 
					          if (this.session.isSpectator) return;
 | 
				
			||||||
 | 
					          this.$refs.menu.toggleTimer();
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
        case "escape":
 | 
					        case "escape":
 | 
				
			||||||
          this.$store.commit("toggleModal");
 | 
					          this.$store.commit("toggleModal");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										173
									
								
								src/components/CountdownTimer.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								src/components/CountdownTimer.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,173 @@
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="countdown-timer">
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      id="timer"
 | 
				
			||||||
 | 
					      v-bind:style="[
 | 
				
			||||||
 | 
					        remainingSeconds <= 30 ? { color: 'red' } : { color: 'white' }
 | 
				
			||||||
 | 
					      ]"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      {{ formattedMinutes }}:{{ formattedSeconds }}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="timer-control" v-if="!session.isSpectator">
 | 
				
			||||||
 | 
					      <div class="timer-button" @click="startTimer" v-if="!isTicking">
 | 
				
			||||||
 | 
					        <font-awesome-icon icon="play"></font-awesome-icon>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="timer-button" @click="pauseTimer" v-if="isTicking">
 | 
				
			||||||
 | 
					        <font-awesome-icon icon="pause"></font-awesome-icon>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="timer-button" @click="stopTimer">
 | 
				
			||||||
 | 
					        <font-awesome-icon icon="stop"></font-awesome-icon>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="timer-button" @click="addMinute" v-if="!isTicking">
 | 
				
			||||||
 | 
					        <font-awesome-icon icon="plus"></font-awesome-icon>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="timer-button" @click="subtractMinute" v-if="!isTicking">
 | 
				
			||||||
 | 
					        <font-awesome-icon icon="minus"></font-awesome-icon>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import { mapState } from "vuex";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  name: "CountdownTimer",
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    ...mapState(["session"]),
 | 
				
			||||||
 | 
					    remainingSeconds: {
 | 
				
			||||||
 | 
					      get: function() {
 | 
				
			||||||
 | 
					        return this.$store.state.countdownTimer.remainingSeconds;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      set: function(newValue) {
 | 
				
			||||||
 | 
					        this.$store.state.countdownTimer.remainingSeconds = newValue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    totalSeconds: {
 | 
				
			||||||
 | 
					      get: function() {
 | 
				
			||||||
 | 
					        return this.$store.state.countdownTimer.totalSeconds;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      set: function(newValue) {
 | 
				
			||||||
 | 
					        this.$store.state.countdownTimer.totalSeconds = newValue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    isTicking: {
 | 
				
			||||||
 | 
					      get: function() {
 | 
				
			||||||
 | 
					        return this.$store.state.countdownTimer.isTicking;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      set: function(newValue) {
 | 
				
			||||||
 | 
					        this.$store.state.countdownTimer.isTicking = newValue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    formattedMinutes() {
 | 
				
			||||||
 | 
					      let minutes = Math.floor(this.remainingSeconds / 60);
 | 
				
			||||||
 | 
					      if (minutes < 10) {
 | 
				
			||||||
 | 
					        minutes = "0" + minutes;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return minutes;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    formattedSeconds() {
 | 
				
			||||||
 | 
					      let seconds = this.remainingSeconds % 60;
 | 
				
			||||||
 | 
					      if (seconds < 10) {
 | 
				
			||||||
 | 
					        seconds = "0" + seconds;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return seconds;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  updated() {
 | 
				
			||||||
 | 
					    clearInterval(this.timerInterval);
 | 
				
			||||||
 | 
					    if (this.isTicking) {
 | 
				
			||||||
 | 
					      this.timerInterval = setInterval(this.elapseTimer, 1000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  data: () => {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      timerInterval: null
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  methods: {
 | 
				
			||||||
 | 
					    startTimer() {
 | 
				
			||||||
 | 
					      clearInterval(this.timerInterval);
 | 
				
			||||||
 | 
					      if (this.remainingSeconds === 0) {
 | 
				
			||||||
 | 
					        this.remainingSeconds = this.totalSeconds;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.isTicking = true;
 | 
				
			||||||
 | 
					      this.sendTimerUpdate();
 | 
				
			||||||
 | 
					      this.timerInterval = setInterval(this.elapseTimer, 1000);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    pauseTimer() {
 | 
				
			||||||
 | 
					      clearInterval(this.timerInterval);
 | 
				
			||||||
 | 
					      this.isTicking = false;
 | 
				
			||||||
 | 
					      this.sendTimerUpdate();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    stopTimer() {
 | 
				
			||||||
 | 
					      clearInterval(this.timerInterval);
 | 
				
			||||||
 | 
					      this.remainingSeconds = this.totalSeconds;
 | 
				
			||||||
 | 
					      this.pauseTimer();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    sendTimerUpdate() {
 | 
				
			||||||
 | 
					      if (this.session.isSpectator) return;
 | 
				
			||||||
 | 
					      let payload = {
 | 
				
			||||||
 | 
					        remainingSeconds: this.remainingSeconds,
 | 
				
			||||||
 | 
					        totalSeconds: this.totalSeconds,
 | 
				
			||||||
 | 
					        isTicking: this.isTicking
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      this.$store.commit("session/distributeTimerAction", payload);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    elapseTimer() {
 | 
				
			||||||
 | 
					      if (this.remainingSeconds <= 0) {
 | 
				
			||||||
 | 
					        clearInterval(this.timerInterval);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.remainingSeconds--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Update local state on ST, so if a player joins while timer is ticking, they will get updated timer state.
 | 
				
			||||||
 | 
					      if (!this.session.isSpectator) {
 | 
				
			||||||
 | 
					        let payload = {
 | 
				
			||||||
 | 
					          remainingSeconds: this.remainingSeconds,
 | 
				
			||||||
 | 
					          totalSeconds: this.totalSeconds,
 | 
				
			||||||
 | 
					          isTicking: this.isTicking
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        this.$store.commit("session/updateTimerState", payload);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    addMinute() {
 | 
				
			||||||
 | 
					      this.totalSeconds += 60;
 | 
				
			||||||
 | 
					      this.remainingSeconds += 60;
 | 
				
			||||||
 | 
					      this.sendTimerUpdate();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    subtractMinute() {
 | 
				
			||||||
 | 
					      this.totalSeconds = Math.max(0, this.totalSeconds - 60);
 | 
				
			||||||
 | 
					      this.remainingSeconds = Math.max(0, this.remainingSeconds - 60);
 | 
				
			||||||
 | 
					      this.sendTimerUpdate();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					.countdown-timer {
 | 
				
			||||||
 | 
					  border-color: white;
 | 
				
			||||||
 | 
					  border-style: solid;
 | 
				
			||||||
 | 
					  border-width: thick;
 | 
				
			||||||
 | 
					  border-radius: 10px;
 | 
				
			||||||
 | 
					  padding: 5px 5px 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.timer-control {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: row;
 | 
				
			||||||
 | 
					  align-items: flex-start;
 | 
				
			||||||
 | 
					  justify-content: space-around;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.timer-button {
 | 
				
			||||||
 | 
					  margin: 0 5px 0 5px;
 | 
				
			||||||
 | 
					  filter: drop-shadow(0 2px 1px black);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#timer {
 | 
				
			||||||
 | 
					  font-weight: bold;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  text-shadow: 0 2px 1px black, 0 -2px 1px black, 2px 0 1px black,
 | 
				
			||||||
 | 
					    -2px 0 1px black;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
| 
						 | 
					@ -138,6 +138,10 @@
 | 
				
			||||||
              Send Characters
 | 
					              Send Characters
 | 
				
			||||||
              <em><font-awesome-icon icon="theater-masks"/></em>
 | 
					              <em><font-awesome-icon icon="theater-masks"/></em>
 | 
				
			||||||
            </li>
 | 
					            </li>
 | 
				
			||||||
 | 
					            <li v-if="!session.isSpectator" @click="toggleTimer">
 | 
				
			||||||
 | 
					              Toggle timer
 | 
				
			||||||
 | 
					              <em>[T]</em>
 | 
				
			||||||
 | 
					            </li>
 | 
				
			||||||
            <li
 | 
					            <li
 | 
				
			||||||
              v-if="session.voteHistory.length || !session.isSpectator"
 | 
					              v-if="session.voteHistory.length || !session.isSpectator"
 | 
				
			||||||
              @click="toggleModal('voteHistory')"
 | 
					              @click="toggleModal('voteHistory')"
 | 
				
			||||||
| 
						 | 
					@ -345,6 +349,9 @@ export default {
 | 
				
			||||||
        this.$store.commit("session/setMarkedPlayer", -1);
 | 
					        this.$store.commit("session/setMarkedPlayer", -1);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    toggleTimer() {
 | 
				
			||||||
 | 
					      this.$store.commit("toggleTimer");
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    ...mapMutations([
 | 
					    ...mapMutations([
 | 
				
			||||||
      "toggleGrimoire",
 | 
					      "toggleGrimoire",
 | 
				
			||||||
      "toggleMenu",
 | 
					      "toggleMenu",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,12 @@
 | 
				
			||||||
      </ul>
 | 
					      </ul>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="fabled" :class="{ closed: !isFabledOpen }" v-if="fabled.length">
 | 
					    <div id="top-left">
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        class="fabled"
 | 
				
			||||||
 | 
					        :class="{ closed: !isFabledOpen }"
 | 
				
			||||||
 | 
					        v-if="fabled.length"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
        <h3>
 | 
					        <h3>
 | 
				
			||||||
          <span>Fabled</span>
 | 
					          <span>Fabled</span>
 | 
				
			||||||
          <font-awesome-icon icon="times-circle" @click.stop="toggleFabled" />
 | 
					          <font-awesome-icon icon="times-circle" @click.stop="toggleFabled" />
 | 
				
			||||||
| 
						 | 
					@ -81,6 +86,9 @@
 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <CountdownTimer v-if="grimoire.isTimerEnabled" />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <ReminderModal :player-index="selectedPlayer"></ReminderModal>
 | 
					    <ReminderModal :player-index="selectedPlayer"></ReminderModal>
 | 
				
			||||||
    <RoleModal :player-index="selectedPlayer"></RoleModal>
 | 
					    <RoleModal :player-index="selectedPlayer"></RoleModal>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
| 
						 | 
					@ -90,6 +98,7 @@
 | 
				
			||||||
import { mapGetters, mapState } from "vuex";
 | 
					import { mapGetters, mapState } from "vuex";
 | 
				
			||||||
import Player from "./Player";
 | 
					import Player from "./Player";
 | 
				
			||||||
import Token from "./Token";
 | 
					import Token from "./Token";
 | 
				
			||||||
 | 
					import CountdownTimer from "./CountdownTimer";
 | 
				
			||||||
import ReminderModal from "./modals/ReminderModal";
 | 
					import ReminderModal from "./modals/ReminderModal";
 | 
				
			||||||
import RoleModal from "./modals/RoleModal";
 | 
					import RoleModal from "./modals/RoleModal";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,6 +106,7 @@ export default {
 | 
				
			||||||
  components: {
 | 
					  components: {
 | 
				
			||||||
    Player,
 | 
					    Player,
 | 
				
			||||||
    Token,
 | 
					    Token,
 | 
				
			||||||
 | 
					    CountdownTimer,
 | 
				
			||||||
    RoleModal,
 | 
					    RoleModal,
 | 
				
			||||||
    ReminderModal
 | 
					    ReminderModal
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					@ -394,16 +404,32 @@ export default {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/***** Demon bluffs / Fabled *******/
 | 
					#top-left {
 | 
				
			||||||
#townsquare > .bluffs,
 | 
					 | 
				
			||||||
#townsquare > .fabled {
 | 
					 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 10px;
 | 
				
			||||||
 | 
					  left: 10px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					  align-items: flex-start;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***** Demon bluffs / Fabled / Countdown Timer *******/
 | 
				
			||||||
 | 
					#townsquare > .bluffs,
 | 
				
			||||||
 | 
					#top-left > .fabled,
 | 
				
			||||||
 | 
					#top-left > .countdown-timer {
 | 
				
			||||||
  &.bluffs {
 | 
					  &.bluffs {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
    bottom: 10px;
 | 
					    bottom: 10px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  &.fabled {
 | 
					  &.fabled {
 | 
				
			||||||
    top: 10px;
 | 
					    width: 100%;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  &.countdown-timer {
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  margin: 5px 0 0 0;
 | 
				
			||||||
  left: 10px;
 | 
					  left: 10px;
 | 
				
			||||||
  background: rgba(0, 0, 0, 0.5);
 | 
					  background: rgba(0, 0, 0, 0.5);
 | 
				
			||||||
  border-radius: 10px;
 | 
					  border-radius: 10px;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,8 +27,12 @@ const faIcons = [
 | 
				
			||||||
  "Heartbeat",
 | 
					  "Heartbeat",
 | 
				
			||||||
  "Image",
 | 
					  "Image",
 | 
				
			||||||
  "Link",
 | 
					  "Link",
 | 
				
			||||||
 | 
					  "Minus",
 | 
				
			||||||
  "MinusCircle",
 | 
					  "MinusCircle",
 | 
				
			||||||
 | 
					  "Pause",
 | 
				
			||||||
  "PeopleArrows",
 | 
					  "PeopleArrows",
 | 
				
			||||||
 | 
					  "Play",
 | 
				
			||||||
 | 
					  "Plus",
 | 
				
			||||||
  "PlusCircle",
 | 
					  "PlusCircle",
 | 
				
			||||||
  "Question",
 | 
					  "Question",
 | 
				
			||||||
  "Random",
 | 
					  "Random",
 | 
				
			||||||
| 
						 | 
					@ -37,6 +41,7 @@ const faIcons = [
 | 
				
			||||||
  "SearchPlus",
 | 
					  "SearchPlus",
 | 
				
			||||||
  "Skull",
 | 
					  "Skull",
 | 
				
			||||||
  "Square",
 | 
					  "Square",
 | 
				
			||||||
 | 
					  "Stop",
 | 
				
			||||||
  "TheaterMasks",
 | 
					  "TheaterMasks",
 | 
				
			||||||
  "Times",
 | 
					  "Times",
 | 
				
			||||||
  "TimesCircle",
 | 
					  "TimesCircle",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,9 +105,15 @@ export default new Vuex.Store({
 | 
				
			||||||
      isStatic: false,
 | 
					      isStatic: false,
 | 
				
			||||||
      isMuted: false,
 | 
					      isMuted: false,
 | 
				
			||||||
      isImageOptIn: false,
 | 
					      isImageOptIn: false,
 | 
				
			||||||
 | 
					      isTimerEnabled: false,
 | 
				
			||||||
      zoom: 0,
 | 
					      zoom: 0,
 | 
				
			||||||
      background: ""
 | 
					      background: ""
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    countdownTimer: {
 | 
				
			||||||
 | 
					      totalSeconds: 300,
 | 
				
			||||||
 | 
					      remainingSeconds: 300,
 | 
				
			||||||
 | 
					      isTicking: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    modals: {
 | 
					    modals: {
 | 
				
			||||||
      edition: false,
 | 
					      edition: false,
 | 
				
			||||||
      fabled: false,
 | 
					      fabled: false,
 | 
				
			||||||
| 
						 | 
					@ -171,6 +177,7 @@ export default new Vuex.Store({
 | 
				
			||||||
    toggleNight: toggle("isNight"),
 | 
					    toggleNight: toggle("isNight"),
 | 
				
			||||||
    toggleGrimoire: toggle("isPublic"),
 | 
					    toggleGrimoire: toggle("isPublic"),
 | 
				
			||||||
    toggleImageOptIn: toggle("isImageOptIn"),
 | 
					    toggleImageOptIn: toggle("isImageOptIn"),
 | 
				
			||||||
 | 
					    toggleTimer: toggle("isTimerEnabled"),
 | 
				
			||||||
    toggleModal({ modals }, name) {
 | 
					    toggleModal({ modals }, name) {
 | 
				
			||||||
      if (name) {
 | 
					      if (name) {
 | 
				
			||||||
        modals[name] = !modals[name];
 | 
					        modals[name] = !modals[name];
 | 
				
			||||||
| 
						 | 
					@ -260,6 +267,14 @@ export default new Vuex.Store({
 | 
				
			||||||
        state.edition = edition;
 | 
					        state.edition = edition;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      state.modals.edition = false;
 | 
					      state.modals.edition = false;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set timer state
 | 
				
			||||||
 | 
					     * @param state
 | 
				
			||||||
 | 
					     * @param payload Object with keys: `remainingSeconds`, `totalSeconds`, and `isTicking`
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    setTimerState(state, payload) {
 | 
				
			||||||
 | 
					      state.countdownTimer = payload;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  plugins: [persistence, socket]
 | 
					  plugins: [persistence, socket]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,12 @@ const state = () => ({
 | 
				
			||||||
  voteHistory: [],
 | 
					  voteHistory: [],
 | 
				
			||||||
  markedPlayer: -1,
 | 
					  markedPlayer: -1,
 | 
				
			||||||
  isVoteHistoryAllowed: true,
 | 
					  isVoteHistoryAllowed: true,
 | 
				
			||||||
  isRolesDistributed: false
 | 
					  isRolesDistributed: false,
 | 
				
			||||||
 | 
					  countdownTimer: {
 | 
				
			||||||
 | 
					    totalSeconds: 300,
 | 
				
			||||||
 | 
					    remainingSeconds: 300,
 | 
				
			||||||
 | 
					    isTicking: false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getters = {};
 | 
					const getters = {};
 | 
				
			||||||
| 
						 | 
					@ -94,6 +99,12 @@ const mutations = {
 | 
				
			||||||
  clearVoteHistory(state) {
 | 
					  clearVoteHistory(state) {
 | 
				
			||||||
    state.voteHistory = [];
 | 
					    state.voteHistory = [];
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  updateTimerState(state, payload) {
 | 
				
			||||||
 | 
					    state.countdownTimer = payload;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  distributeTimerAction(state, payload) {
 | 
				
			||||||
 | 
					    state.countdownTimer = payload;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Store a vote with and without syncing it to the live session.
 | 
					   * Store a vote with and without syncing it to the live session.
 | 
				
			||||||
   * This is necessary in order to prevent infinite voting loops.
 | 
					   * This is necessary in order to prevent infinite voting loops.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -205,6 +205,13 @@ class LiveSession {
 | 
				
			||||||
      case "pronouns":
 | 
					      case "pronouns":
 | 
				
			||||||
        this._updatePlayerPronouns(params);
 | 
					        this._updatePlayerPronouns(params);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					      case "timer":
 | 
				
			||||||
 | 
					        this._handleTimerAction(params);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case "isTimerEnabled":
 | 
				
			||||||
 | 
					        if (!this._isSpectator) return;
 | 
				
			||||||
 | 
					        this._store.commit("toggleTimer", params);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -284,6 +291,8 @@ class LiveSession {
 | 
				
			||||||
        isVoteInProgress: session.isVoteInProgress,
 | 
					        isVoteInProgress: session.isVoteInProgress,
 | 
				
			||||||
        markedPlayer: session.markedPlayer,
 | 
					        markedPlayer: session.markedPlayer,
 | 
				
			||||||
        fabled: fabled.map(f => (f.isCustom ? f : { id: f.id })),
 | 
					        fabled: fabled.map(f => (f.isCustom ? f : { id: f.id })),
 | 
				
			||||||
 | 
					        isTimerEnabled: grimoire.isTimerEnabled,
 | 
				
			||||||
 | 
					        countdownTimer: session.countdownTimer,
 | 
				
			||||||
        ...(session.nomination ? { votes: session.votes } : {})
 | 
					        ...(session.nomination ? { votes: session.votes } : {})
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -307,7 +316,9 @@ class LiveSession {
 | 
				
			||||||
      lockedVote,
 | 
					      lockedVote,
 | 
				
			||||||
      isVoteInProgress,
 | 
					      isVoteInProgress,
 | 
				
			||||||
      markedPlayer,
 | 
					      markedPlayer,
 | 
				
			||||||
      fabled
 | 
					      fabled,
 | 
				
			||||||
 | 
					      isTimerEnabled,
 | 
				
			||||||
 | 
					      countdownTimer
 | 
				
			||||||
    } = data;
 | 
					    } = data;
 | 
				
			||||||
    const players = this._store.state.players.players;
 | 
					    const players = this._store.state.players.players;
 | 
				
			||||||
    // adjust number of players
 | 
					    // adjust number of players
 | 
				
			||||||
| 
						 | 
					@ -365,6 +376,8 @@ class LiveSession {
 | 
				
			||||||
      this._store.commit("players/setFabled", {
 | 
					      this._store.commit("players/setFabled", {
 | 
				
			||||||
        fabled: fabled.map(f => this._store.state.fabled.get(f.id) || f)
 | 
					        fabled: fabled.map(f => this._store.state.fabled.get(f.id) || f)
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					      this._store.commit("toggleTimer", isTimerEnabled);
 | 
				
			||||||
 | 
					      this._store.commit("setTimerState", countdownTimer);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -668,6 +681,25 @@ class LiveSession {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Distribute new timer action to each player.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  distributeTimerAction(payload) {
 | 
				
			||||||
 | 
					    if (this._isSpectator) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this._send("timer", payload);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Handle a timer action.
 | 
				
			||||||
 | 
					   * @param payload
 | 
				
			||||||
 | 
					   * @private
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  _handleTimerAction(payload) {
 | 
				
			||||||
 | 
					    this._store.commit("setTimerState", payload);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * A player nomination. ST only
 | 
					   * A player nomination. ST only
 | 
				
			||||||
   * This also syncs the voting speed to the players.
 | 
					   * This also syncs the voting speed to the players.
 | 
				
			||||||
| 
						 | 
					@ -703,6 +735,14 @@ class LiveSession {
 | 
				
			||||||
    this._send("isNight", this._store.state.grimoire.isNight);
 | 
					    this._send("isNight", this._store.state.grimoire.isNight);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Send the isTimerEnabled status. ST only
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  setIsTimerEnabled() {
 | 
				
			||||||
 | 
					    if (this._isSpectator) return;
 | 
				
			||||||
 | 
					    this._send("isTimerEnabled", this._store.state.grimoire.isTimerEnabled);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Send the isVoteHistoryAllowed state. ST only
 | 
					   * Send the isVoteHistoryAllowed state. ST only
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
| 
						 | 
					@ -859,6 +899,11 @@ export default store => {
 | 
				
			||||||
          session.distributeRoles();
 | 
					          session.distributeRoles();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					      case "session/distributeTimerAction":
 | 
				
			||||||
 | 
					        if (payload) {
 | 
				
			||||||
 | 
					          session.distributeTimerAction(payload);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
      case "session/nomination":
 | 
					      case "session/nomination":
 | 
				
			||||||
      case "session/setNomination":
 | 
					      case "session/setNomination":
 | 
				
			||||||
        session.nomination(payload);
 | 
					        session.nomination(payload);
 | 
				
			||||||
| 
						 | 
					@ -914,6 +959,9 @@ export default store => {
 | 
				
			||||||
          session.sendPlayer(payload);
 | 
					          session.sendPlayer(payload);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					      case "toggleTimer":
 | 
				
			||||||
 | 
					        session.setIsTimerEnabled();
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue