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