Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change volume icon and add click to toggle mute #166

Merged
merged 8 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/components/Icon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,31 @@ export default class Icon extends Vue {
return `
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2V0H16V2H0ZM7 8H4L8 4L12 8H9V18H7V8Z" />
`;
case "volumeMute":
this.viewBox = "0 0 50 50";
return `
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M3.886 0L0 3.889l12.018 12.024-.8.827H.193v16.547h11.025L25 47.077V28.902L36.522
40.43c-1.792 1.352-3.804 2.427-6.01 3.062v5.68c3.694-.827 7.084-2.537 9.951-4.826L46.113
50 50 46.111 3.886 0zm15.601 33.756l-5.981-5.985h-7.8v-5.515h7.8l2.426-2.427 3.555
3.557v10.37zm23.677-2.289a19.248 19.248 0 001.13-6.453c0-8.743-5.816-16.134-13.781-18.505V.827c11.053
2.51 19.294 12.383 19.294 24.187 0 3.833-.882 7.446-2.425 10.673l-4.218-4.22zM25 2.951l-5.182 5.185L25
13.32V2.95zM30.513 13.9c4.08 2.04 6.89 6.232 6.89 11.114 0 .22-.027.441-.055.662l-6.835-6.84V13.9z"
/>
`;
case "volumeMed":
this.viewBox = "0 0 38 46";
return `
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M0 14.448v17.104h11.111L25 45.805V.195L11.111
14.448H0zm19.444-.484v18.073l-6.027-6.186H5.556V20.15h7.86l6.028-6.186zm11.111-2.452C34.667
13.622 37.5 17.954 37.5 23c0 5.046-2.833 9.379-6.945 11.46V11.512z"
/>
`;
case "volumeMax":
this.viewBox = "0 0 18 18";
return `
Expand Down
91 changes: 50 additions & 41 deletions src/components/ui/Button.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
<template>
<div class="btnWrapper" @[clickEvent]="$emit('click')">
<div class="btnWrapper">
<button v-if="combinedInfo" id="outlined" class="infoBtn">
<slot></slot>
</button>

<button ref="mainBtn" class="mainBtn">
<Icon v-if="icon" :i="icon" />

<span v-if="text">{{ text }}</span>

<div v-if="slider" ref="sliderBar" class="sliderBar"></div>
<div @[clickEvent]="$emit('click')">
<Icon v-if="icon" :i="icon" />

<span v-if="text">{{ text }}</span>
</div>

<input
v-if="slider"
ref="sliderBar"
class="sliderBar"
type="range"
:min="sliderMin"
:max="sliderMax"
:step="sliderStep"
/>
</button>
</div>
</template>

<script lang="ts">
import { Prop, Component, Vue } from "vue-property-decorator";
import noUiSlider from "nouislider";
import Icon from "./../Icon.vue";

@Component({
Expand All @@ -32,18 +41,29 @@ export default class Button extends Vue {
@Prop() combinedInfo: boolean;
@Prop() outlined: boolean;
@Prop({ default: false }) slider: boolean;
@Prop({ default: 0 }) sliderValue: string;
@Prop({ default: 0 }) sliderMin: number;
@Prop({ default: 100 }) sliderMax: number;
@Prop({ default: 1 }) sliderStep: number;

mainBtn: HTMLButtonElement;
sliderBar: HTMLInputElement;
clickEvent = "click";

mounted() {
this.mainBtn = this.$refs.mainBtn as HTMLButtonElement;
this.sliderBar = this.$refs.sliderBar as HTMLInputElement;

if (this.outlined) this.mainBtn.id += "outlined";
if (this.slider) this.createSlider();
if (this.slider) this.initSlider();

this.updateSliderValue();
}

updated() {
// Update sliderBar value, if slider is enabled and it is updated
this.updateSliderValue();

// Enable/disable button click event
if (this.disabled) {
this.clickEvent = "null";
Expand All @@ -58,39 +78,38 @@ export default class Button extends Vue {
this.mainBtn.classList.add(classToAdd);
}

createSlider() {
initSlider() {
this.addClassToButton("slider");

let slider = this.$refs.sliderBar as noUiSlider.Instance;

noUiSlider.create(slider, {
start: [0.8],
behaviour: "snap",
range: {
min: 0,
max: 1
}
});

slider.noUiSlider.on("update", (value) => {
this.$emit("update", Number(value[0]));
this.sliderBar.addEventListener("input", (value) => {
this.$emit("slider-update", Number((value.target as HTMLInputElement).value));
});

this.mainBtn.addEventListener(
"wheel",
(e) => {
let noSlider = slider.noUiSlider;
let sliderVal = Number(noSlider.get());
let slider = this.sliderBar;
let sliderVal = Number(slider.value);

// Change slider value up/down depending on if wheel was scrolled up/down
if (e.deltaY < 0) {
noSlider.set(sliderVal + 0.1);
slider.value = String(sliderVal + 0.1);
} else {
noSlider.set(sliderVal - 0.1);
slider.value = String(sliderVal - 0.1);
}

// Manually fire input event, because it doesn't do this itself
slider.dispatchEvent(new Event("input"));
},
{ passive: true }
);
}

updateSliderValue() {
if (this.slider && this.sliderBar) {
this.sliderBar.value = String(this.sliderValue);
}
}
}
</script>

Expand Down Expand Up @@ -189,25 +208,15 @@ export default class Button extends Vue {
flex-flow: row;

.sliderBar {
-webkit-appearance: none;
width: 0;
margin: 0;

height: 5px;
transition: width 150ms ease-in-out, margin 150ms ease-in-out;
background: transparent;

::v-deep .noUi-handle {
&::-webkit-slider-thumb {
visibility: hidden;
top: -3px;
right: -6px;
height: 12px;
width: 12px;
}

// Set transition for slider handle to 0ms.
// For some reason 'snap' behaviour doesn't
// work when moving handle by using mouse wheel.
::v-deep .noUi-origin {
transition: transform 0ms ease-in;
}
}

Expand All @@ -218,9 +227,9 @@ export default class Button extends Vue {
&:active {
.sliderBar {
width: 100px;
margin: 0 7px 0 12px;
margin: 0 7px 0 7.5px;

::v-deep .noUi-handle {
&::-webkit-slider-thumb {
visibility: visible;
}
}
Expand Down
24 changes: 23 additions & 1 deletion src/styles/_norm.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ a {
display: none !important;
}

// Default slider styling
// Default nouislider styling
.noUi-target {
&,
* {
Expand Down Expand Up @@ -61,3 +61,25 @@ a {
}
}
}

// Default slider styling
[type="range"] {
outline: none;

&::-webkit-slider-thumb {
-webkit-appearance: none;
height: 12px;
width: 12px;
margin-top: -2px;
background-color: $darkAccentColor;
border: 1px solid $textPrimary;
border-radius: 4px;
cursor: pointer;
}

&::-webkit-slider-runnable-track {
height: 8px;
background-color: $quaternaryColor;
border-radius: 4px;
}
}
36 changes: 35 additions & 1 deletion src/views/VideoPlayer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,16 @@
<div class="controls">
<Button @click="playPause" :icon="playPauseBtnIcon" />

<Button icon="volumeMax" :slider="true" @update="updateVolume" />
<Button
:icon="volumeIcon"
:slider="true"
:sliderValue="volume"
sliderMin="0"
sliderMax="1"
sliderStep="0.01"
@slider-update="updateVolume"
@click="toggleMute"
/>

<Button :text="`${currentVideoTime} / ${maxVideoTime}`" :outlined="true" />

Expand Down Expand Up @@ -76,6 +85,8 @@ export default class VideoPlayer extends Vue {
maxVideoTime = "00:00";
playPauseBtnIcon = "play";
continueBtnCI = false;
volumeIcon = "volumeMax";
volume = 0.8;

/**
* Play/Pause the video.
Expand All @@ -98,6 +109,10 @@ export default class VideoPlayer extends Vue {
* @param volume Volume to set video to.
*/
async updateVolume(volume: number) {
// Update volume var used for volumeBars sliderValue
// So the slider is updated on the volume button.
this.volume = volume;

// Try 3 times to update volume
// First time volume is updated, the video element
// hasn't loaded fully so we need to keep trying until it has.
Expand All @@ -110,6 +125,23 @@ export default class VideoPlayer extends Vue {

await Helpers.sleep(250);
}

// Change volume icon depending on volume
if (this.video.volume == 0) {
this.volumeIcon = "volumeMute";
} else if (this.video.volume < 0.5) {
this.volumeIcon = "volumeMed";
} else {
this.volumeIcon = "volumeMax";
}
}

toggleMute() {
if (this.video.volume > 0) {
this.updateVolume(0);
} else {
this.updateVolume(0.5);
}
}

/**
Expand Down Expand Up @@ -343,11 +375,13 @@ export default class VideoPlayer extends Vue {
updateTotalLengthOfClips(values: string[]) {
let totalLength = 0;
let v = values.map(Number);

// Loop over values in pairs
for (let i = 0, n = v.length; i < n; i += 2) {
// Update totalLength after calculating current pairs length
totalLength += Number((v[i + 1] - v[i]).toFixed(0));
}

// Finally, update actual lengthOfClips variable
this.lengthOfClips = totalLength.toReadableTimeFromSeconds();
}
Expand Down