From 7807c7d0ce5d2facd8952d9f6a2d202d60e5b578 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Sat, 24 May 2025 01:53:26 -0400 Subject: [PATCH 01/15] test change --- src/app/services/you-tube-player.service.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index 4716ee9f..a64f4479 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -129,10 +129,10 @@ export class YouTubePlayerService { private _getYouTubePlayer(): YouTubePlayer { const elm = document.createElement('div'); // Expose the following code for debugging purposes - // elm.style['position'] = 'absolute'; - // elm.style['top'] = '0'; - // elm.style['width'] = '100px'; - // elm.style['height'] = '100px'; + elm.style['position'] = 'absolute'; + elm.style['top'] = '0'; + elm.style['width'] = '400px'; + elm.style['height'] = '200px'; document.body.appendChild(elm); return PlayerFactory(elm); } From a1e7d287c3fda1cdbd4df5e1b2beed93e5f12bb3 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Sat, 24 May 2025 02:02:57 -0400 Subject: [PATCH 02/15] Add playsinlien --- src/app/services/you-tube-player.service.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index a64f4479..d3caf1c9 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -134,7 +134,11 @@ export class YouTubePlayerService { elm.style['width'] = '400px'; elm.style['height'] = '200px'; document.body.appendChild(elm); - return PlayerFactory(elm); + return PlayerFactory(elm, { + playerVars: { + playsinline: 1, + }, + }); } private _startTimeListener(): void { From 0fb968af7df28a9efdbae5968f71fa981ae2e983 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 17:30:21 -0400 Subject: [PATCH 03/15] Make the video visible --- .../answers-layout.component.scss | 1 - .../exercise/exercise.page/exercise.page.html | 1 + .../exercise/exercise.page/exercise.page.scss | 5 ++ src/app/services/you-tube-player.service.ts | 59 +++++++++++-------- 4 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/app/exercise/exercise.page/components/answers-layout/answers-layout.component.scss b/src/app/exercise/exercise.page/components/answers-layout/answers-layout.component.scss index 30539af5..19b76398 100644 --- a/src/app/exercise/exercise.page/components/answers-layout/answers-layout.component.scss +++ b/src/app/exercise/exercise.page/components/answers-layout/answers-layout.component.scss @@ -8,7 +8,6 @@ .answers-layout { &__answers-rows-container, &__answers-buttons-auto-layout-container { - flex-grow: 1; display: flex; flex-direction: column; gap: math.div($unit, 2); diff --git a/src/app/exercise/exercise.page/exercise.page.html b/src/app/exercise/exercise.page/exercise.page.html index a72a36b6..d3fb9fd1 100644 --- a/src/app/exercise/exercise.page/exercise.page.html +++ b/src/app/exercise/exercise.page/exercise.page.html @@ -71,6 +71,7 @@ }" (answerSelected)="onAnswerSelected($event)" > +
@if (answerConfig.answer; as answer) { diff --git a/src/app/exercise/exercise.page/exercise.page.scss b/src/app/exercise/exercise.page/exercise.page.scss index 2dab8c1d..154200f0 100644 --- a/src/app/exercise/exercise.page/exercise.page.scss +++ b/src/app/exercise/exercise.page/exercise.page.scss @@ -31,3 +31,8 @@ ion-title { padding: 0; } + +.video-container { + flex-grow: 1; + text-align: center; +} diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index d3caf1c9..fc0fbdb7 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -1,10 +1,9 @@ -import { Injectable } from '@angular/core'; +import { computed, Injectable } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import * as PriorityQueue from 'js-priority-queue'; import { BehaviorSubject, interval, NEVER } from 'rxjs'; import { filter, switchMap, take } from 'rxjs/operators'; import PlayerFactory from 'youtube-player'; -import { YouTubePlayer } from 'youtube-player/dist/types'; export interface YouTubeCallbackDescriptor { seconds: number; @@ -17,11 +16,12 @@ const TIME_STAMP_POLLING: number = 200; providedIn: 'root', }) export class YouTubePlayerService { + private _elm = this._getHostElement(); private _isVideoLoading: boolean = false; private _currentlyLoadedVideoId: string | null = null; private _onCurrentVideoLoaded: Promise = Promise.resolve(); private _isPlaying$ = new BehaviorSubject(false); - private _youTubePlayer: YouTubePlayer = this._getYouTubePlayer(); + private _youTubePlayer = this._getYouTubePlayer(); private _callBackQueue = new PriorityQueue({ comparator: ( a: YouTubeCallbackDescriptor, @@ -54,16 +54,16 @@ export class YouTubePlayerService { if (this._currentlyLoadedVideoId !== videoId) { this._currentlyLoadedVideoId = videoId; this._isVideoLoading = true; - this._onCurrentVideoLoaded = this._youTubePlayer + this._onCurrentVideoLoaded = this._youTubePlayer() .loadVideoById(videoId) .then(() => { return new Promise((resolve) => { - const listener = this._youTubePlayer.on( + const listener = this._youTubePlayer().on( 'stateChange', ({ data }) => { if (data === 1) { // @ts-ignore - this._youTubePlayer.off(listener); + this._youTubePlayer().off(listener); resolve(); } }, @@ -71,7 +71,7 @@ export class YouTubePlayerService { }); }) .then(() => { - this._youTubePlayer.pauseVideo(); // we don't always want it to start playing immediately + this._youTubePlayer().pauseVideo(); // we don't always want it to start playing immediately }) .then(() => { this._isVideoLoading = false; @@ -97,8 +97,8 @@ export class YouTubePlayerService { await this.loadVideoById(videoId); } await this._onCurrentVideoLoaded; // it's possible loadVideoById was invoked by another function but video is not loaded yet - await this._youTubePlayer.seekTo(time, true); - await this._youTubePlayer.playVideo(); + await this._youTubePlayer().seekTo(time, true); + await this._youTubePlayer().playVideo(); this._isPlaying$.next(true); callbacks.forEach((callback) => { this._callBackQueue.queue(callback); @@ -107,7 +107,7 @@ export class YouTubePlayerService { async stop(): Promise { if (this._isPlaying$.value) { - await this._youTubePlayer.pauseVideo(); // used instead of stopVideo to avoid resetting of the play position + await this._youTubePlayer().pauseVideo(); // used instead of stopVideo to avoid resetting of the play position this._callBackQueue.clear(); this._isPlaying$.next(false); } @@ -126,19 +126,8 @@ export class YouTubePlayerService { } } - private _getYouTubePlayer(): YouTubePlayer { - const elm = document.createElement('div'); - // Expose the following code for debugging purposes - elm.style['position'] = 'absolute'; - elm.style['top'] = '0'; - elm.style['width'] = '400px'; - elm.style['height'] = '200px'; - document.body.appendChild(elm); - return PlayerFactory(elm, { - playerVars: { - playsinline: 1, - }, - }); + private _getYouTubePlayer() { + return computed(() => PlayerFactory(this._elm())); } private _startTimeListener(): void { @@ -158,11 +147,33 @@ export class YouTubePlayerService { return; } const nextCallback = this._callBackQueue.peek(); - const currentTime = await this._youTubePlayer.getCurrentTime(); + const currentTime = await this._youTubePlayer().getCurrentTime(); if (currentTime > nextCallback.seconds - TIME_STAMP_POLLING / 2000) { this._callBackQueue.dequeue(); nextCallback.callback(); } }); } + + private _getHostElement() { + return computed(() => { + const elm = document.createElement('div'); + let host = + document.querySelector('.video-container') ?? + document.body; + + // if (!elm) { + // console.warn('Video container not found'); + + // elm = document.createElement('div'); + // } + // Expose the following code for debugging purposes + // elm.style['position'] = 'absolute'; + // elm.style['top'] = '0'; + elm.style['width'] = '70%'; + elm.style['height'] = '150px'; + host.appendChild(elm); + return elm; + }); + } } From 5b8fe4738fbeb197383d960615f706c7aec0b302 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 17:45:46 -0400 Subject: [PATCH 04/15] Add message --- src/app/services/you-tube-player.service.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index fc0fbdb7..becb4309 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -1,5 +1,6 @@ -import { computed, Injectable } from '@angular/core'; +import { computed, inject, Injectable } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { AlertController, Platform } from '@ionic/angular'; import * as PriorityQueue from 'js-priority-queue'; import { BehaviorSubject, interval, NEVER } from 'rxjs'; import { filter, switchMap, take } from 'rxjs/operators'; @@ -30,6 +31,8 @@ export class YouTubePlayerService { return a.seconds - b.seconds; }, }); + private readonly _alertController = inject(AlertController); + private readonly _platform = inject(Platform); get isVideoLoading(): boolean { return this._isVideoLoading; @@ -93,6 +96,17 @@ export class YouTubePlayerService { callbacks: YouTubeCallbackDescriptor[] = [], ): Promise { console.log('play', videoId, time); + if (this._platform.is('ios')) { + this._alertController + .create({ + message: + 'Autoplay for videos is not support on iOS, to work around this, please manually press the video to start', + subHeader: 'Press Play on the Video To Start', + buttons: ["I'll Press Play on the Video"], + }) + .then((alert) => alert.present()); + } + if (videoId !== this._currentlyLoadedVideoId) { await this.loadVideoById(videoId); } From 6aef60907d6d3f61fbaf8379edb7f83b9fde850c Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 17:58:14 -0400 Subject: [PATCH 05/15] Add toaster for video state --- src/app/services/you-tube-player.service.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index becb4309..122a9c36 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -1,6 +1,6 @@ import { computed, inject, Injectable } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { AlertController, Platform } from '@ionic/angular'; +import { AlertController, Platform, ToastController } from '@ionic/angular'; import * as PriorityQueue from 'js-priority-queue'; import { BehaviorSubject, interval, NEVER } from 'rxjs'; import { filter, switchMap, take } from 'rxjs/operators'; @@ -33,6 +33,7 @@ export class YouTubePlayerService { }); private readonly _alertController = inject(AlertController); private readonly _platform = inject(Platform); + private readonly _toastController = inject(ToastController); get isVideoLoading(): boolean { return this._isVideoLoading; @@ -64,6 +65,13 @@ export class YouTubePlayerService { const listener = this._youTubePlayer().on( 'stateChange', ({ data }) => { + // todo: remove + this._toastController + .create({ + message: `stateChange: ${data}`, + duration: 1000, + }) + .then((toast) => toast.present()); if (data === 1) { // @ts-ignore this._youTubePlayer().off(listener); From 6e3e1834a97f49fa94bc12f06f2e530768d1a73a Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 18:06:45 -0400 Subject: [PATCH 06/15] handle autoplay block --- .../state/exercise-state.service.ts | 26 +++++++++++++++++-- src/app/services/you-tube-player.service.ts | 24 +++++++---------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/app/exercise/exercise.page/state/exercise-state.service.ts b/src/app/exercise/exercise.page/state/exercise-state.service.ts index 72aa6297..97d00396 100644 --- a/src/app/exercise/exercise.page/state/exercise-state.service.ts +++ b/src/app/exercise/exercise.page/state/exercise-state.service.ts @@ -75,6 +75,7 @@ export class ExerciseStateService implements OnDestroy { readonly answerList = this._answerList.asReadonly(); private _answerToLabelStringMap: Record = this._getAnswerToLabelStringMap(); + _alertController; constructor() { listenToChanges(this, '_currentQuestion') @@ -462,7 +463,27 @@ export class ExerciseStateService implements OnDestroy { private async _loadYoutubeQuestion( question: Exercise.YouTubeQuestion, ): Promise { - await this._youtubePlayer.loadVideoById(question.videoId); + await this._youtubePlayer.loadVideoById( + question.videoId, + this._handleAutoPlayBlocked, + ); + } + + private _autoPlayBlockedVisible = false; + private async _handleAutoPlayBlocked() { + if (this._autoPlayBlockedVisible) { + return; + } + this._autoPlayBlockedVisible = true; + await this._alertController + .create({ + message: + 'Autoplay for videos is not support on iOS. To work around this, please manually press the video to start', + subHeader: 'Press Play on the Video To Start', + buttons: ["I'll Press Play on the Video"], + }) + .then((alert) => alert.present()); + this._autoPlayBlockedVisible = false; } private async _playYouTubeQuestion( @@ -471,7 +492,7 @@ export class ExerciseStateService implements OnDestroy { if (this._destroyed) { return; } - if (this._youtubePlayer.isVideoLoading) { + if (this._youtubePlayer.isVideoLoading && !this._autoPlayBlockedVisible) { this._showMessage('Video is loading...'); this._youtubePlayer.onCurrentVideoLoaded.then(() => { this._hideMessage(); @@ -495,6 +516,7 @@ export class ExerciseStateService implements OnDestroy { }, }, ], + this._handleAutoPlayBlocked, ); this._adaptiveExercise.questionStartedPlaying(); await this._youtubePlayer.onStop(); diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index 122a9c36..92da432f 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -54,14 +54,17 @@ export class YouTubePlayerService { /** * This method will not load the video if it's already loaded * */ - async loadVideoById(videoId: string): Promise { + async loadVideoById( + videoId: string, + onAutoplayBlocked: () => void, + ): Promise { if (this._currentlyLoadedVideoId !== videoId) { this._currentlyLoadedVideoId = videoId; this._isVideoLoading = true; this._onCurrentVideoLoaded = this._youTubePlayer() .loadVideoById(videoId) .then(() => { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { const listener = this._youTubePlayer().on( 'stateChange', ({ data }) => { @@ -77,6 +80,9 @@ export class YouTubePlayerService { this._youTubePlayer().off(listener); resolve(); } + if (data === -1) { + onAutoplayBlocked(); + } }, ); }); @@ -102,21 +108,11 @@ export class YouTubePlayerService { videoId: string, time: number, callbacks: YouTubeCallbackDescriptor[] = [], + onAutoplayBlocked: () => void, ): Promise { console.log('play', videoId, time); - if (this._platform.is('ios')) { - this._alertController - .create({ - message: - 'Autoplay for videos is not support on iOS, to work around this, please manually press the video to start', - subHeader: 'Press Play on the Video To Start', - buttons: ["I'll Press Play on the Video"], - }) - .then((alert) => alert.present()); - } - if (videoId !== this._currentlyLoadedVideoId) { - await this.loadVideoById(videoId); + await this.loadVideoById(videoId, onAutoplayBlocked); } await this._onCurrentVideoLoaded; // it's possible loadVideoById was invoked by another function but video is not loaded yet await this._youTubePlayer().seekTo(time, true); From b75176effcec75fc0bf71201f2135d6877e9b13c Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 18:11:56 -0400 Subject: [PATCH 07/15] fix null pointer issue --- .../exercise/exercise.page/state/exercise-state.service.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/exercise/exercise.page/state/exercise-state.service.ts b/src/app/exercise/exercise.page/state/exercise-state.service.ts index 97d00396..05270811 100644 --- a/src/app/exercise/exercise.page/state/exercise-state.service.ts +++ b/src/app/exercise/exercise.page/state/exercise-state.service.ts @@ -463,9 +463,8 @@ export class ExerciseStateService implements OnDestroy { private async _loadYoutubeQuestion( question: Exercise.YouTubeQuestion, ): Promise { - await this._youtubePlayer.loadVideoById( - question.videoId, - this._handleAutoPlayBlocked, + await this._youtubePlayer.loadVideoById(question.videoId, () => + this._handleAutoPlayBlocked(), ); } @@ -516,7 +515,7 @@ export class ExerciseStateService implements OnDestroy { }, }, ], - this._handleAutoPlayBlocked, + () => this._handleAutoPlayBlocked(), ); this._adaptiveExercise.questionStartedPlaying(); await this._youtubePlayer.onStop(); From 149b4fc0c1158fbf9947fdad7102340eec8958d5 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 18:16:24 -0400 Subject: [PATCH 08/15] add alert --- src/app/services/you-tube-player.service.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index 92da432f..78664973 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -81,6 +81,9 @@ export class YouTubePlayerService { resolve(); } if (data === -1) { + alert( + 'Autoplay for videos is not support on iOS. To work around this, please manually press the video to start', + ); onAutoplayBlocked(); } }, From f4750371b20fc49347a792b79f2d180b28ecc315 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 18:18:45 -0400 Subject: [PATCH 09/15] Remove alert --- src/app/services/you-tube-player.service.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index 78664973..92da432f 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -81,9 +81,6 @@ export class YouTubePlayerService { resolve(); } if (data === -1) { - alert( - 'Autoplay for videos is not support on iOS. To work around this, please manually press the video to start', - ); onAutoplayBlocked(); } }, From de1965e6613dd7eb3c798454ed03d9af3c098665 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 18:19:12 -0400 Subject: [PATCH 10/15] remove unnecessary alert --- src/app/services/you-tube-player.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index 92da432f..b88098c9 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -64,7 +64,7 @@ export class YouTubePlayerService { this._onCurrentVideoLoaded = this._youTubePlayer() .loadVideoById(videoId) .then(() => { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { const listener = this._youTubePlayer().on( 'stateChange', ({ data }) => { From abd75d3a078f5e1d5f0b7e076350d7292eb01281 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 18:21:35 -0400 Subject: [PATCH 11/15] test popup --- src/app/services/you-tube-player.service.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index b88098c9..251a5298 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -81,6 +81,13 @@ export class YouTubePlayerService { resolve(); } if (data === -1) { + this._alertController + .create({ + message: 'Test popup', + subHeader: 'Test popup', + buttons: ['OK'], + }) + .then((alert) => alert.present()); onAutoplayBlocked(); } }, From ed821fc9306acea67f9ee7d8e79f4c4564fdc619 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 18:24:57 -0400 Subject: [PATCH 12/15] test 2 --- .../exercise.page/state/exercise-state.service.ts | 6 +++--- src/app/services/you-tube-player.service.ts | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/app/exercise/exercise.page/state/exercise-state.service.ts b/src/app/exercise/exercise.page/state/exercise-state.service.ts index 05270811..7397fc04 100644 --- a/src/app/exercise/exercise.page/state/exercise-state.service.ts +++ b/src/app/exercise/exercise.page/state/exercise-state.service.ts @@ -470,9 +470,9 @@ export class ExerciseStateService implements OnDestroy { private _autoPlayBlockedVisible = false; private async _handleAutoPlayBlocked() { - if (this._autoPlayBlockedVisible) { - return; - } + // if (this._autoPlayBlockedVisible) { + // return; + // } this._autoPlayBlockedVisible = true; await this._alertController .create({ diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index 251a5298..fdf3d415 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -81,13 +81,13 @@ export class YouTubePlayerService { resolve(); } if (data === -1) { - this._alertController - .create({ - message: 'Test popup', - subHeader: 'Test popup', - buttons: ['OK'], - }) - .then((alert) => alert.present()); + // this._alertController + // .create({ + // message: 'Test popup', + // subHeader: 'Test popup', + // buttons: ['OK'], + // }) + // .then((alert) => alert.present()); onAutoplayBlocked(); } }, From 1cd34ef9f94d6e927002ff15c4de842a35b346b4 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 18:29:16 -0400 Subject: [PATCH 13/15] Fix missing alert controller --- .../exercise.page/state/exercise-state.service.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/exercise/exercise.page/state/exercise-state.service.ts b/src/app/exercise/exercise.page/state/exercise-state.service.ts index 7397fc04..b1f01a8a 100644 --- a/src/app/exercise/exercise.page/state/exercise-state.service.ts +++ b/src/app/exercise/exercise.page/state/exercise-state.service.ts @@ -1,6 +1,7 @@ import { Injectable, OnDestroy, inject, signal } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ActivatedRoute } from '@angular/router'; +import { AlertController } from '@ionic/angular'; import * as _ from 'lodash'; import { defaults } from 'lodash'; import { filter, map } from 'rxjs/operators'; @@ -75,7 +76,7 @@ export class ExerciseStateService implements OnDestroy { readonly answerList = this._answerList.asReadonly(); private _answerToLabelStringMap: Record = this._getAnswerToLabelStringMap(); - _alertController; + private readonly _alertController = inject(AlertController); constructor() { listenToChanges(this, '_currentQuestion') @@ -470,9 +471,9 @@ export class ExerciseStateService implements OnDestroy { private _autoPlayBlockedVisible = false; private async _handleAutoPlayBlocked() { - // if (this._autoPlayBlockedVisible) { - // return; - // } + if (this._autoPlayBlockedVisible) { + return; + } this._autoPlayBlockedVisible = true; await this._alertController .create({ From 3bcd25c1d50228e5ca796c3d2a4b05716df7b3e1 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Mon, 26 May 2025 18:35:59 -0400 Subject: [PATCH 14/15] Fix --- .../state/exercise-state.service.ts | 20 ++++++++++--------- src/style/overrides/index.scss | 4 ++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/app/exercise/exercise.page/state/exercise-state.service.ts b/src/app/exercise/exercise.page/state/exercise-state.service.ts index b1f01a8a..f07910b5 100644 --- a/src/app/exercise/exercise.page/state/exercise-state.service.ts +++ b/src/app/exercise/exercise.page/state/exercise-state.service.ts @@ -475,15 +475,17 @@ export class ExerciseStateService implements OnDestroy { return; } this._autoPlayBlockedVisible = true; - await this._alertController - .create({ - message: - 'Autoplay for videos is not support on iOS. To work around this, please manually press the video to start', - subHeader: 'Press Play on the Video To Start', - buttons: ["I'll Press Play on the Video"], - }) - .then((alert) => alert.present()); - this._autoPlayBlockedVisible = false; + const alert = await this._alertController.create({ + message: + 'Autoplay for videos is not support on iOS. To work around this, please manually press the video to start', + subHeader: 'Press Play on the Video To Start', + buttons: ["I'll Press Play on the Video"], + cssClass: 'above-toaster', + }); + await alert.present(); + alert.onDidDismiss().then(() => { + this._autoPlayBlockedVisible = false; + }); } private async _playYouTubeQuestion( diff --git a/src/style/overrides/index.scss b/src/style/overrides/index.scss index 27aead97..f107e1dc 100644 --- a/src/style/overrides/index.scss +++ b/src/style/overrides/index.scss @@ -11,3 +11,7 @@ ion-toggle, ion-select { flex-grow: 0; } + +.above-toaster { + z-index: 1001 !important; +} From f4ac420fa956d4b4d0275f505f3b5ba488265f95 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Sat, 31 May 2025 18:21:57 -0400 Subject: [PATCH 15/15] ios playback alert (progress) --- .../state/exercise-state.service.ts | 24 ++++++++------ src/app/services/you-tube-player.service.ts | 31 +++++-------------- src/style/overrides/index.scss | 2 +- 3 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/app/exercise/exercise.page/state/exercise-state.service.ts b/src/app/exercise/exercise.page/state/exercise-state.service.ts index f07910b5..a6c365b1 100644 --- a/src/app/exercise/exercise.page/state/exercise-state.service.ts +++ b/src/app/exercise/exercise.page/state/exercise-state.service.ts @@ -1,4 +1,4 @@ -import { Injectable, OnDestroy, inject, signal } from '@angular/core'; +import { Injectable, OnDestroy, effect, inject, signal } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ActivatedRoute } from '@angular/router'; import { AlertController } from '@ionic/angular'; @@ -92,6 +92,13 @@ export class ExerciseStateService implements OnDestroy { this._dronePlayer.stopDrone(); } }); + + effect(() => { + if (this._youtubePlayer.isPlaying() && this._autoPlayAlert) { + this._autoPlayAlert.dismiss(); + this._autoPlayAlert = null; + } + }); } get playerReady(): boolean { @@ -469,22 +476,21 @@ export class ExerciseStateService implements OnDestroy { ); } - private _autoPlayBlockedVisible = false; + private _autoPlayAlert: HTMLIonAlertElement | null = null; private async _handleAutoPlayBlocked() { - if (this._autoPlayBlockedVisible) { + if (this._autoPlayAlert) { return; } - this._autoPlayBlockedVisible = true; - const alert = await this._alertController.create({ + this._autoPlayAlert = await this._alertController.create({ message: 'Autoplay for videos is not support on iOS. To work around this, please manually press the video to start', subHeader: 'Press Play on the Video To Start', buttons: ["I'll Press Play on the Video"], cssClass: 'above-toaster', }); - await alert.present(); - alert.onDidDismiss().then(() => { - this._autoPlayBlockedVisible = false; + await this._autoPlayAlert.present(); + this._autoPlayAlert.onDidDismiss().then(() => { + this._autoPlayAlert = null; }); } @@ -494,7 +500,7 @@ export class ExerciseStateService implements OnDestroy { if (this._destroyed) { return; } - if (this._youtubePlayer.isVideoLoading && !this._autoPlayBlockedVisible) { + if (this._youtubePlayer.isVideoLoading && !this._autoPlayAlert) { this._showMessage('Video is loading...'); this._youtubePlayer.onCurrentVideoLoaded.then(() => { this._hideMessage(); diff --git a/src/app/services/you-tube-player.service.ts b/src/app/services/you-tube-player.service.ts index fdf3d415..dcfa64cd 100644 --- a/src/app/services/you-tube-player.service.ts +++ b/src/app/services/you-tube-player.service.ts @@ -1,6 +1,5 @@ -import { computed, inject, Injectable } from '@angular/core'; -import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { AlertController, Platform, ToastController } from '@ionic/angular'; +import { computed, Injectable } from '@angular/core'; +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; import * as PriorityQueue from 'js-priority-queue'; import { BehaviorSubject, interval, NEVER } from 'rxjs'; import { filter, switchMap, take } from 'rxjs/operators'; @@ -22,6 +21,9 @@ export class YouTubePlayerService { private _currentlyLoadedVideoId: string | null = null; private _onCurrentVideoLoaded: Promise = Promise.resolve(); private _isPlaying$ = new BehaviorSubject(false); + readonly isPlaying = toSignal(this._isPlaying$.asObservable(), { + initialValue: false, + }); private _youTubePlayer = this._getYouTubePlayer(); private _callBackQueue = new PriorityQueue({ comparator: ( @@ -31,9 +33,6 @@ export class YouTubePlayerService { return a.seconds - b.seconds; }, }); - private readonly _alertController = inject(AlertController); - private readonly _platform = inject(Platform); - private readonly _toastController = inject(ToastController); get isVideoLoading(): boolean { return this._isVideoLoading; @@ -43,10 +42,6 @@ export class YouTubePlayerService { return this._onCurrentVideoLoaded; } - get isPlaying() { - return this._isPlaying$.value; - } - constructor() { this._startTimeListener(); } @@ -68,26 +63,14 @@ export class YouTubePlayerService { const listener = this._youTubePlayer().on( 'stateChange', ({ data }) => { - // todo: remove - this._toastController - .create({ - message: `stateChange: ${data}`, - duration: 1000, - }) - .then((toast) => toast.present()); + console.log('stateChange', data); // todo + if (data === 1) { // @ts-ignore this._youTubePlayer().off(listener); resolve(); } if (data === -1) { - // this._alertController - // .create({ - // message: 'Test popup', - // subHeader: 'Test popup', - // buttons: ['OK'], - // }) - // .then((alert) => alert.present()); onAutoplayBlocked(); } }, diff --git a/src/style/overrides/index.scss b/src/style/overrides/index.scss index f107e1dc..589170e5 100644 --- a/src/style/overrides/index.scss +++ b/src/style/overrides/index.scss @@ -13,5 +13,5 @@ ion-select { } .above-toaster { - z-index: 1001 !important; + z-index: 60003 !important; }