@inappstory/slide-api 0.1.7 → 0.1.9

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.
package/dist/index.js CHANGED
@@ -1149,6 +1149,12 @@ class EsModuleSdkApi {
1149
1149
  enableVerticalSwipeGesture() {
1150
1150
  this.sdkBinding.enableVerticalSwipeGesture();
1151
1151
  }
1152
+ disableHorizontalSwipeGesture() {
1153
+ this.sdkBinding.disableHorizontalSwipeGesture();
1154
+ }
1155
+ enableHorizontalSwipeGesture() {
1156
+ this.sdkBinding.enableHorizontalSwipeGesture();
1157
+ }
1152
1158
  disableBackpress() { }
1153
1159
  enableBackpress() { }
1154
1160
  closeCard(reason) {
@@ -2239,6 +2245,15 @@ class Video {
2239
2245
  this._isVOD = Boolean(this._vodData != null && this._VideoPlayer != null);
2240
2246
  if (this._isVOD) ;
2241
2247
  else {
2248
+ if (this._vodData != null && Array.isArray(this._vodData.formats)) {
2249
+ this._vodData.formats.forEach(format => {
2250
+ const videoSource = window.document.createElement("source");
2251
+ videoSource.type = format.mimeType;
2252
+ videoSource.src = format.url;
2253
+ videoSource.dataset.remoteSrc = format.url;
2254
+ this._video.appendChild(videoSource);
2255
+ });
2256
+ }
2242
2257
  this.mediaElementsLoadingPromises.push(waitForVideoHtmlElementLoad(this._video));
2243
2258
  }
2244
2259
  // console.log({mediaElementsLoadingPromises: this.mediaElementsLoadingPromises})
@@ -2263,12 +2278,13 @@ class Video {
2263
2278
  // clean up memory and cpu processes
2264
2279
  // @ts-ignore
2265
2280
  // _log("onBeforeUnmount", true)
2281
+ // console.log("onBeforeUnmount")
2266
2282
  this._destroyVODPlayer();
2267
2283
  }
2268
2284
  _initVOD(vodData) {
2269
2285
  const onWaiting = () => {
2270
2286
  /**
2271
- * When screen on pause - ignore onWaiting
2287
+ * When screen on pause - ignore onWaiting (or when SlideApi is destroyed)
2272
2288
  * (triggered when video paused, not only when canplay = false)
2273
2289
  */
2274
2290
  if (this._isScreenOnPause) {
@@ -2811,14 +2827,14 @@ class SlideTimeline {
2811
2827
  slideDuration;
2812
2828
  slideDisabledTimer;
2813
2829
  slideReady;
2814
- _afterResumeQueuePush;
2830
+ _afterAppResumeQueuePush;
2815
2831
  sdkApi;
2816
- constructor(slideIndex, slideDuration, slideDisabledTimer, slideReady, _afterResumeQueuePush, sdkApi) {
2832
+ constructor(slideIndex, slideDuration, slideDisabledTimer, slideReady, _afterAppResumeQueuePush, sdkApi) {
2817
2833
  this.slideIndex = slideIndex;
2818
2834
  this.slideDuration = slideDuration;
2819
2835
  this.slideDisabledTimer = slideDisabledTimer;
2820
2836
  this.slideReady = slideReady;
2821
- this._afterResumeQueuePush = _afterResumeQueuePush;
2837
+ this._afterAppResumeQueuePush = _afterAppResumeQueuePush;
2822
2838
  this.sdkApi = sdkApi;
2823
2839
  this.timelineDisabledState = this.slideDisabledTimer ? TimelineDisabledState.disabled : TimelineDisabledState.enabled;
2824
2840
  }
@@ -2975,7 +2991,7 @@ class SlideTimeline {
2975
2991
  // if app is paused (in background) - don't call start timeline (Android issues)
2976
2992
  // @ts-ignore
2977
2993
  // window._log(`Push startDisabledTimeline to queue at state: ${window.slideApi.state}, time: ${new Date().getTime()}`, true);
2978
- this._afterResumeQueuePush(() => {
2994
+ this._afterAppResumeQueuePush(() => {
2979
2995
  // @ts-ignore
2980
2996
  // window._log(`Call startDisabledTimeline at state: ${window.slideApi.state}, time: ${new Date().getTime()}`, true);
2981
2997
  if (this.isSDKSupportUpdateTimeline) {
@@ -3022,7 +3038,7 @@ class Layer {
3022
3038
  _nodeRef;
3023
3039
  _slide;
3024
3040
  _slideReadyPromise;
3025
- _afterResumeQueuePush;
3041
+ _afterAppResumeQueuePush;
3026
3042
  _afterStartInitQueuePush;
3027
3043
  _showNextSlide;
3028
3044
  sdkApi;
@@ -3035,11 +3051,11 @@ class Layer {
3035
3051
  _disabledNavigation;
3036
3052
  _elements = [];
3037
3053
  _timeline;
3038
- constructor(_nodeRef, _slide, _slideReadyPromise, _afterResumeQueuePush, _afterStartInitQueuePush, _showNextSlide, sdkApi) {
3054
+ constructor(_nodeRef, _slide, _slideReadyPromise, _afterAppResumeQueuePush, _afterStartInitQueuePush, _showNextSlide, sdkApi) {
3039
3055
  this._nodeRef = _nodeRef;
3040
3056
  this._slide = _slide;
3041
3057
  this._slideReadyPromise = _slideReadyPromise;
3042
- this._afterResumeQueuePush = _afterResumeQueuePush;
3058
+ this._afterAppResumeQueuePush = _afterAppResumeQueuePush;
3043
3059
  this._afterStartInitQueuePush = _afterStartInitQueuePush;
3044
3060
  this._showNextSlide = _showNextSlide;
3045
3061
  this.sdkApi = sdkApi;
@@ -3050,7 +3066,7 @@ class Layer {
3050
3066
  this._duration = parseInt(this._nodeRef.getAttribute("data-duration") ?? "") || DEFAULT_SLIDE_DURATION;
3051
3067
  this._disabledTimer = this._nodeRef.getAttribute("data-disable-timer") === "1";
3052
3068
  this._disabledNavigation = this._nodeRef.getAttribute("data-disable-navigation") === "1";
3053
- this._timeline = new SlideTimeline(this._slideIndex, this._duration, this._disabledTimer, this._slideReadyPromise, this._afterResumeQueuePush, this.sdkApi);
3069
+ this._timeline = new SlideTimeline(this._slideIndex, this._duration, this._disabledTimer, this._slideReadyPromise, this._afterAppResumeQueuePush, this.sdkApi);
3054
3070
  const onWidgetComplete = (cardId, slideIndex) => {
3055
3071
  // todo if nothing more widgets with disabled timers - we can start layer timeline
3056
3072
  const fallback = () => this._showNextSlide(DEFAULT_SLIDE_DURATION);
@@ -3302,7 +3318,7 @@ class Layer {
3302
3318
  element.onStop();
3303
3319
  }
3304
3320
  }
3305
- async pause(resetVideoTime = false, stopAnimation = false) {
3321
+ async pause(resetVideoTime = false, stopAnimation = false, updateTimeline = true) {
3306
3322
  return new Promise(resolve => {
3307
3323
  const cb = () => {
3308
3324
  let currentTime = this.videoElement?.pause(resetVideoTime) ?? null;
@@ -3320,7 +3336,9 @@ class Layer {
3320
3336
  for (const element of this._elements) {
3321
3337
  element.onPause();
3322
3338
  }
3323
- this.timeline.slidePaused(currentTime);
3339
+ if (updateTimeline) {
3340
+ this.timeline.slidePaused(currentTime);
3341
+ }
3324
3342
  resolve({ currentTime });
3325
3343
  };
3326
3344
  const videoStartedPromise = this.videoElement?.videoStartedPromise;
@@ -3544,16 +3562,16 @@ class TextElementAutoWidthCorrection {
3544
3562
  class Slide {
3545
3563
  _slidesNodesRefs;
3546
3564
  _slideReadyPromise;
3547
- _afterResumeQueuePush;
3565
+ _afterAppResumeQueuePush;
3548
3566
  _afterStartInitQueuePush;
3549
3567
  _showNextSlide;
3550
3568
  sdkApi;
3551
3569
  _layers;
3552
3570
  _start;
3553
- constructor(_slidesNodesRefs, _slideReadyPromise, _afterResumeQueuePush, _afterStartInitQueuePush, _showNextSlide, sdkApi) {
3571
+ constructor(_slidesNodesRefs, _slideReadyPromise, _afterAppResumeQueuePush, _afterStartInitQueuePush, _showNextSlide, sdkApi) {
3554
3572
  this._slidesNodesRefs = _slidesNodesRefs;
3555
3573
  this._slideReadyPromise = _slideReadyPromise;
3556
- this._afterResumeQueuePush = _afterResumeQueuePush;
3574
+ this._afterAppResumeQueuePush = _afterAppResumeQueuePush;
3557
3575
  this._afterStartInitQueuePush = _afterStartInitQueuePush;
3558
3576
  this._showNextSlide = _showNextSlide;
3559
3577
  this.sdkApi = sdkApi;
@@ -3561,7 +3579,7 @@ class Slide {
3561
3579
  if (!this._slidesNodesRefs.length) {
3562
3580
  throw new Error("No slides found.");
3563
3581
  }
3564
- this._layers = this._slidesNodesRefs.map(item => new Layer(item, this, this._slideReadyPromise, this._afterResumeQueuePush, this._afterStartInitQueuePush, this._showNextSlide, this.sdkApi));
3582
+ this._layers = this._slidesNodesRefs.map(item => new Layer(item, this, this._slideReadyPromise, this._afterAppResumeQueuePush, this._afterStartInitQueuePush, this._showNextSlide, this.sdkApi));
3565
3583
  this._activeLayer = this._layers[0];
3566
3584
  }
3567
3585
  _activeLayer;
@@ -3668,6 +3686,7 @@ let SlideApi$1 = class SlideApi {
3668
3686
  _getViewportWidth;
3669
3687
  _getViewportHeight;
3670
3688
  _overlappingActionBarHeight;
3689
+ _separateUserAndAppPause;
3671
3690
  sdkApi;
3672
3691
  constructor(config) {
3673
3692
  this.config = config;
@@ -3677,6 +3696,7 @@ let SlideApi$1 = class SlideApi {
3677
3696
  this._getViewportWidth = config.getViewportWidth;
3678
3697
  this._getViewportHeight = config.getViewportHeight;
3679
3698
  this._overlappingActionBarHeight = config.overlappingActionBarHeight ?? 0;
3699
+ this._separateUserAndAppPause = config.separateUserAndAppPause;
3680
3700
  this.refreshSizes = proxy(this.refreshSizes, this);
3681
3701
  this.initListeners();
3682
3702
  this.refreshSizes();
@@ -3685,10 +3705,10 @@ let SlideApi$1 = class SlideApi {
3685
3705
  if (slideBox && slideBox.innerText.trim() !== "{%content}".replace("{", "{{").replace("}", "}}")) {
3686
3706
  this._slideInInit = null;
3687
3707
  this._slideInRender = true;
3688
- this._init(() => this._slideBoxRenderComplete(null), () => this._slideBoxRenderError(null)).then(({ slide, result, reason }) => {
3708
+ this._init(() => this._slideBoxRenderComplete(null)).then(({ slide, result, reason }) => {
3689
3709
  this._slide = slide;
3690
3710
  if (config.slideLoadedCb != null) {
3691
- config.slideLoadedCb({ slide, result, reason });
3711
+ config.slideLoadedCb({ cardId: slide.cardId, slideIndex: slide.slideIndex, result, reason });
3692
3712
  }
3693
3713
  });
3694
3714
  }
@@ -3698,6 +3718,7 @@ let SlideApi$1 = class SlideApi {
3698
3718
  this.slide.onBeforeUnmount();
3699
3719
  }
3700
3720
  this.destroyListeners();
3721
+ this._state = 13 /* STATE.DESTROYED */;
3701
3722
  }
3702
3723
  initListeners() {
3703
3724
  this._viewport.addEventListener("resize", this.refreshSizes);
@@ -3778,7 +3799,7 @@ let SlideApi$1 = class SlideApi {
3778
3799
  async showSlide(html) {
3779
3800
  const slideBox = this._slideWrapper.querySelector(`.${SlideApi.renderedBoxClassName}`);
3780
3801
  const slideBoxPrerender = this._slideWrapper.querySelector(`.${SlideApi.prerenderBoxClassName}`);
3781
- const _result = { slide: this.slide, result: false, reason: "" };
3802
+ const _result = { cardId: this.slide?.cardId ?? 0, slideIndex: this.slide?.slideIndex ?? 0, result: false, reason: "" };
3782
3803
  if (slideBox && slideBoxPrerender) {
3783
3804
  if (this._slideInRender) {
3784
3805
  this._slideInRender = false;
@@ -3788,12 +3809,17 @@ let SlideApi$1 = class SlideApi {
3788
3809
  this._slideInRender = true;
3789
3810
  slideBoxPrerender.innerHTML = html;
3790
3811
  const prevSlide = this.slide ? Object.assign(Object.create(Object.getPrototypeOf(this.slide)), this.slide) : null;
3791
- const { slide, result, reason } = await this._init(() => this._slideBoxRenderComplete(prevSlide), () => this._slideBoxRenderError(prevSlide));
3812
+ const { slide, result, reason } = await this._init(() => this._slideBoxRenderComplete(prevSlide));
3792
3813
  this._slide = slide;
3793
3814
  _result.result = result;
3794
3815
  _result.reason = reason;
3795
3816
  }
3796
- _result.slide = this.slide;
3817
+ else {
3818
+ _result.result = false;
3819
+ _result.reason = `Element .${SlideApi.renderedBoxClassName} or .${SlideApi.prerenderBoxClassName} does not found in DOM`;
3820
+ }
3821
+ _result.cardId = this.slide.cardId;
3822
+ _result.slideIndex = this.slide.slideIndex;
3797
3823
  return _result;
3798
3824
  }
3799
3825
  handleBackpress() {
@@ -3847,44 +3873,50 @@ let SlideApi$1 = class SlideApi {
3847
3873
  }
3848
3874
  });
3849
3875
  }
3876
+ // todo nullable
3850
3877
  _slide;
3851
3878
  _slideInInit;
3852
3879
  _state;
3853
3880
  _afterStartInitQueue = [];
3854
- _afterResumeQueue = [];
3881
+ _afterAppResumeQueue = [];
3855
3882
  get state() {
3856
3883
  return this._state;
3857
3884
  }
3858
3885
  async _onAllMediaLoaded(slide) {
3859
- return new Promise((resolve, reject) => {
3860
- const promises = slide.layers.flatMap(layer => layer.elements.flatMap(element => element.mediaElementsLoadingPromises));
3861
- console.log({ promises });
3862
- let checkerTimerId = undefined;
3863
- let timeOutFired = false;
3864
- if (promises.length > 0) {
3865
- checkerTimerId = this.layoutService.env.setTimeout(() => {
3866
- timeOutFired = true;
3867
- reject("onAllMediaLoaded timeout");
3868
- }, 3000);
3869
- }
3870
- else {
3871
- resolve();
3872
- return;
3873
- }
3874
- Promise.all(promises).then(_ => {
3875
- checkerTimerId && this.layoutService.env.clearTimeout(checkerTimerId);
3876
- if (!timeOutFired) {
3877
- resolve();
3878
- }
3879
- }, reason => {
3880
- checkerTimerId && this.layoutService.env.clearTimeout(checkerTimerId);
3881
- if (!timeOutFired) {
3882
- reject(reason);
3883
- }
3884
- });
3885
- });
3886
- }
3887
- async _init(slideBoxCb, slideBoxFailedCb) {
3886
+ return Promise.all(slide.layers.flatMap(layer => layer.elements.flatMap(element => element.mediaElementsLoadingPromises))).then(_ => { });
3887
+ // return new Promise((resolve, reject) => {
3888
+ // const promises = slide.layers.flatMap(layer => layer.elements.flatMap(element => element.mediaElementsLoadingPromises));
3889
+ //
3890
+ // // console.log({ promises });
3891
+ //
3892
+ // let checkerTimerId: number | undefined = undefined;
3893
+ // let timeOutFired = false;
3894
+ // if (promises.length > 0) {
3895
+ // checkerTimerId = this.layoutService.env.setTimeout(() => {
3896
+ // timeOutFired = true;
3897
+ // reject("onAllMediaLoaded timeout");
3898
+ // }, 3000);
3899
+ // } else {
3900
+ // resolve();
3901
+ // return;
3902
+ // }
3903
+ // Promise.all(promises).then(
3904
+ // _ => {
3905
+ // checkerTimerId && this.layoutService.env.clearTimeout(checkerTimerId);
3906
+ // if (!timeOutFired) {
3907
+ // resolve();
3908
+ // }
3909
+ // },
3910
+ // reason => {
3911
+ // checkerTimerId && this.layoutService.env.clearTimeout(checkerTimerId);
3912
+ // if (!timeOutFired) {
3913
+ // reject(reason);
3914
+ // }
3915
+ // },
3916
+ // );
3917
+ // });
3918
+ }
3919
+ async _init(slideBoxCb) {
3888
3920
  this._state = 0 /* STATE.INIT */;
3889
3921
  const slideNodeRef = this._slideWrapper.querySelector(`.${SlideApi.prerenderBoxClassName} .narrative-slide`);
3890
3922
  const slidesNodesRefs = Array.prototype.slice.call(this._slideWrapper.querySelectorAll(`.${SlideApi.prerenderBoxClassName} .narrative-slide.narrative-multi-slide`));
@@ -3895,53 +3927,59 @@ let SlideApi$1 = class SlideApi {
3895
3927
  throw new Error("No slides found.");
3896
3928
  }
3897
3929
  let slideReadyResolve = null;
3898
- let slideReadyReject = null;
3899
- const slideReadyPromise = new Promise((resolve, reject) => {
3930
+ const slideReadyPromise = new Promise(resolve => {
3900
3931
  slideReadyResolve = resolve;
3901
- slideReadyReject = reject;
3902
3932
  });
3903
- const slide = new Slide(slidesNodesRefs, slideReadyPromise, this.afterResumeQueuePush.bind(this), this.afterStartInitQueuePush.bind(this), this.sdkApi.showNextSlide.bind(this), this.sdkApi);
3933
+ const slide = new Slide(slidesNodesRefs, slideReadyPromise, this.afterAppResumeQueuePush.bind(this), this.afterStartInitQueuePush.bind(this), this.sdkApi.showNextSlide.bind(this), this.sdkApi);
3904
3934
  this._slideInInit = slide;
3905
3935
  slide.activeLayer.timeline.triggerSlideLoadState();
3906
- const onAllMediaLoaded = this._onAllMediaLoaded(slide);
3907
3936
  if (this.sdkApi.isAndroid) {
3908
3937
  this._afterStartInitQueue = [];
3909
3938
  }
3910
- this._afterResumeQueue = [];
3939
+ this._afterAppResumeQueue = [];
3911
3940
  const result = { slide, result: false, reason: "" };
3912
- await this._initAndLoadFonts(this.sdkApi.getCardFonts());
3913
- const localData = await this.getLocalData();
3914
- const finishRender = await slide.init(localData);
3915
- /**
3916
- * если есть виджеты, которых надо ждать - то не завершаем рендеринг текущего слайда
3917
- * пример - квест, если зашли в сторис а виджету нужно показать другой слайд вместо первого
3918
- */
3919
- if (finishRender) {
3920
- this._state = 1 /* STATE.INITED */;
3921
- try {
3922
- await onAllMediaLoaded;
3941
+ try {
3942
+ const onAllMediaLoaded = this._onAllMediaLoaded(slide);
3943
+ const fontsPromise = this._initAndLoadFonts(this.sdkApi.getCardFonts());
3944
+ const mediaAndFontsPromise = Promise.all([onAllMediaLoaded, fontsPromise]).then(() => {
3945
+ this.layoutService.env.clearTimeout(mediaResourcesTimeoutId);
3946
+ });
3947
+ let mediaResourcesTimeoutId = null;
3948
+ const mediaResourcesTimeoutPromise = new Promise((resolve, reject) => {
3949
+ mediaResourcesTimeoutId = this.layoutService.env.setTimeout(() => {
3950
+ // todo add detailed info about pending media resources
3951
+ reject("MediaResources loading timed out (5 sec).");
3952
+ }, 5000);
3953
+ });
3954
+ const mediaResourcesWithTimeoutPromise = Promise.race([mediaAndFontsPromise, mediaResourcesTimeoutPromise]);
3955
+ const elementsPromise = slide.init(await this.getLocalData());
3956
+ const finishRender = await elementsPromise;
3957
+ /**
3958
+ * если есть виджеты, которых надо ждать - то не завершаем рендеринг текущего слайда
3959
+ * пример - квест, если зашли в сторис а виджету нужно показать другой слайд вместо первого
3960
+ */
3961
+ if (finishRender) {
3962
+ this._state = 1 /* STATE.INITED */;
3963
+ await mediaResourcesWithTimeoutPromise;
3923
3964
  result.result = true;
3924
3965
  slideBoxCb();
3925
- this.layoutService.env.setTimeout(() => {
3926
- slideReadyResolve();
3927
- });
3928
3966
  }
3929
- catch (reason) {
3930
- console.log("SlideInit, onAllMediaLoaded reject", reason);
3931
- slideBoxFailedCb();
3932
- this.layoutService.env.setTimeout(() => {
3933
- slideReadyReject();
3934
- });
3935
- result.result = false;
3936
- result.reason = String(reason);
3967
+ else {
3968
+ this._state = 12 /* STATE.STOPPED */;
3969
+ result.result = true;
3937
3970
  }
3971
+ this.layoutService.env.setTimeout(() => {
3972
+ slideReadyResolve();
3973
+ });
3938
3974
  }
3939
- else {
3940
- this._state = 10 /* STATE.STOPPED */;
3975
+ catch (reason) {
3976
+ console.log("SlideInit, onAllMediaLoaded reject", reason);
3977
+ slideBoxCb();
3941
3978
  this.layoutService.env.setTimeout(() => {
3942
3979
  slideReadyResolve();
3943
3980
  });
3944
- result.result = true;
3981
+ result.result = false;
3982
+ result.reason = String(reason);
3945
3983
  }
3946
3984
  return result;
3947
3985
  }
@@ -3957,6 +3995,8 @@ let SlideApi$1 = class SlideApi {
3957
3995
  slideBoxPrerender.classList.remove(SlideApi.prerenderBoxClassName);
3958
3996
  slideBox.classList.remove(SlideApi.renderedBoxClassName);
3959
3997
  slideBox.classList.add(SlideApi.prerenderBoxClassName);
3998
+ // pause Video - prevent triggering onDataWaiting from VODPlayer
3999
+ prevSlide?.activeLayer.pause(false, true, false);
3960
4000
  // 2 RAF - wait for browser render complete (CSS changes, etc.)
3961
4001
  this.layoutService.env.requestAnimationFrame(() => {
3962
4002
  this.layoutService.env.requestAnimationFrame(() => {
@@ -3970,34 +4010,10 @@ let SlideApi$1 = class SlideApi {
3970
4010
  }
3971
4011
  this._slideInRender = false;
3972
4012
  }
3973
- _slideBoxRenderError(prevSlide) {
3974
- // if (!slideInRender) {
3975
- // slideInRender = true;
3976
- // return;
3977
- // }
3978
- const slideBox = this._slideWrapper.querySelector(`.${SlideApi.renderedBoxClassName}`);
3979
- const slideBoxPrerender = this._slideWrapper.querySelector(`.${SlideApi.prerenderBoxClassName}`);
3980
- if (slideBox && slideBoxPrerender) {
3981
- const slides = Array.prototype.slice.call(slideBoxPrerender.querySelectorAll(".narrative-slide"));
3982
- for (let i = 0; i < slides.length; ++i) {
3983
- const slide = slides[i];
3984
- if (slide) {
3985
- slide.innerHTML = "";
3986
- }
3987
- }
3988
- slideBoxPrerender.classList.remove(SlideApi.prerenderBoxClassName);
3989
- slideBox.classList.remove(SlideApi.renderedBoxClassName);
3990
- slideBox.classList.add(SlideApi.prerenderBoxClassName);
3991
- prevSlide?.onBeforeUnmount();
3992
- slideBox.innerHTML = "";
3993
- slideBoxPrerender.classList.add(SlideApi.renderedBoxClassName);
3994
- }
3995
- // slideInRender = false;
3996
- }
3997
4013
  _slideConfig = {};
3998
4014
  async slideStart(config) {
3999
4015
  // console.log(`slideStart slideIdx: ${this.activeLayer.slideIndex} state: ${this._state}`);
4000
- if (!(this._state === 10 /* STATE.STOPPED */ || this._state === 1 /* STATE.INITED */)) {
4016
+ if (!(this._state === 12 /* STATE.STOPPED */ || this._state === 1 /* STATE.INITED */)) {
4001
4017
  return { currentTime: 0 };
4002
4018
  }
4003
4019
  this._state = 2 /* STATE.START */;
@@ -4012,30 +4028,32 @@ let SlideApi$1 = class SlideApi {
4012
4028
  }
4013
4029
  this._afterStartInitQueue = [];
4014
4030
  }
4015
- if (this._afterResumeQueue && Array.isArray(this._afterResumeQueue)) {
4016
- for (const job of this._afterResumeQueue) {
4031
+ if (this._afterAppResumeQueue && Array.isArray(this._afterAppResumeQueue)) {
4032
+ for (const job of this._afterAppResumeQueue) {
4017
4033
  if (isFunction(job)) {
4018
4034
  job();
4019
4035
  }
4020
4036
  }
4021
- this._afterResumeQueue = [];
4037
+ this._afterAppResumeQueue = [];
4022
4038
  }
4023
4039
  const { currentTime } = await this.slide.activeLayer.start(this._slideConfig.muted);
4024
4040
  this._state = 3 /* STATE.STARTED */;
4025
4041
  if (this.slide.activeLayer.isLayerForcePaused) {
4026
- this._state = 7 /* STATE.PAUSED */;
4042
+ this._state = 9 /* STATE.USER_PAUSED */;
4027
4043
  }
4028
4044
  return { currentTime };
4029
4045
  }
4030
4046
  async slideRestart(config) {
4031
- this._state = 10 /* STATE.STOPPED */;
4047
+ this._state = 12 /* STATE.STOPPED */;
4032
4048
  return this.slideStart(config);
4033
4049
  }
4034
4050
  _pauseCbTimer = null;
4035
- async slidePause() {
4051
+ async slideUserPause() {
4052
+ // apply user pause only if state is started or resumed
4036
4053
  if (!(this._state === 3 /* STATE.STARTED */ || this._state === 5 /* STATE.RESUMED */)) {
4037
4054
  return;
4038
4055
  }
4056
+ // TODO - move to Android SlideApi adapter
4039
4057
  // обход бага на андроиде (вызывает pause/resume при любом нажатии на экран, даже если это клик - для перехода по слайдам)
4040
4058
  // поэтому делаем отложенный вызов (300мс) а если следом приходит stop - то отменяем таймер
4041
4059
  const pauseCb = () => {
@@ -4046,15 +4064,16 @@ let SlideApi$1 = class SlideApi {
4046
4064
  // stop pause event (from sdk) if _narrative_range_slider is active
4047
4065
  return;
4048
4066
  }
4049
- this._state = 6 /* STATE.PAUSE */;
4067
+ this._state = 8 /* STATE.USER_PAUSE */;
4050
4068
  // _log("pause: " + (performance.now() - window.start));
4051
4069
  this.slide.activeLayer.pause(false, false);
4052
4070
  // clean up
4053
4071
  if (this._pauseCbTimer != null) {
4054
4072
  clearTimeout(this._pauseCbTimer);
4055
4073
  }
4056
- this._state = 7 /* STATE.PAUSED */;
4074
+ this._state = 9 /* STATE.USER_PAUSED */;
4057
4075
  };
4076
+ // todo move to Android adapter
4058
4077
  if (this.sdkApi.isAndroid) {
4059
4078
  this._pauseCbTimer = this.layoutService.env.setTimeout(pauseCb, 300);
4060
4079
  }
@@ -4062,38 +4081,68 @@ let SlideApi$1 = class SlideApi {
4062
4081
  pauseCb();
4063
4082
  }
4064
4083
  }
4065
- async slideResume() {
4084
+ async slideUserResume() {
4066
4085
  if (this._pauseCbTimer != null) {
4067
4086
  // отменяем pause если есть (баг андроида - шлет pause/resume на простой клик)
4068
4087
  clearTimeout(this._pauseCbTimer);
4069
4088
  }
4070
- if (this._state !== 7 /* STATE.PAUSED */) {
4089
+ if (this._state !== 9 /* STATE.USER_PAUSED */) {
4071
4090
  return;
4072
4091
  }
4073
4092
  this._state = 4 /* STATE.RESUME */;
4074
4093
  // _log("resume: " + (performance.now() - window.start));
4075
- if (this._afterResumeQueue && Array.isArray(this._afterResumeQueue)) {
4076
- for (const job of this._afterResumeQueue) {
4094
+ // fallback for native sdk without user and app pause event
4095
+ if (!this._separateUserAndAppPause) {
4096
+ if (this._afterAppResumeQueue && Array.isArray(this._afterAppResumeQueue)) {
4097
+ for (const job of this._afterAppResumeQueue) {
4098
+ if (isFunction(job)) {
4099
+ job();
4100
+ }
4101
+ }
4102
+ this._afterAppResumeQueue = [];
4103
+ }
4104
+ }
4105
+ this.slide.activeLayer.resume();
4106
+ this._state = 5 /* STATE.RESUMED */;
4107
+ }
4108
+ /**
4109
+ * Call on app gone background
4110
+ */
4111
+ async slideAppPause() {
4112
+ this._state = 6 /* STATE.APP_PAUSE */;
4113
+ this.slide.activeLayer.pause(false, false);
4114
+ this._state = 7 /* STATE.APP_PAUSED */;
4115
+ }
4116
+ /**
4117
+ * Call on app gone foreground after a background
4118
+ */
4119
+ async slideAppResume() {
4120
+ if (this._state !== 7 /* STATE.APP_PAUSED */) {
4121
+ return;
4122
+ }
4123
+ this._state = 4 /* STATE.RESUME */;
4124
+ if (this._afterAppResumeQueue && Array.isArray(this._afterAppResumeQueue)) {
4125
+ for (const job of this._afterAppResumeQueue) {
4077
4126
  if (isFunction(job)) {
4078
4127
  job();
4079
4128
  }
4080
4129
  }
4081
- this._afterResumeQueue = [];
4130
+ this._afterAppResumeQueue = [];
4082
4131
  }
4083
4132
  this.slide.activeLayer.resume();
4084
4133
  this._state = 5 /* STATE.RESUMED */;
4085
4134
  }
4086
4135
  async slideStop(options) {
4087
- if (!(this._state === 3 /* STATE.STARTED */ || this._state === 5 /* STATE.RESUMED */ || this._state === 7 /* STATE.PAUSED */)) {
4136
+ if (!(this._state === 3 /* STATE.STARTED */ || this._state === 5 /* STATE.RESUMED */ || this._state === 9 /* STATE.USER_PAUSED */)) {
4088
4137
  return;
4089
4138
  }
4090
- this._state = 9 /* STATE.STOP */;
4139
+ this._state = 11 /* STATE.STOP */;
4091
4140
  if (this._pauseCbTimer != null) {
4092
4141
  // отменяем pause если есть (баг андроида - шлет pause/resume на простой клик)
4093
4142
  clearTimeout(this._pauseCbTimer);
4094
4143
  }
4095
4144
  await this.slide.activeLayer.stop(options);
4096
- this._state = 10 /* STATE.STOPPED */;
4145
+ this._state = 12 /* STATE.STOPPED */;
4097
4146
  }
4098
4147
  slideTimerEnd() {
4099
4148
  const defaultAction = () => {
@@ -4126,7 +4175,7 @@ let SlideApi$1 = class SlideApi {
4126
4175
  // skip state checking and sdk issues
4127
4176
  async slidePauseUI() {
4128
4177
  await this.slide.activeLayer.pause(false, false);
4129
- this._state = 8 /* STATE.FORCE_PAUSED */;
4178
+ this._state = 10 /* STATE.FORCE_PAUSED */;
4130
4179
  }
4131
4180
  // for call from SlideApi internals (from widgets)
4132
4181
  // skip state checking and sdk issues
@@ -4143,7 +4192,7 @@ let SlideApi$1 = class SlideApi {
4143
4192
  this._slideConfig.muted = true;
4144
4193
  }
4145
4194
  get isStopped() {
4146
- return this._state === 10 /* STATE.STOPPED */;
4195
+ return this._state === 12 /* STATE.STOPPED */;
4147
4196
  }
4148
4197
  afterStartInitQueuePush(cb) {
4149
4198
  if (!isFunction(cb)) {
@@ -4156,15 +4205,20 @@ let SlideApi$1 = class SlideApi {
4156
4205
  cb();
4157
4206
  }
4158
4207
  }
4159
- afterResumeQueuePush(cb) {
4208
+ afterAppResumeQueuePush(cb) {
4160
4209
  if (!isFunction(cb)) {
4161
4210
  return false;
4162
4211
  }
4163
- if ([4 /* STATE.RESUME */, 5 /* STATE.RESUMED */, 1 /* STATE.INITED */, 2 /* STATE.START */, 3 /* STATE.STARTED */].includes(this._state)) {
4212
+ let states = [4 /* STATE.RESUME */, 5 /* STATE.RESUMED */, 1 /* STATE.INITED */, 2 /* STATE.START */, 3 /* STATE.STARTED */, 8 /* STATE.USER_PAUSE */, 9 /* STATE.USER_PAUSED */];
4213
+ // fallback for native sdk without user and app pause event
4214
+ if (!this._separateUserAndAppPause) {
4215
+ states = [4 /* STATE.RESUME */, 5 /* STATE.RESUMED */, 1 /* STATE.INITED */, 2 /* STATE.START */, 3 /* STATE.STARTED */];
4216
+ }
4217
+ if (states.includes(this._state)) {
4164
4218
  cb();
4165
4219
  }
4166
4220
  else {
4167
- this._afterResumeQueue.push(cb);
4221
+ this._afterAppResumeQueue.push(cb);
4168
4222
  }
4169
4223
  }
4170
4224
  get activeLayer() {
@@ -4743,7 +4797,7 @@ let SlideApi$1 = class SlideApi {
4743
4797
  }
4744
4798
  }
4745
4799
  }
4746
- static get [Symbol.for("___CTOR_ARGS___")]() { return [`{\n sdkApi: SDKApi;\n slideWrapper: HTMLElement;\n viewport: Window;\n userResizeHandler?: (data: { viewportWidth: number; viewportHeight: number; fontSize: number }) => void;\n slideRatio: number;\n isFullscreen: boolean;\n slideLoadedCb?: (data: { slide: Slide; result: boolean; reason?: string }) => void;\n getViewportWidth: () => number;\n getViewportHeight: () => number;\n overlappingActionBarHeight?: number;\n }`]; }
4800
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`{\n sdkApi: SDKApi;\n slideWrapper: HTMLElement;\n viewport: Window;\n userResizeHandler?: (data: { viewportWidth: number; viewportHeight: number; fontSize: number }) => void;\n slideRatio: number;\n isFullscreen: boolean;\n slideLoadedCb?: (data: { cardId: number; slideIndex: number; result: boolean; reason?: string }) => void;\n getViewportWidth: () => number;\n getViewportHeight: () => number;\n overlappingActionBarHeight?: number;\n separateUserAndAppPause: boolean;\n }`]; }
4747
4801
  };
4748
4802
 
4749
4803
  const slideApiPeerDeps = {};
@@ -4792,6 +4846,7 @@ class SlideApi extends SlideApi$1 {
4792
4846
  getViewportWidth: () => slideWrapper.clientWidth,
4793
4847
  getViewportHeight: () => slideWrapper.clientHeight,
4794
4848
  overlappingActionBarHeight: config.overlappingActionBarHeight,
4849
+ separateUserAndAppPause: true,
4795
4850
  });
4796
4851
  }
4797
4852
  static get [Symbol.for("___CTOR_ARGS___")]() { return [`SDKInterface`, `{\n root: HTMLElement;\n slideRatio: number;\n isFullscreen: boolean;\n nonce?: string;\n viewport: Window;\n userResizeHandler?: (data: { viewportWidth: number; viewportHeight: number; fontSize: number }) => void;\n VODPlayer?: typeof VODPlayer;\n overlappingActionBarHeight?: number;\n }`]; }
@@ -17097,6 +17152,7 @@ class WidgetProducts extends WidgetBase {
17097
17152
  this.isOpen = true;
17098
17153
  // prevent next slide navigation gesture
17099
17154
  this.isClickCapturedByWidget = true;
17155
+ this.sdkApi.disableHorizontalSwipeGesture();
17100
17156
  this.sdkApi.disableVerticalSwipeGesture();
17101
17157
  this.sdkApi.disableBackpress();
17102
17158
  this._statEventWidgetOpen(this.currentModels);
@@ -17116,6 +17172,7 @@ class WidgetProducts extends WidgetBase {
17116
17172
  this.productsView?.classList.add("ias-products-container-view--hidden");
17117
17173
  this.element.classList.remove("hidden");
17118
17174
  this.isClickCapturedByWidget = false;
17175
+ this.sdkApi.enableHorizontalSwipeGesture();
17119
17176
  if (this.swipeGestureDetector != null) {
17120
17177
  this.swipeGestureDetector.destroy();
17121
17178
  this.swipeGestureDetector = null;
@@ -18575,6 +18632,7 @@ class WidgetRangeSlider extends WidgetBase {
18575
18632
  }
18576
18633
  e.preventDefault();
18577
18634
  this.isClickCapturedBySlider = true;
18635
+ this.sdkApi.disableHorizontalSwipeGesture();
18578
18636
  if (!this.maxHandlePos) {
18579
18637
  this.update(true, false);
18580
18638
  }
@@ -18604,6 +18662,7 @@ class WidgetRangeSlider extends WidgetBase {
18604
18662
  handleEnd(e) {
18605
18663
  this.env.requestAnimationFrame(() => {
18606
18664
  this.isClickCapturedBySlider = false;
18665
+ this.sdkApi.enableHorizontalSwipeGesture();
18607
18666
  });
18608
18667
  // e.preventDefault();
18609
18668
  this.env.document.removeEventListener("touchmove", this.handleMove);