@saooti/octopus-sdk 29.0.7 → 29.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,155 @@
1
+ <template>
2
+ <router-link
3
+ v-if="isImage && podcastImage"
4
+ :to="podcastShareUrl"
5
+ >
6
+ <img
7
+ :src="podcastImage"
8
+ :alt="$t('Podcast image')"
9
+ class="player-image c-hand"
10
+ >
11
+ </router-link>
12
+ <div
13
+ v-if="!playerError"
14
+ class="play-button-box"
15
+ :class="{
16
+ 'primary-bg': !isLoading,
17
+ 'text-light': !isLoading,
18
+ }"
19
+ @click="switchPausePlay"
20
+ >
21
+ <div
22
+ class="text-light"
23
+ :aria-label="$t('Play')"
24
+ :class="{
25
+ saooti: isPlaying || isPaused,
26
+ 'saooti-play2-bounty': isPaused,
27
+ 'saooti-pause-bounty': isPlaying,
28
+ loading: isLoading,
29
+ }"
30
+ />
31
+ </div>
32
+ <div
33
+ v-if="(isPlaying || isPaused) && (media || isStop)"
34
+ class="play-button-box primary-bg text-light"
35
+ @click="stopPlayer"
36
+ >
37
+ <div
38
+ class="text-light saooti-stop-bounty"
39
+ :aria-label="$t('Stop')"
40
+ />
41
+ </div>
42
+ </template>
43
+
44
+ <script lang="ts">
45
+ import { state } from '../../store/paramStore';
46
+ import { defineComponent } from 'vue';
47
+ import { Media } from '@/store/class/media';
48
+ import { Podcast } from '@/store/class/podcast';
49
+ export default defineComponent({
50
+ name: 'PlayerButtons',
51
+
52
+ props: {
53
+ playerError: { default: false, type: Boolean},
54
+ },
55
+
56
+ data() {
57
+ return {
58
+ };
59
+ },
60
+
61
+ computed: {
62
+ isPlaying(): boolean {
63
+ return 'PLAYING' === this.$store.state.player.status;
64
+ },
65
+ isPaused(): boolean {
66
+ return 'PAUSED' === this.$store.state.player.status;
67
+ },
68
+ isLoading(): boolean {
69
+ return 'LOADING' === this.$store.state.player.status;
70
+ },
71
+ isImage(): string {
72
+ return state.player.image;
73
+ },
74
+ podcastImage(): string{
75
+ if (this.$store.state.player.podcast) return state.player.podcast.imageUrl;
76
+ return '';
77
+ },
78
+ isStop(): boolean{
79
+ return this.$store.state.player.stop;
80
+ },
81
+ media(): undefined|Media{
82
+ return this.$store.state.player.media;
83
+ },
84
+ podcast(): undefined|Podcast{
85
+ return this.$store.state.player.podcast;
86
+ },
87
+
88
+ podcastShareUrl(): any {
89
+ if (this.podcast) {
90
+ return {
91
+ name: 'podcast',
92
+ params: { podcastId: this.podcast.podcastId },
93
+ query: { productor: this.$store.state.filter.organisationId },
94
+ };
95
+ }
96
+ return '';
97
+ },
98
+ },
99
+
100
+ methods: {
101
+ switchPausePlay(): void {
102
+ const audioPlayer: any = document.querySelector('#audio-player');
103
+ if (audioPlayer.paused) {
104
+ this.onPlay();
105
+ } else {
106
+ this.onPause();
107
+ }
108
+ },
109
+ stopPlayer(): void {
110
+ this.$store.commit('playerPlayPodcast');
111
+ },
112
+
113
+ onPlay(): void {
114
+ this.$store.commit('playerPause', false);
115
+ },
116
+ onPause(): void {
117
+ this.$store.commit('playerPause', true);
118
+ },
119
+ },
120
+ })
121
+ </script>
122
+
123
+ <style lang="scss">
124
+ .play-button-box {
125
+ height: 2.5rem;
126
+ width: 2.5rem;
127
+ display: flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+ margin: 0 0.5rem;
131
+ border-radius: 50%;
132
+ font-size: 1.2rem;
133
+ flex-shrink: 0;
134
+ cursor: pointer;
135
+ }
136
+
137
+ .player-container {
138
+ .player-image {
139
+ border-radius: 0.2rem;
140
+ height: 2.4rem;
141
+ width: 2.4rem;
142
+ }
143
+
144
+ }
145
+ /** PHONES*/
146
+ @media (max-width: 450px) {
147
+ .player-container {
148
+ .player-image {
149
+ height: 2rem;
150
+ width: 2rem;
151
+ }
152
+ }
153
+ }
154
+
155
+ </style>
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <div
3
+ v-if="0 !== comments.length && !isPodcastmaker"
4
+ class="timeline-button"
5
+ @click="$emit('update:showTimeline', !showTimeline)"
6
+ >
7
+ <div
8
+ class="saooti-arrow_down saooti-arrow_down-margin"
9
+ :class="showTimeline ? '' : 'arrow-transform'"
10
+ />
11
+ <div>Timeline</div>
12
+ </div>
13
+ <div
14
+ v-if="isClock"
15
+ class="d-flex text-light align-items-center hide-phone"
16
+ >
17
+ <div class="saooti-clock-stud m-2" />
18
+ <div>{{ actualTime }}</div>
19
+ </div>
20
+ </template>
21
+
22
+ <script lang="ts">
23
+ const moment = require('moment');
24
+ import { state } from '../../store/paramStore';
25
+ import { defineComponent } from 'vue';
26
+ import { CommentPodcast } from '@/store/class/comment';
27
+ export default defineComponent({
28
+ name: 'PlayerClockAndTimeline',
29
+
30
+ props: {
31
+ showTimeline: { default: false, type: Boolean},
32
+ comments: { default: ()=>[], type: Array as ()=>Array<CommentPodcast>},
33
+ },
34
+ emits:['update:showTimeline'],
35
+
36
+ data() {
37
+ return {
38
+ actualTime: '' as string,
39
+ };
40
+ },
41
+
42
+ computed: {
43
+ isPodcastmaker(): boolean {
44
+ return state.generalParameters.podcastmaker;
45
+ },
46
+ isClock(): boolean {
47
+ return state.player.clock;
48
+ },
49
+
50
+ },
51
+
52
+ mounted() {
53
+ if (this.isClock) {
54
+ setInterval(() => {
55
+ this.actualTime = moment(new Date()).format('HH:mm:ss');
56
+ }, 1000);
57
+ }
58
+ },
59
+
60
+ })
61
+ </script>
62
+ <style lang="scss">
63
+ @import '../../sass/_variables.scss';
64
+ .player-container {
65
+ .timeline-button {
66
+ background: black;
67
+ padding: 0.1rem;
68
+ border-radius: 50%;
69
+ width: 70px;
70
+ height: 70px;
71
+ font-size: 0.7rem;
72
+ font-weight: bold;
73
+ justify-content: center;
74
+ display: flex;
75
+ flex-direction: column;
76
+ align-items: center;
77
+ cursor: pointer;
78
+ color: $octopus-primary-color;
79
+ margin-left: 0.5rem;
80
+ @media (max-width: 960px) {
81
+ display: none;
82
+ }
83
+ }
84
+ }
85
+ </style>
@@ -0,0 +1,202 @@
1
+ <template>
2
+ <div class="text-light player-grow-content">
3
+ <div class="d-flex">
4
+ <div
5
+ v-if="playerError"
6
+ class="text-warning player-title ms-2 me-2"
7
+ >
8
+ {{ $t('Podcast play error') + ' - ' }}
9
+ </div>
10
+ <div class="flex-grow player-title">
11
+ {{ podcastTitle }}
12
+ </div>
13
+ <div
14
+ v-if="!playerError"
15
+ v-show="!isBarTop"
16
+ class="hide-phone"
17
+ >
18
+ {{ playedTime }} / {{ totalTime }}
19
+ </div>
20
+ </div>
21
+ <div
22
+ v-if="!playerError"
23
+ v-show="!isBarTop"
24
+ class="progress c-hand custom-bg-darkgrey"
25
+ style="height: 3px;"
26
+ @mouseup="seekTo"
27
+ >
28
+ <div
29
+ class="progress-bar custom-bg-grey"
30
+ role="progressbar"
31
+ aria-valuenow="0"
32
+ aria-valuemin="0"
33
+ aria-valuemax="100"
34
+ :style="'width: ' + percentLiveProgress + '%'"
35
+ />
36
+ <div
37
+ class="progress-bar primary-bg"
38
+ role="progressbar"
39
+ aria-valuenow="0"
40
+ aria-valuemin="0"
41
+ aria-valuemax="100"
42
+ :style="'width: ' + percentProgress + '%'"
43
+ />
44
+ <div
45
+ v-if="displayAlertBar"
46
+ class="progress-bar progress-bar-duration bg-danger"
47
+ :style="'left: ' + durationLivePosition + '%'"
48
+ />
49
+ </div>
50
+ <CommentPlayer
51
+ v-if="showTimeline"
52
+ :total-time="totalSecondes"
53
+ :comments="comments"
54
+ />
55
+ </div>
56
+ </template>
57
+
58
+ <script lang="ts">
59
+ import { state } from '../../store/paramStore';
60
+ import DurationHelper from '../../helper/duration';
61
+ import { CommentPodcast } from '@/store/class/comment';
62
+ import { defineComponent, defineAsyncComponent } from 'vue';
63
+ const CommentPlayer = defineAsyncComponent(() => import('../display/comments/CommentPlayer.vue'));
64
+ export default defineComponent({
65
+ name: 'PlayerProgressBar',
66
+
67
+ components: {
68
+ CommentPlayer,
69
+ },
70
+ props: {
71
+ hlsReady: { default: false, type: Boolean},
72
+ showTimeline: { default: false, type: Boolean},
73
+ comments: { default: ()=>[], type: Array as ()=>Array<CommentPodcast>},
74
+ displayAlertBar: { default: false, type: Boolean},
75
+ percentLiveProgress: { default: 0, type: Number},
76
+ durationLivePosition: { default: 0, type: Number},
77
+ playerError: { default: false, type: Boolean},
78
+ listenTime: { default: 0, type: Number},
79
+ notListenTime: { default: 0, type: Number},
80
+ },
81
+ emits: ['update:notListenTime'],
82
+
83
+ data() {
84
+ return {
85
+ };
86
+ },
87
+
88
+ computed: {
89
+ isEmissionName(): string {
90
+ return state.player.emissionName;
91
+ },
92
+ isBarTop(): boolean {
93
+ return state.player.barTop;
94
+ },
95
+ playedTime(): string{
96
+ if (this.$store.state.player.elapsed && this.$store.state.player.elapsed > 0 && this.$store.state.player.total && this.$store.state.player.total > 0) {
97
+ return DurationHelper.formatDuration(
98
+ Math.round(this.$store.state.player.elapsed * this.$store.state.player.total)
99
+ );
100
+ }
101
+ return '--:--';
102
+ },
103
+ percentProgress(): number{
104
+ if(!this.$store.state.player.elapsed){return 0;}
105
+ return this.$store.state.player.elapsed * 100;
106
+ },
107
+ totalTime(): string {
108
+ if (this.$store.state.player.elapsed && this.$store.state.player.elapsed > 0 && this.$store.state.player.total && this.$store.state.player.total > 0)
109
+ return DurationHelper.formatDuration(Math.round(this.$store.state.player.total));
110
+ return '--:--';
111
+ },
112
+ totalSecondes(): number{
113
+ return this.$store.state.player.total;
114
+ },
115
+ podcastTitle(): string {
116
+ if (this.$store.state.player.podcast) {
117
+ if (this.isEmissionName)
118
+ return this.emissionName + ' - ' + this.$store.state.player.podcast.title;
119
+ return this.$store.state.player.podcast.title;
120
+ }
121
+ if (this.$store.state.player.media) return this.$store.state.player.media.title;
122
+ if (this.$store.state.player.live) {
123
+ if (!this.hlsReady)
124
+ return this.$store.state.player.live.title + ' (' + this.$t('Start in a while') + ')';
125
+ return this.$store.state.player.live.title;
126
+ }
127
+ return '';
128
+ },
129
+ emissionName(): string {
130
+ if (this.$store.state.player.podcast) return this.$store.state.player.podcast.emission.name;
131
+ return '';
132
+ },
133
+ },
134
+
135
+
136
+ methods: {
137
+ seekTo(event: { currentTarget: { getBoundingClientRect: () => any; clientWidth: any }; clientX: number }): void {
138
+ const audioPlayer: any = document.querySelector('#audio-player');
139
+ const rect = event.currentTarget.getBoundingClientRect();
140
+ const barWidth = event.currentTarget.clientWidth;
141
+ const x = event.clientX - rect.left;
142
+ const percentPosition = x / barWidth;
143
+ if (percentPosition * 100 >= this.percentLiveProgress) return;
144
+ const seekTime = this.$store.state.player.total * percentPosition;
145
+ if (this.$store.state.player.podcast || this.$store.state.player.live) {
146
+ this.$emit('update:notListenTime',seekTime - this.listenTime);
147
+ }
148
+ audioPlayer.currentTime = seekTime;
149
+ }
150
+ },
151
+ })
152
+ </script>
153
+
154
+ <style lang="scss">
155
+ .player-container {
156
+ .progress {
157
+ align-items: flex-end;
158
+ height: 10px;
159
+ position: relative;
160
+ }
161
+ .progress-bar-duration {
162
+ width: 10px;
163
+ }
164
+ .progress-bar {
165
+ height: 4px;
166
+ position: absolute;
167
+ }
168
+
169
+ .progress.custom-bg-darkgrey {
170
+ background: #555;
171
+ }
172
+
173
+ .progress-bar.custom-bg-grey {
174
+ background: #e9ecef;
175
+ }
176
+
177
+ .player-title,
178
+ .hide-phone {
179
+ font-size: 0.8rem;
180
+ margin: 0 0 5px 0;
181
+ }
182
+ .player-grow-content {
183
+ display: flex;
184
+ flex-grow: 1;
185
+ flex-direction: column;
186
+ flex-shrink: 1;
187
+ flex-basis: 20px;
188
+ overflow: hidden;
189
+ }
190
+ }
191
+ /** PHONES*/
192
+ @media (max-width: 960px) {
193
+ .player-container {
194
+ .player-title {
195
+ font-size: 12px;
196
+ overflow: hidden;
197
+ white-space: nowrap;
198
+ text-overflow: ellipsis;
199
+ }
200
+ }
201
+ }
202
+ </style>
@@ -21,7 +21,7 @@
21
21
 
22
22
  <script lang="ts">
23
23
  import {Popover} from 'bootstrap'
24
- import {defineComponent, onMounted, PropType, ref, watch} from 'vue'
24
+ import {defineComponent, onMounted, PropType, ref} from 'vue'
25
25
  import useEventListener from '../../helper/useEventListener'
26
26
  export default defineComponent({
27
27
  name: 'Popover',
@@ -34,6 +34,7 @@ export default defineComponent({
34
34
  title: {type: String, default: ''},
35
35
  triggers: {type: String as PropType<Popover.Options['trigger']>, default: 'click'},
36
36
  show: {type: Boolean, default: false},
37
+ disable: {type: Boolean, default: false},
37
38
  },
38
39
  emits: ['show', 'shown', 'hide', 'hidden', 'inserted'],
39
40
  setup(props, {emit}) {
@@ -42,7 +43,7 @@ export default defineComponent({
42
43
  const instance = ref<Popover>()
43
44
  const titleRef = ref<HTMLElement>()
44
45
  const contentRef = ref<HTMLElement>()
45
- onMounted(() => {
46
+ function initPopover(){
46
47
  instance.value = new Popover(`#${props.target}`, {
47
48
  container: 'body',
48
49
  trigger: props.triggers,
@@ -58,19 +59,13 @@ export default defineComponent({
58
59
  if (props.show) {
59
60
  instance.value.show()
60
61
  }
61
- })
62
- watch(
63
- () => props.show,
64
- (show, oldVal) => {
65
- if (show !== oldVal) {
66
- if (show) {
67
- instance.value?.show()
68
- } else {
69
- instance.value?.hide()
70
- }
71
- }
62
+ if (props.disable) {
63
+ instance.value.disable()
72
64
  }
73
- )
65
+ }
66
+ onMounted(()=>{
67
+ initPopover();
68
+ })
74
69
  useEventListener(target, 'show.bs.popover', () => emit('show'))
75
70
  useEventListener(target, 'shown.bs.popover', () => emit('shown'))
76
71
  useEventListener(target, 'hide.bs.popover', () => emit('hide'))
@@ -80,7 +75,34 @@ export default defineComponent({
80
75
  element,
81
76
  titleRef,
82
77
  contentRef,
78
+ instance,
79
+ initPopover
83
80
  }
84
81
  },
82
+ watch:{
83
+ disable(){
84
+ if(!this.instance){ return; }
85
+ if (this.disable) {
86
+ this.instance.disable();
87
+ } else {
88
+ this.instance.enable();
89
+ }
90
+ },
91
+ content(){
92
+ if(!this.instance){ return; }
93
+ this.$nextTick(() => {
94
+ this.instance?.dispose();
95
+ this.initPopover();
96
+ });
97
+ },
98
+ title(){
99
+ if(!this.instance){ return; }
100
+ this.$nextTick(() => {
101
+ this.instance?.dispose();
102
+ this.initPopover();
103
+ });
104
+ }
105
+ }
106
+
85
107
  })
86
108
  </script>
@@ -62,7 +62,7 @@
62
62
  </div>
63
63
  <div
64
64
  v-if="directLink"
65
- class="tab-pane tab-pane active"
65
+ class="tab-pane tab-pane"
66
66
  :class="activeTab === 2? 'active':''"
67
67
  >
68
68
  <p>{{ directLink.audioUrl }}</p>