{"version":3,"file":"7918.86e08d35390aaffe.js","mappings":"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","names":["PAGE","ClipsService","_ClipsService","constructor","store","sentryService","clipsApi","youtubeService","analyticsService","this","getPoster","clip","res","poster","DEFAULT_POSTER","youtube_id","getThumbnail","url","createClipFromFilestack","filestackResult","projectId","userId","_this","_asyncToGenerator","uploadTags","lastModifiedDate","duration","environment","production","console","log","warn","Error","newVideo","filename","type","mimetype","size","Date","toISOString","loading","originalFile","lastModified","convertVideoFileToClip","source","src","filestackConfig","storeTo","path","orig","key","name","file","id","Utils","removeFileExt","filmingDate","getDateTimeString","createClip","then","newClip","subClipsUpdated","dispatch","mystackActions","toFixed","seconds","durationInSeconds","clipUpload","error","DEBUG_LOGS","hlsMeta","HLS_META_TRANSCODE","Clip","clipActions","catch","err","Array","isArray","errors","length","errorType","info","message","params","sub","subscribeClipsUpdated","subscribe","next","updates","JSON","parse","hlsSrc","sources","Object","keys","isHlsComplete","unsubscribe","captureError","errorMessage","complete","getPosterTimeFromPoster","sNum","substring","lastIndexOf","parsed","parseInt","updatePosterToPosterTime","posterTime","newPoster","slice","startIndex","endIndex","handleSubClips","i0","i1","i2","i3","i4","i5","factory","ɵfac","providedIn","TabFabContainerComponent","_TabFabContainerComponent","_viewContainerRef","router","initialUrl","subscriptions","Subscription","ngAfterViewInit","attachPortal","subscription","events","pipe","filter","e","NavigationEnd","distinctUntilChanged","route","setTimeout","outlet","hasAttached","detach","add","ngOnDestroy","DomPortalOutlet","document","querySelector","portal","TemplatePortal","portalContent","attachTemplatePortal","selectors","viewQuery","rf","ctx","TabFabContainerComponent_ng_template_0_Template","PortalModule","encapsulation","list_r2","_r1","ngIf","ctx_r2","loadMoreStacks","headingWithDefault","_c1","layoutType","Carousel","_c0","stackList","items$","nextToken","label","CarouselGuidesComponent","_CarouselGuidesComponent","translate","LAYOUT_TYPE","listId","showListIfEmpty","ngOnInit","labelWithDefault","list$","select","selectList","selectStackListItems","shareReplay","stackActions","filters","GUIDES_PROJECT","FilterEntityTypes","Featured","q","instant","heading","list","inputs","standalone","features","decls","vars","consts","template","CarouselGuidesComponent_ng_container_0_Template","tmp_0_0","NgIf","AsyncPipe","StackListComponent","user_r2","$implicit","viewUserProfile","avatarFallback","tmp_4_0","undefined","tmp_5_0","tmp_6_0","UserListPopoverComponent","_UserListPopoverComponent","modalController","popoverCtrl","users","DEFAULT_USER_AVATAR_TERTIARY","modal","create","component","ProjectMemberModalComponent","componentProps","cssClass","dismiss","present","UserListPopoverComponent_ion_item_1_Template","IonLabel","IonAvatar","IonItem","IonList","NgFor","ImageFadeInDirective","ImageFallbackDirective","AvatarUrlPipe","styles","$event","_r4","viewUserList","hiddenUsersCount_r5","AvatarStackComponent","_AvatarStackComponent","_users","value","threshold","_threshold","changeDetectorRef","platform","modalOpened","EventEmitter","avatarStack","show","hide","avatarStackItemSize","avatarStackItemSizePx","onDestroy$","Subject","resize","refreshAvatarStack","forEach","u","i","selectMember","takeUntil","us","take","user","username","splitAvatarStackOnThreshold","_a","_b","_c","_d","currentThreshold","getDynamicThreshold","detectChanges","Math","floor","avatarStackEl","nativeElement","clientWidth","trackByFn","index","_this2","emit","event","_this3","popover","showBackdrop","data","selected","onDidDismiss","AvatarStackComponent_div_2_Template","AvatarStackComponent_div_3_Template","IonBadge","changeDetection","NoStackClipsDisclaimerComponent","_NoStackClipsDisclaimerComponent","configService","navCtrl","DISCOVER_LINK_ID","onDiscoverClick","preventDefault","stopPropagation","eltClass","target","attributes","getNamedItem","getStackDiscoverPath","navigateForward","hostBindings","TranslatePipe","_r2","onPlayerEnded","onVideoPlaying","onPlaylistDone","playerId","stack_r4","clips","currentPlaylistIndex$","isPageShowing","doHlsDestroy","project$","StackPlayPage_section_5_div_1_Template","hasStackClips","_r5","toggleExplore","i_r8","_r7","playIndex","clip_r9","isVideoPlaying","currentClipDetail_r10","description","StackPlayPage_ng_container_8_div_2_div_9_div_1_div_7_Template","isShowingClipDetails","tmp_16_0","title","StackPlayPage_ng_container_8_div_2_div_9_div_1_Template","_r11","pausePlayer","avatarStackThreshold","contributors","_c2","tmp_9_0","_c3","stack_r12","stackId","_c4","routeProjectDetail","project_r13","routerLinkJoin","_r14","approveStack","StackPlayPage_ng_container_8_div_2_div_25_ion_spinner_3_Template","approvingStack","_r15","_r16","confirmTranscode","StackPlayPage_ng_container_8_div_2_div_27_ion_item_1_ion_spinner_3_Template","StackPlayPage_ng_container_8_div_2_div_27_ion_item_1_span_6_Template","optimizingStack","isAllClipsHls","StackPlayPage_ng_container_8_div_2_div_27_ion_item_1_Template","dtePublished","hasYoutubeClips","StackPlayPage_ng_container_8_div_2_fs_thumbnail_poster_4_Template","_r6","togglePlaylist","StackPlayPage_ng_container_8_div_2_div_9_Template","StackPlayPage_ng_container_8_div_2_ng_container_17_Template","StackPlayPage_ng_container_8_div_2_ng_template_18_Template","StackPlayPage_ng_container_8_div_2_div_20_Template","StackPlayPage_ng_container_8_div_2_div_22_Template","StackPlayPage_ng_container_8_div_2_div_24_Template","StackPlayPage_ng_container_8_div_2_div_25_Template","StackPlayPage_ng_container_8_div_2_div_26_Template","StackPlayPage_ng_container_8_div_2_div_27_Template","openTabFab","fabClick","addAllClipsToStack","addClipToStack","isPlaylistOpen","enableClipDetails","currentClip$","dteSaved","views","shares","singleContributor_r17","currentUserId$","showJoinButton","isProjectAdmin","isProjectModerated","isApproved","isStackPublic","doHlsDebug","isSiteAdmin","canApprove","isProjectMember","StackPlayPage_ng_container_8_div_1_Template","StackPlayPage_ng_container_8_div_2_Template","enableExplore","isExploreOpen","noClips_r18","StackPlayPage_ng_template_12_div_0_Template","STACK_PLAY_PLAYER_ID","StackPlayPage","_StackPlayPage","activatedRoute","snapshot","paramMap","get","inviteType","toLowerCase","alertCtrl","toaster","projectService","projectMemberService","stackService","clipsService","userService","videoPlayerService","videoService","tokensService","renderer","pageTitle","ENABLE_EXPLORE","isStackLoading","userId$","PROJECT_DETAIL_ROUTE","selectedItemSuccess$","BehaviorSubject","topDrawerExpand$","topDrawerClose$","_wasPageShowing","isFabOpen","_playlistSelected","_incExpandEvent","_incCloseEvent","token$","onOrientationChange","orient","ready","is","stack$","selectAndGetPlay","x","y","playlist","stringify","tap","stack","clearTimeout","contributorTimeout","loadMembers","userIds","map","c","privacy","STACK_PRIVACY","PUBLIC","getProjectPreview","p","project","isModerated","getInviteTypeFromProject","loadingTimeout","providerId","HLS_META_UPGRADE_PROP","sendStackForHLSTranscode","selectCurrentPlayIndex","currentPlaylistIndex","getSelectedStackCurrentPlayClip","currentClip","ClipActions","t","isTokenExpired","token","projectRole","eventType","payload","returnUrl","isLandscape","userIsGlobalAdmin$","isAdmin","window","addEventListener","evt","ionViewWillEnter","ionViewWillLeave","closeTabFab","pause","play","scrollToItem","playlistScroller","smoothScrollTo","expandDraftDrawer","showCreateForm","closeDraftDrawer","tabFab","activated","close","isCreateNew","draftDrawerExpanded","draftDrawerSelected","draftDrawerNewItem","navigate","_ref2","_x","apply","arguments","header","subHeader","buttons","text","role","handler","_","i6","i7","i8","i9","i10","i11","i12","i13","IonContent","StackPlayPage_section_5_Template","StackPlayPage_ng_container_8_Template","StackPlayPage_ng_template_10_Template","StackPlayPage_ng_template_12_Template","loading_r19","RouterLink","FormsModule","i14","StackPopoverActionsComponent","TopNavbarComponent","ThumbnailPosterComponent","UploaderStatsComponent","VideoPlayerComponent","IonHeader","IonButton","IonIcon","IonThumbnail","IonSpinner","IonText","IonToggle","IonNote","IonFab","IonFabButton","IonFabList","IonChip","IonCard","IonCardContent","IonSkeletonText"],"ignoreList":[],"sourceRoot":"webpack:///","sources":["./src/app/clips/shared/services/clips.service.ts","./src/app/shared/components/tab-fab-container/tab-fab-container.component.html","./src/app/shared/components/tab-fab-container/tab-fab-container.component.ts","./src/app/stacks/carousels/carousel-guides/carousel-guides.component.html","./src/app/stacks/carousels/carousel-guides/carousel-guides.component.ts","./src/app/shared/components/user-list-popover/user-list-popover.component.html","./src/app/shared/components/user-list-popover/user-list-popover.component.ts","./src/app/shared/components/ui/avatar-stack/avatar-stack.component.html","./src/app/shared/components/ui/avatar-stack/avatar-stack.component.ts","./src/app/stacks/shared/components/no-stack-clips-disclaimer/no-stack-clips-disclaimer.component.ts","./src/app/stacks/stack-play/stack-play.page.html","./src/app/stacks/stack-play/stack-play.page.ts"],"sourcesContent":["/** @format */\n\nimport { Injectable } from '@angular/core';\nimport { Store } from '@ngrx/store';\nimport { State } from '@store/reducers';\nimport * as clipActions from '@store/actions/clips.actions';\nimport * as mystackActions from '@store/actions/mystack.actions';\nimport { ClipsApiService } from '@app/core/api/clips-api.service';\nimport { AnalyticsService } from '@app/core/services/analytics/analytics.service';\nimport { SentryService } from '@app/core/services/sentry.service';\nimport { YoutubeService } from '@app/core/services/youtube.service';\nimport { Utils } from '@app/shared/utils';\nimport { ClipVideoFile, Clip } from '@app/shared/models/clip.model';\nimport { convertVideoFileToClip, isHlsComplete } from '@app/shared/models/clip.model';\nimport { HLS_META_TRANSCODE, DEFAULT_POSTER } from '@app/shared/models/clip.model';\nimport { environment, filestackConfig } from 'src/environments/environment';\n\nconst DEBUG_LOGS = false;\nconst PAGE = '[ClipsService]';\n\n@Injectable({\n  providedIn: 'root',\n})\nexport class ClipsService {\n  constructor(\n    private store: Store<State>,\n    private sentryService: SentryService,\n    private clipsApi: ClipsApiService,\n    private youtubeService: YoutubeService,\n    private analyticsService: AnalyticsService\n  ) {}\n\n  getPoster(clip: Clip, res: string = 'default') {\n    let poster = DEFAULT_POSTER;\n    if (clip) {\n      if (clip.poster) {\n        poster = clip.poster;\n      } else if (clip.youtube_id) {\n        poster = this.youtubeService.getThumbnail(clip.youtube_id, res).url;\n      }\n    }\n    return poster;\n  }\n\n  /**\n   * Create a new Clip from the FileStack Upload\n   */\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  async createClipFromFilestack(filestackResult: any, projectId: string, userId: string) {\n    DEBUG_LOGS && console.log(`createClipFromFilestack filestackResult =`, filestackResult);\n    const {\n      uploadTags: {\n        lastModifiedDate = null, // = (new Date()).toISOString(),\n        // filesize = filestackResult.size, // don't use the stringified from uploadTags\n        duration = 0,\n      } = {},\n    } = filestackResult;\n    // MVP-1169 file selected metadata\n    !environment.production &&\n      console.log(`get size & updatedDate from filestackResult:`, { lastModifiedDate, duration, filestackResult });\n\n    if (!filestackResult || !projectId) {\n      console.warn(`${PAGE} createClipFromFilestack missing required params`, { filestackResult, projectId });\n      throw new Error('Missing required parameters - unable to create clip.');\n    }\n\n    const newVideo: ClipVideoFile = {\n      filename: filestackResult.filename,\n      type: filestackResult.mimetype,\n      size: filestackResult.size,\n      lastModifiedDate: new Date().toISOString(),\n      loading: true,\n    };\n\n    // get additional metadata if it exists.\n    if (lastModifiedDate) {\n      newVideo.lastModifiedDate = lastModifiedDate;\n    } else if (filestackResult.originalFile) {\n      if (\n        filestackResult.originalFile.lastModifiedDate &&\n        typeof filestackResult.originalFile.lastModifiedDate.toISOString === 'function'\n      ) {\n        newVideo.lastModifiedDate = filestackResult.originalFile.lastModifiedDate.toISOString();\n      } else if (filestackResult.originalFile.lastModified) {\n        newVideo.lastModifiedDate = new Date(filestackResult.originalFile.lastModified).toISOString();\n      }\n    }\n\n    // create our clip...\n    const clip = convertVideoFileToClip(newVideo);\n    clip.source = clip.source || {};\n    // it is important that this startsWith(filestackConfig.storeTo.path) in the clipApi logic\n    clip.source.src = filestackConfig.storeTo.clip.path + newVideo.filename;\n    clip.source.orig = filestackResult.key;\n    clip.source.filename = newVideo.filename;\n    clip.source.type = newVideo.type;\n    clip.source.loading = newVideo.loading;\n    clip.source.lastModifiedDate = newVideo.lastModifiedDate;\n\n    if (filestackResult.originalFile && filestackResult.originalFile.name) {\n      clip.source.file = filestackResult.originalFile;\n    }\n    // this must match for api to do its magic...\n    clip.id = Utils.removeFileExt(newVideo.filename);\n    clip.projectId = projectId;\n\n    if (typeof clip.filmingDate !== 'string') {\n      clip.filmingDate = Utils.getDateTimeString(clip.filmingDate);\n    }\n\n    DEBUG_LOGS && console.log(`${PAGE} createClipFromFilestack -> createClip:`, clip);\n\n    // kick off the createClip flow, subscribe to updates, add to mystack\n    // as soon as we return, the Capture Page will nav to the Stack Editor\n    return this.createClip(clip).then((newClip) => {\n      DEBUG_LOGS &&\n        console.log(`${PAGE} createClipFromFilestack -> now watch updates & addToStack (createClip result:`, newClip);\n      // watch changes and push to store\n      this.subClipsUpdated(newClip.projectId, newClip.id, userId);\n      // add the clip to the Editor\n      this.store.dispatch(mystackActions.addClip({ clip: newClip }));\n\n      try {\n        // analytics\n        const size =\n          newVideo && newVideo.size && typeof newVideo.size.toFixed === 'function' ? newVideo.size.toFixed(0) : false;\n        const seconds =\n          clip.source && clip.source.durationInSeconds && typeof clip.source.durationInSeconds.toFixed === 'function'\n            ? clip.source.durationInSeconds.toFixed(3)\n            : false;\n        this.analyticsService.clipUpload({\n          projectId: newClip.projectId,\n          id: newClip.id,\n          userId: newClip.userId,\n          ...(seconds && { seconds }),\n          ...(size && { size }),\n        });\n      } catch (error) {\n        console.warn(`Analytics error:`, error);\n      }\n    });\n  }\n\n  /**\n   * upload clip and add to store\n   * @param clip\n   * 1. Create the clip in DB\n   * 2.\n   */\n  createClip(clip: Clip): Promise<Clip> {\n    DEBUG_LOGS && console.log(`${PAGE} createClip`, clip);\n\n    // add the new HLS transcoding instruction\n    clip.hlsMeta = {\n      ...(clip.hlsMeta || {}),\n      ...HLS_META_TRANSCODE,\n    };\n\n    return this.clipsApi\n      .createClip(clip)\n      .then((res) => {\n        DEBUG_LOGS && console.log(`${PAGE} createClip res:`, res);\n        // add the clip to the Store\n        const newClip = new Clip(res);\n        this.store.dispatch(clipActions.addClip({ clip: newClip }));\n        return newClip;\n      })\n      .catch((err) => {\n        if (\n          err &&\n          Array.isArray(err.errors) &&\n          err.errors.length > 0 &&\n          err.errors[0] &&\n          err.errors[0].errorType &&\n          err.errors[0].errorType === 'DynamoDB:ConditionalCheckFailedException'\n        ) {\n          console.info(`${PAGE} createClip already Exists:`, err);\n          return new Clip(clip);\n        }\n        console.error(`${PAGE} createClip err:`, err);\n        if (err && Array.isArray(err.errors) && err.errors.length > 0 && err.errors[0].message) {\n          throw err.errors[0].message;\n        }\n        throw err;\n      });\n  }\n\n  /**\n   * clipUpdate GraphQL Subscription\n   */\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  subClipsUpdated(projectId: string, id = '', userId = '') {\n    const params: { projectId: string; id?: string } = {\n      projectId,\n    };\n    if (id) {\n      params.id = id;\n    }\n    // not currently using userId on this GQL subscription in the API\n    // if (userId) {  params.userId = userId; }\n\n    // keeping the sub variable local so there can be multiple open subs\n    const sub = this.clipsApi.subscribeClipsUpdated(params).subscribe({\n      next: (res) => {\n        // todo: convert to handleSubClips(res) when this not needed by editor\n        DEBUG_LOGS && console.log(`${PAGE} clipsUpdatedSubscription next:`, res);\n        if (!res || !res.id || !res.projectId) {\n          throw new Error('Missing clip id in subscription?');\n        }\n        const updates: Partial<Clip> = {};\n        let hlsMeta;\n        if (res.hlsMeta) {\n          try {\n            hlsMeta = typeof res.hlsMeta === 'string' ? JSON.parse(res.hlsMeta) : res.hlsMeta;\n            updates.hlsMeta = hlsMeta;\n          } catch (error) {\n            console.log(`Caught error during JSON.parse(res.hlsMeta):`, {\n              hlsMeta: res.hlsMeta,\n              error: error.message || error,\n            });\n          }\n        }\n        if (res.hlsSrc) {\n          updates.hlsSrc = res.hlsSrc;\n        }\n        if (Array.isArray(res.sources) && res.sources.length > 0) {\n          updates.sources = res.sources;\n        }\n        if (res.poster) {\n          updates.poster = res.poster;\n        }\n        if (res.duration) {\n          updates.duration = res.duration;\n        }\n\n        if (Object.keys(updates).length > 0) {\n          // take the updates and flow to store...\n          this.store.dispatch(\n            clipActions.updateClipTranscoding({\n              projectId: res.projectId,\n              id: res.id,\n              updates,\n            })\n          );\n          DEBUG_LOGS &&\n            console.log(`${PAGE} clipsUpdatedSubscription updateClipTranscoding:`, {\n              projectId: res.projectId,\n              id: res.id,\n              updates,\n            });\n        }\n\n        if (isHlsComplete(new Clip(updates))) {\n          // when complete, this.unsubClipsUpdated()\n          sub.unsubscribe();\n        }\n      },\n      error: (err) => {\n        console.warn(`${PAGE} clipsUpdatedSubscription ERROR:`, err);\n        this.sentryService.captureError(err);\n\n        if (projectId && id) {\n          this.store.dispatch(\n            clipActions.updateClipTranscoding({\n              projectId,\n              id,\n              updates: {\n                hlsMeta: {\n                  errorMessage: err.message || err.errorMessage || err,\n                },\n              },\n            })\n          );\n        }\n        sub.unsubscribe();\n      },\n      complete: () => {\n        DEBUG_LOGS && console.log(`${PAGE} clipsUpdatedSubscription => Complete`);\n      },\n    });\n  }\n  //end GraphQL Subscription\n\n  /**\n   * Take the poster string and return poster time from the transcoded name\n   * example poster path:\n   * https://videos.filmstacker.com/public/filmstacker-dev/jd_-_jd-note_202203021348/jd_-_jd-note_202203021348_thumb.0000000.jpg\n   */\n  getPosterTimeFromPoster(clip: Clip) {\n    if (clip && clip.poster) {\n      const sNum = clip.poster.substring(clip.poster.lastIndexOf('_thumb.'), clip.poster.lastIndexOf('.'));\n      // there shouldn't be any dashes anymore\n      // const sTime = sNum.replace(/-/g, '').replace(/0/gi, '');\n      try {\n        const parsed = parseInt(sNum, 10);\n        return parsed > 0 ? parsed : 0;\n      } catch (error) {\n        return 0;\n      }\n    }\n    return 0;\n  }\n\n  /**\n   * Update the poster image to match the new posterTime\n   *\n   * @todo verify it exists in s3\n   * potential ref: https://stackoverflow.com/questions/9815762/detect-when-an-image-fails-to-load-in-javascript\n   *\n   * example poster path:\n   * https://videos.filmstacker.com/public/filmstacker-dev/jd_-_jd-note_202203021348/jd_-_jd-note_202203021348_thumb.0000000.jpg\n   */\n  updatePosterToPosterTime(clip: Clip, posterTime: number) {\n    if (clip && clip.poster) {\n      let newPoster = clip.poster;\n      const sNum = ('0000000' + posterTime).slice(-7);\n      const startIndex = newPoster.lastIndexOf('_thumb.') + '_thumb.'.length;\n      const endIndex = newPoster.lastIndexOf('.');\n      newPoster = newPoster.slice(0, startIndex) + sNum + newPoster.slice(endIndex);\n      console.log(`${PAGE} change clip.poster (TODO: verify it exists in s3) posterTime: ${posterTime} to:`, {\n        sNum,\n        newPoster,\n      });\n      return newPoster;\n    } else {\n      console.warn(`${PAGE} missing clip.poster - unable to change`, clip);\n      return null;\n    }\n  }\n\n  /**\n   * @deprecated unused - use subClipsUpdated\n   * Do what we need with the clip we just received\n   */\n  private handleSubClips(res) {\n    DEBUG_LOGS && console.log(`${PAGE} handleSubClips next:`, res);\n    if (!res || !res.id || !res.projectId) {\n      throw new Error('Missing clip id in subscription?');\n    }\n    // if any values exist not null, add them as changes?\n    const updates: Partial<Clip> = {};\n    let hlsMeta;\n    if (res.hlsMeta) {\n      try {\n        hlsMeta = typeof res.hlsMeta === 'string' ? JSON.parse(res.hlsMeta) : res.hlsMeta;\n        updates.hlsMeta = hlsMeta;\n      } catch (error) {\n        console.log(`Caught error during JSON.parse(res.hlsMeta):`, {\n          hlsMeta: res.hlsMeta,\n          error: error.message || error,\n        });\n      }\n    }\n    if (res.hlsSrc) {\n      updates.hlsSrc = res.hlsSrc;\n    }\n    if (Array.isArray(res.sources) && res.sources.length > 0) {\n      updates.sources = res.sources;\n    }\n    if (res.poster) {\n      updates.poster = res.poster;\n    }\n    if (res.duration) {\n      updates.duration = res.duration;\n    }\n\n    // take the updates and flow to store...\n    // this.store.dispatch(clipActions.updateClipTranscoding({\n    //   projectId: res.projectId,\n    //   id: res.id,\n    //   updates,\n    // }));\n  }\n}\n","<!-- @format -->\n\n<ng-template #portalContent><ng-content></ng-content></ng-template>\n","/** @format */\n\nimport { PortalModule, DomPortalOutlet, TemplatePortal } from '@angular/cdk/portal';\nimport { AfterViewInit, Component, OnDestroy, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core';\nimport { NavigationEnd, Router, RouterEvent, Event as RouterEvents } from '@angular/router';\nimport { Subscription } from 'rxjs';\nimport { distinctUntilChanged, filter } from 'rxjs/operators';\n\n@Component({\n  selector: 'fs-tab-fab-container',\n  templateUrl: './tab-fab-container.component.html',\n  standalone: true,\n  imports: [PortalModule],\n})\nexport class TabFabContainerComponent implements OnDestroy, AfterViewInit {\n  @ViewChild('portalContent') portalContent: TemplateRef<unknown>;\n\n  outlet: DomPortalOutlet;\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  portal: TemplatePortal<any>;\n\n  initialUrl = this.router.url;\n\n  private subscriptions = new Subscription();\n\n  constructor(private _viewContainerRef: ViewContainerRef, private router: Router) {}\n\n  ngAfterViewInit() {\n    this.attachPortal();\n    // watch over route changes to detach or re-attach portals.\n    // reason: if a route has a defined portal in its template and the user routes away from it,\n    // that route only gets detached from the change detection. thus it will stay in the DOM, no update logic.\n    // that is why we work on the update logic manually ourselves.\n    const subscription = this.router.events\n      .pipe(\n        filter((e: Event | RouterEvent | RouterEvents): e is RouterEvent => e instanceof NavigationEnd),\n        distinctUntilChanged()\n      )\n      .subscribe((route: RouterEvent) => {\n        if (route.url === this.initialUrl) {\n          // for change detection reasons we need to delay this operation\n          setTimeout(() => {\n            this.attachPortal();\n          });\n        }\n        if (this.outlet.hasAttached()) {\n          this.outlet.detach();\n        }\n      });\n    this.subscriptions.add(subscription);\n  }\n\n  ngOnDestroy() {\n    this.subscriptions.unsubscribe();\n  }\n\n  private attachPortal() {\n    this.outlet = new DomPortalOutlet(document.querySelector('#tab-portal-container'));\n    this.portal = new TemplatePortal(this.portalContent, this._viewContainerRef);\n    this.outlet.attachTemplatePortal(this.portal);\n  }\n}\n","<ng-container *ngIf=\"((stackList.items$ | async)?.length > 0 || showListIfEmpty) && (stackList.list$ | async) as list\">\n  <h3>{{ headingWithDefault }}</h3>\n  <app-stack-list \n    [layout]=\"{\n      type: layoutType.Carousel,\n      options: {\n        hasAddNewItemButton: false\n      }\n    }\"\n    [items]=\"stackList.items$ | async\"\n    [canLoadMore]=\"!!list.nextToken\"\n    [isLoading]=\"list.loading\"\n    [heading]=\"stackList.label\"\n    (loadMore)=\"loadMoreStacks(list)\"\n  ></app-stack-list>\n</ng-container>\n\n","/** @format */\n\nimport { Component, Input, OnInit } from '@angular/core';\nimport { NgIf, AsyncPipe } from '@angular/common';\nimport { shareReplay } from 'rxjs/operators';\nimport { TranslateService } from '@ngx-translate/core';\nimport { Store } from '@ngrx/store';\nimport { State } from '@store/reducers';\nimport * as stackActions from '@store/actions/stacks.actions';\nimport { List, selectList, selectStackListItems } from '@store/selectors/lists.selectors';\nimport { FilterEntityTypes } from '@store/selectors/viewstate.selectors';\nimport { GUIDES_PROJECT } from '@app/app.config';\nimport { LAYOUT_TYPE } from '@app/shared/models/layout.model';\nimport { StackList } from '@app/shared/models/list.model';\nimport { StackListComponent } from '@app/stacks/shared/components/stack-list/stack-list.component';\n\nconst CAROUSEL_GUIDES_LIST_ID = 'carousel_guides';\nconst CAROUSEL_GUIDES_HEADING = 'DISCOVER.GUIDES.HEADING';\nconst CAROUSEL_GUIDES_LABEL = 'DISCOVER.GUIDES.LABEL';\n\n@Component({\n  selector: 'fs-carousel-guides',\n  templateUrl: './carousel-guides.component.html',\n  styleUrls: ['./carousel-guides.component.scss'],\n  standalone: true,\n  imports: [NgIf, AsyncPipe, StackListComponent],\n})\nexport class CarouselGuidesComponent implements OnInit {\n  stackList: StackList;\n  layoutType = LAYOUT_TYPE;\n\n  @Input() heading: string;\n  @Input() label: string;\n  @Input() listId = CAROUSEL_GUIDES_LIST_ID;\n  @Input() showListIfEmpty = true;\n\n  constructor(private translate: TranslateService, private store: Store<State>) {}\n\n  ngOnInit() {\n    this.stackList = {\n      id: this.listId,\n      label: this.labelWithDefault,\n      list$: this.store.select(selectList(this.listId)),\n      items$: this.store.select(selectStackListItems(this.listId)).pipe(shareReplay(1)),\n    };\n\n    this.store.dispatch(\n      stackActions.loadFilteredStacks({\n        listId: this.listId,\n        filters: {\n          // : FilterEntity\n          projectId: GUIDES_PROJECT,\n          type: FilterEntityTypes.Featured,\n          id: this.listId,\n          q: null,\n        },\n      })\n    );\n  }\n\n  get labelWithDefault() {\n    return this.label ?? this.translate.instant(CAROUSEL_GUIDES_LABEL);\n  }\n\n  get headingWithDefault() {\n    return this.heading ?? this.translate.instant(CAROUSEL_GUIDES_HEADING);\n  }\n\n  loadMoreStacks(list: List) {\n    this.store.dispatch(\n      stackActions.loadMoreFilteredStacks({\n        listId: list.id,\n        filters: list.filters,\n        nextToken: list.nextToken,\n      })\n    );\n  }\n}\n","<ion-list class=\"light users-popover\" lines=\"none\">\n  <ion-item\n    *ngFor=\"let user of users\"\n    button\n    small\n    detail=\"false\"\n    (click)=\"viewUserProfile(user.userId)\"\n  >\n    <ion-avatar class=\"users-popover__avatar\" slot=\"start\">\n      <img\n        class=\"users-popover__avatar__image\"\n        [src]=\"user.userId | avatarUrl:'dark'\"\n        [fallback]=\"avatarFallback\"\n        imageFadeIn\n        [alt]=\"user?.name ?? user.userId\"\n        [title]=\"user?.name ?? user.userId\"\n      />\n    </ion-avatar>\n    <!-- <ion-text style=\"padding-left: 0; white-space: nowrap\" slot=\"start\"> -->\n    <ion-label>\n      {{ user?.name ?? user.userId }}\n    </ion-label>\n  </ion-item>\n</ion-list>\n","/** @format */\n\nimport { Component, Input } from '@angular/core';\nimport { NgFor } from '@angular/common';\nimport { ModalController, PopoverController, IonList, IonItem, IonAvatar, IonLabel } from '@ionic/angular/standalone';\nimport { User, DEFAULT_USER_AVATAR_TERTIARY } from '@app/shared/models/user.model';\nimport { AvatarUrlPipe } from '@app/shared/pipes/avatar-url.pipe';\nimport { ImageFadeInDirective } from '@app/shared/directives/image-fade-in.directive';\nimport { ImageFallbackDirective } from '@app/shared/directives/image-fallback.directive';\nimport { ProjectMemberModalComponent } from '@app/project-members/project-member-modal/project-member-modal.component';\n\n@Component({\n  selector: 'app-user-list-popover',\n  templateUrl: './user-list-popover.component.html',\n  styleUrls: ['./user-list-popover.component.scss'],\n  standalone: true,\n  imports: [IonLabel, IonAvatar, IonItem, IonList, NgFor, ImageFadeInDirective, ImageFallbackDirective, AvatarUrlPipe],\n})\nexport class UserListPopoverComponent {\n  @Input() users: Partial<User>[] = [];\n\n  avatarFallback = DEFAULT_USER_AVATAR_TERTIARY;\n\n  constructor(private modalController: ModalController, private popoverCtrl: PopoverController) {}\n\n  async viewUserProfile(userId: string) {\n    const modal = await this.modalController.create({\n      component: ProjectMemberModalComponent,\n      componentProps: {\n        userId,\n      },\n      cssClass: 'modal-lg',\n    });\n    this.popoverCtrl.dismiss({ userId });\n    return await modal.present();\n  }\n}\n","<div class=\"avatar-stack\" #avatarStackContainer>\n  <div class=\"avatar-stack__item\" *ngFor=\"let user of avatarStack.show; trackBy: trackByFn\">\n    <ion-avatar class=\"avatar-stack__item__avatar\">\n      <img class=\"avatar-stack__item__avatar__image\"\n        [src]=\"user.userId | avatarUrl\"\n        [fallback]\n        imageFadeIn\n        [alt]=\"user.userId\"\n        [title]=\"user.name || user.userId\"\n        (click)=\"viewUserProfile(user.userId)\" />\n    </ion-avatar>\n  </div>\n  <div class=\"avatar-stack__item\" *ngIf=\"avatarStack?.hide?.length; let hiddenUsersCount\">\n    <ion-badge\n      class=\"avatar-stack__item__badge\"\n      color=\"primary\"\n      (click)=\"viewUserList($event)\"\n    >+{{hiddenUsersCount}}\n  </ion-badge>\n  </div>\n</div>","/** @format */\n\nimport {\n  Component,\n  Input,\n  OnInit,\n  ViewChild,\n  ElementRef,\n  HostBinding,\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  OnDestroy,\n  EventEmitter,\n  Output,\n} from '@angular/core';\nimport { NgFor, NgIf } from '@angular/common';\nimport { IonAvatar, IonBadge, ModalController, Platform, PopoverController } from '@ionic/angular/standalone';\nimport { Subject } from 'rxjs';\nimport { filter, take, takeUntil } from 'rxjs/operators';\nimport { Store } from '@ngrx/store';\nimport { selectMember } from '@store/selectors/members.selectors';\nimport { User } from '@app/shared/models/user.model';\nimport { UserListPopoverComponent } from '@app/shared/components/user-list-popover/user-list-popover.component';\nimport { ImageFallbackDirective } from '@app/shared/directives/image-fallback.directive';\nimport { AvatarUrlPipe } from '@app/shared/pipes/avatar-url.pipe';\nimport { ProjectMemberModalComponent } from '@app/project-members/project-member-modal/project-member-modal.component';\n\n/** it is more interesting to show all users than just the hidden ones */\nconst SHOW_ALL_IN_POPUP = true;\n\n@Component({\n  selector: 'fs-avatar-stack',\n  templateUrl: './avatar-stack.component.html',\n  styleUrls: ['./avatar-stack.component.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  standalone: true,\n  imports: [NgFor, NgIf, ImageFallbackDirective, AvatarUrlPipe, IonAvatar, IonBadge],\n})\nexport class AvatarStackComponent implements OnInit, AfterViewInit, OnDestroy {\n  @Input()\n  get users() {\n    return this._users;\n  }\n  set users(value: Partial<User>[]) {\n    this._users = value;\n  }\n\n  @Input()\n  get threshold() {\n    return this._threshold;\n  }\n  set threshold(value: number) {\n    this._threshold = value;\n  }\n\n  @Output() modalOpened = new EventEmitter<string>();\n\n  public avatarStack = {\n    show: [],\n    hide: [],\n  };\n\n  @ViewChild('avatarStackContainer', { static: false }) avatarStackEl: ElementRef;\n\n  private _threshold: number;\n  private avatarStackItemSize = 36;\n  @HostBinding('style.--avatar-size')\n  private avatarStackItemSizePx = `${this.avatarStackItemSize}px`;\n\n  /** inner users for names */\n  private _users: Partial<User>[] = [];\n\n  private onDestroy$ = new Subject<void>();\n\n  constructor(\n    private store: Store,\n    private changeDetectorRef: ChangeDetectorRef,\n    private modalController: ModalController,\n    private platform: Platform,\n    private popoverCtrl: PopoverController\n  ) {}\n\n  ngOnInit(): void {\n    this.platform.resize.subscribe(async () => {\n      this.refreshAvatarStack();\n    });\n\n    (this.users || []).forEach((u, i) => {\n      if (u?.userId) {\n        this.store\n          .select(selectMember(u.userId))\n          .pipe(\n            takeUntil(this.onDestroy$),\n            filter((us) => us?.userId?.length > 0),\n            take(1)\n          )\n          .subscribe((user) => {\n            if (user?.userId) {\n              this._users[i].name = user.name || user.username || user.userId;\n            }\n          });\n      }\n    });\n  }\n\n  ngAfterViewInit(): void {\n    this.refreshAvatarStack();\n    const REFRESH_EL_DELAY = 1000;\n    setTimeout(() => {\n      // First iteration could omit side elements, observed on stack-play where content-actions side-bar width is omitted by getDynamicThreshold.\n      this.refreshAvatarStack();\n    }, REFRESH_EL_DELAY);\n  }\n\n  ngOnDestroy(): void {\n    this.onDestroy$.next();\n    this.onDestroy$.complete();\n  }\n\n  splitAvatarStackOnThreshold(threshold: number) {\n    /**\n     * Avoid showing only one more Elt badge\n     */\n    if (this.users?.slice(threshold).length === 1) {\n      threshold = this.users?.length;\n    }\n    this.avatarStack = {\n      show: this.users?.slice(0, threshold),\n      hide: this.users?.slice(threshold),\n    };\n  }\n\n  refreshAvatarStack() {\n    const currentThreshold = this.threshold ?? this.getDynamicThreshold();\n\n    this.splitAvatarStackOnThreshold(currentThreshold);\n    this.changeDetectorRef.detectChanges();\n  }\n\n  /**\n   * Min threshold is 1, to avoid showing only more Elt w/o any avatar\n   */\n  getDynamicThreshold(): number {\n    const avatarStackWidth = this.avatarStackEl.nativeElement.clientWidth;\n    const threshold = Math.floor(avatarStackWidth / this.avatarStackItemSize) - 2;\n\n    return threshold > 0 ? threshold : 1;\n  }\n\n  trackByFn(index, user) {\n    return user?.userId ?? index;\n  }\n\n  async viewUserProfile(id: string) {\n    const modal = await this.modalController.create({\n      component: ProjectMemberModalComponent,\n      componentProps: {\n        userId: id,\n      },\n      cssClass: 'modal-lg',\n    });\n    this.modalOpened.emit(id);\n    return await modal.present();\n  }\n\n  async viewUserList(event: MouseEvent) {\n    const users = SHOW_ALL_IN_POPUP ? this.users : this.avatarStack?.hide ?? [];\n    const popover = await this.popoverCtrl.create({\n      component: UserListPopoverComponent,\n      componentProps: {\n        users,\n      },\n      cssClass: 'user-list-popover',\n      showBackdrop: false, // allow to see video when opened\n      event,\n    });\n    await popover.present();\n    const { data: { userId: selected = '' } = {} } = await popover.onDidDismiss();\n    if (selected) {\n      this.modalOpened.emit(selected);\n    }\n  }\n}\n","/** @format */\n\nimport { Component, HostListener } from '@angular/core';\nimport { NavController } from '@ionic/angular/standalone';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { ConfigService } from '@app/core/config/config.service';\n\n@Component({\n  selector: 'app-no-stack-clips-disclaimer',\n  template: `\n    <div class=\"ion-padding\">\n      <h2>{{ 'PLAYER.INTRO_HEADER' | translate }}</h2>\n      <p [innerHTML]=\"'PLAYER.INTRO_TEXT' | translate\"></p>\n    </div>\n  `,\n  // styles: [':host >>> span { color: red; }'],\n  styleUrls: ['./no-stack-clips-disclaimer.component.scss'],\n  standalone: true,\n  imports: [TranslatePipe],\n})\nexport class NoStackClipsDisclaimerComponent {\n  DISCOVER_LINK_ID = 'discover_link';\n\n  constructor(private configService: ConfigService, private navCtrl: NavController) {}\n\n  @HostListener('click', ['$event'])\n  onDiscoverClick(event: Event) {\n    event.preventDefault();\n    event.stopPropagation();\n    const elt = event.target as HTMLElement;\n    const eltClass = elt.attributes.getNamedItem('class');\n    if (eltClass && eltClass.value === this.DISCOVER_LINK_ID) {\n      this.configService.getStackDiscoverPath().then((path) => {\n        this.navCtrl.navigateForward(path);\n      });\n    }\n  }\n}\n","<ion-header style=\"z-index:300;\">\n  <app-top-navbar \n    [title]=\"pageTitle\" \n    [drawerEnabled]=\"true\"\n    \n    [drawerExpandEvent]=\"topDrawerExpand$ | async\"\n    [drawerCloseEvent]=\"topDrawerClose$ | async\"\n    [drawerSelectedItemSuccess]=\"selectedItemSuccess$ | async\"\n    (drawerSelected)=\"draftDrawerSelected($event)\"\n    (drawerNewItem)=\"draftDrawerNewItem($event)\"\n    (drawerExpand)=\"draftDrawerExpanded($event)\"\n    (drawerClose)=\"draftDrawerExpanded($event)\"\n  >\n  </app-top-navbar>\n</ion-header>\n<section *ngIf=\"stack$ | async as stack\">\n  <!-- MVP-989 note that ngIf= && isPageShowing will cause playlist to restart from the beginning -->\n  <div class=\"player-wrap\" *ngIf=\"hasStackClips\">\n    <app-video-player\n      #topPlayer\n      [playerId]=\"playerId\"\n      [stack]=\"stack\"\n      [playlist]=\"stack.clips\"\n      [currentIndex]=\"currentPlaylistIndex$ | async\"\n      [autoplay]=\"isPageShowing\"\n      [fullscreen]=\"false\"\n      [handlePlaylistDone]=\"true\"\n      [doHlsDestroy]=\"doHlsDestroy\"\n      [project]=\"project$ | async\"\n      (videoDone)=\"onPlayerEnded($event)\"\n      (videoPlaying)=\"onVideoPlaying($event)\"\n      (playlistDone)=\"onPlaylistDone($event)\"\n    ></app-video-player>\n  </div>\n</section>\n<ion-content forceOverflow=\"false\">\n  <ng-container *ngIf=\"!isStackLoading && (stack$ | async) as stack; else loading\">\n    <div class=\"panel-action\" *ngIf=\"enableExplore && !isExploreOpen && stack.stackId\">\n      <ion-button class=\"explore-action-btn ion-text-uppercase\" color=\"medium\" (click)=\"toggleExplore()\">\n        {{ 'PLAYER.EXPLORE_TAB' | translate }}\n      </ion-button>\n    </div>\n    <div class=\"container\" *ngIf=\"hasStackClips; else noClips\">\n      <div\n      class=\"content\"\n      [class.content--collapsed-sidebar]=\"isPlaylistOpen\"\n    >\n        <div class=\"content__left ion-padding-top\" scrollY=\"true\" #playlistScroller>\n          <fs-thumbnail-poster\n            *ngFor=\"let clip of stack.clips; ; let i = index\"\n            [item]=\"clip\"\n            [isPlaying]=\"i === (currentPlaylistIndex$ | async) && isVideoPlaying\"\n            [isCurrent]=\"i === (currentPlaylistIndex$ | async)\"\n            [showAvatar]=\"true\"\n            (click)=\"playIndex(i)\"\n          ></fs-thumbnail-poster>\n          <div class=\"tab-bottom-spacer\"></div>\n        </div>\n        <div class=\"content__right ion-padding-top\" scrollY=\"true\"\n          [class.content__right--expanded]=\"isPlaylistOpen\"\n          >\n          <ion-button color=\"medium\" class=\"content__right__collapser ion-padding-top\" fill=\"clear\" (click)=\"togglePlaylist()\">\n            <ion-icon [name]=\"isPlaylistOpen ? 'chevron-forward-outline' : 'chevron-back-outline'\"></ion-icon>\n          </ion-button>\n\n          <div *ngIf=\"enableClipDetails && (currentClip$ | async) as currentClipDetail\" class=\"clip-details\">\n            <div *ngIf=\"currentClipDetail?.id\" [class.clip-details__showing]=\"isShowingClipDetails\" class=\"clip-details__wrap ion-padding-bottom\">\n              <ion-item lines=\"none\">\n                <ion-thumbnail slot=\"start\" class=\"clip-details__poster\">\n                  <fs-thumbnail-poster\n                    [item]=\"currentClipDetail\"\n                    [showAvatar]=\"false\"\n                    [showDuration]=\"false\"\n                    [showActionIcon]=\"false\"\n                  ></fs-thumbnail-poster>\n                </ion-thumbnail>\n                <ion-label>\n                  <div class=\"clip-details__title\">\n                    {{ currentClipDetail?.title ?? currentClipDetail.id }}\n                  </div>\n                  <div *ngIf=\"currentClipDetail?.description\" class=\"clip-details__description\">\n                    {{ currentClipDetail.description }}\n                  </div>\n                </ion-label>\n              </ion-item>\n            </div>\n          </div>\n\n          <h1>{{ stack.title }}</h1>\n          \n          <fs-uploader-stats\n            [userId]=\"stack.userId\"\n            [date]=\"stack.dteSaved\"\n            [showAvatar]=\"true\"\n            [views]=\"stack.views\"\n            [shares]=\"stack.shares\"\n            [stacks]=\"stack?.clips?.length\"\n            [stacksTitle]=\"'Clips'\"\n          ></fs-uploader-stats>\n\n          <p>{{ stack.description }}</p>\n\n          <div class=\"content__right__contributors\">\n            <ng-container *ngIf=\"contributors?.length > 1; else singleContributor\">\n              <div class=\"content__right__contributors__stack\">\n                <fs-avatar-stack [threshold]=\"avatarStackThreshold\" [users]=\"contributors\" (modalOpened)=\"pausePlayer()\"></fs-avatar-stack>\n              </div>\n              <div class=\"content__right__contributors__label\">\n                <ion-icon name=\"people-outline\"></ion-icon>\n                <span>\n                  {{'STACK.CONTRIBUTORS_LABEL.PLURAL' | translate: { count: contributors.length } }}\n                </span>\n              </div>\n              <div style=\"clear: both\"></div>\n            </ng-container>\n          </div>\n\n          <ng-template #singleContributor>\n            {{'STACK.CONTRIBUTORS_LABEL.SINGULAR' | translate: { count: contributors?.length ?? 1 } }}\n          </ng-template>\n\n          \n\n          <div *ngIf=\"(currentUserId$ | async) === stack.userId && !stack.dtePublished\" class=\"content__right__draft-actions\">\n            <ion-button fill=\"outline\" [routerLink]=\"['/stack/edit', stack.projectId, stack.stackId]\">\n              {{ 'COMMON.EDIT' | translate }}\n            </ion-button>\n             <!-- Needs upgraded to v3 MVP-1146  -->\n            <ion-button [routerLink]=\"['/stack/edit', stack.projectId, stack.stackId]\">\n              {{ 'COMMON.PUBLISH' | translate }}\n            </ion-button>\n          </div>\n\n          <div *ngIf=\"project$ | async as project\" class=\"ion-padding-top\">\n            {{ 'COMMON.PROJECT' | translate }}:\n            <a [routerLink]=\"[routeProjectDetail, stack.projectId]\">{{ project.title }}</a>\n          </div>\n\n          <div class=\"container ion-text-center ion-padding\" *ngIf=\"showJoinButton\">\n            <ion-button size=\"large\" [routerLink]=\"routerLinkJoin\" queryParamsHandling=\"preserve\">\n              {{ 'COMMON.JOIN_AS_CREW' | translate }}\n            </ion-button>\n          </div>\n\n          <div *ngIf=\"isProjectAdmin && isProjectModerated && !stack.isApproved && stack.dtePublished && isStackPublic\" class=\"ion-padding-top\">\n            <!-- if you're a project admin & this stack needs approved -->\n            <ion-item lines=\"none\">\n              <ion-button slot=\"end\"\n                fill=\"outline\" \n                [disabled]=\"approvingStack\"\n                (click)=\"approveStack(stack)\">\n                <ion-spinner *ngIf=\"approvingStack\" slot=\"start\"></ion-spinner>\n                <ion-label>\n                  {{ 'STACK.ACTIONS.APPROVE' | translate }}\n                </ion-label>\n              </ion-button>\n            </ion-item>\n          </div>\n\n          <!-- HLS Dev tool -->\n          <div *ngIf=\"doHlsDebug\" class=\"ion-padding-top ion-margin-top\">\n            <!-- HLS Player optimization test - Attach/Re-Attach or Destroy/Build -->\n            <ion-text color=\"medium\" style=\"font-size:80%\">HLS DEV:</ion-text>\n            <ion-item style=\"--padding-start:0;--padding-end:0;\" lines=\"none\">\n              <ion-toggle slot=\"end\" [enableOnOffLabels]=\"true\" [(ngModel)]=\"doHlsDestroy\" style=\"padding:0\">\n                <div class=\"ion-text-capitalize ion-text-wrap\" style=\"font-size:70%;padding:0;margin:0;margin-right:3px;\">Re/Attach</div>\n              </ion-toggle>\n              <ion-note slot=\"end\" color=\"ion-color-medium\" style=\"white-space:normal;font-size:70%;\">Destroy<br>/build</ion-note>\n            </ion-item>\n          </div>\n\n          <!-- HLS Dev tool -->\n          <div *ngIf=\"isSiteAdmin && stack\">\n            <!-- if you're a site admin & this stack need upgraded (and not a draft), offer it -->\n            <ion-item *ngIf=\"!stack.hlsSrc && stack.dtePublished && !hasYoutubeClips\" class=\"ion-padding-top ion-margin-top\" style=\"--padding-start:0;--padding-end:0;\" lines=\"none\">\n              <ion-label slot=\"end\" style=\"font-size:70%;padding:0;margin:0;margin-right:3px;\">\n                <ion-button \n                  fill=\"outline\" \n                  [disabled]=\"optimizingStack\"\n                  (click)=\"confirmTranscode()\">\n                  <ion-spinner *ngIf=\"optimizingStack\" slot=\"start\"></ion-spinner>\n                  <ion-label>\n                    Upgrad{{ optimizingStack ? 'ing' : 'e' }} Stack <span *ngIf=\"!isAllClipsHls\">&nbsp;Clips&nbsp;</span> to HLS\n                  </ion-label>\n                </ion-button>\n              </ion-label>\n            </ion-item>\n          </div>\n\n          <div class=\"tab-bottom-spacer\"></div>\n        </div>\n        <div class=\"content__actions ion-padding-top\" scrollY=\"true\">\n          <div class=\"reserve-space-add-fab\"></div>\n          \n          <!-- isProjectAdmin && isProjectModerated && !stack.isApproved -->\n          <app-stack-popover-actions \n            [stack]=\"stack\" \n            [currentClip]=\"currentClip$ | async\"\n            [isModerated]=\"isProjectModerated\"\n            [canApprove]=\"canApprove\"\n            [canAddToStack]=\"false\"\n            [doHandleAddToStack]=\"false\"\n            [isProjectMember]=\"isProjectMember || isProjectAdmin\"\n            [isProjectAdmin]=\"isProjectAdmin\"\n            (addToStack)=\"openTabFab($event)\"\n          ></app-stack-popover-actions>\n        </div>\n        <!-- moved from tab-fab-container MVP-1336 -->\n        <ion-fab class=\"popover-fab\" #tabFabPlayer>\n          <ion-fab-button size=\"default\" (click)=\"fabClick($event)\">\n            <ion-icon name=\"add\"></ion-icon>\n          </ion-fab-button>\n          <ion-fab-list side=\"bottom\">\n            <ion-chip outline=\"true\" (click)=\"addAllClipsToStack($event)\">\n              <ion-label>{{ 'CLIP.USE_ALL_CLIPS' | translate }}</ion-label>\n            </ion-chip>\n            <ion-chip outline=\"true\" (click)=\"addClipToStack($event)\">\n              <ion-label>{{ 'CLIP.USE_THIS_CLIP' | translate }}</ion-label>\n            </ion-chip>\n          </ion-fab-list>\n        </ion-fab>\n      </div> \n      <!-- end .content -->\n    </div>\n\n    <!-- todo: enableExplore\n    <div *ngIf=\"enableExplore\" hidden slot=\"fixed\" class=\"explore-panel\" [class.explore-expanded]=\"isExploreOpen\">\n      <div *ngIf=\"stack.stackId\" class=\"explore-panel-contents\" scrollY=\"true\" #explorePanelScroller #fitContentHeight>\n        <div class=\"panel-action-close\" *ngIf=\"isExploreOpen\">\n          <ion-button class=\"explore-action-btn ion-text-uppercase\" color=\"medium\" (click)=\"toggleExplore()\">\n            <ion-icon slot=\"start\" name=\"close\"></ion-icon>\n            {{ 'COMMON.STORYLINES' | translate }}\n          </ion-button>\n        </div>\n        <div>\n          <app-explore-ui drawerId=\"playerId\" [helpText]=\"\" [scroller]=\"explorePanelScroller\"></app-explore-ui>\n        </div>\n      </div>\n    </div> -->\n\n\n    <fs-tab-fab-container>\n      <!-- Moved the tab to actions container MVP-1336 -->\n      <!-- <ion-fab *ngIf=\"stack.stackId\" class=\"tab-fab\" #tabFabPlayer>\n        <ion-fab-button (click)=\"fabClick($event)\">\n          <ion-icon name=\"add\"></ion-icon>\n        </ion-fab-button>\n        <ion-fab-list side=\"top\">\n          <ion-chip outline=\"true\" (click)=\"addAllClipsToStack($event)\">\n            <ion-label>{{ 'CLIP.USE_ALL_CLIPS' | translate }}</ion-label>\n          </ion-chip>\n          <ion-chip outline=\"true\" (click)=\"addClipToStack($event)\">\n            <ion-label>{{ 'CLIP.USE_THIS_CLIP' | translate }}</ion-label>\n          </ion-chip>\n        </ion-fab-list>\n      </ion-fab> -->\n    </fs-tab-fab-container>\n  </ng-container>\n</ion-content>\n\n<ng-template #loading>\n  <ion-card>\n    <ion-card-content>\n      <div style=\"height: 200px\">\n        <ion-skeleton-text animated></ion-skeleton-text>\n      </div>\n    </ion-card-content>\n    <ion-item>\n      <ion-label>\n        <h3>\n          <ion-skeleton-text animated style=\"width: 50%\"></ion-skeleton-text>\n        </h3>\n        <p>\n          <ion-skeleton-text animated style=\"width: 80%\"></ion-skeleton-text>\n        </p>\n        <p>\n          <ion-skeleton-text animated style=\"width: 60%\"></ion-skeleton-text>\n        </p>\n      </ion-label>\n    </ion-item>\n  </ion-card>\n</ng-template>\n\n<ng-template #noClips>\n  <div *ngIf=\"errorMessage\" class=\"error-message ion-padding\">{{ errorMessage }}</div>\n  <app-no-stack-clips-disclaimer></app-no-stack-clips-disclaimer>\n\n  <div class=\"ion-padding ion-margin-vertical\">\n    <fs-carousel-guides></fs-carousel-guides>\n  </div>\n</ng-template>","/** @format */\n\nimport { ChangeDetectorRef, Component, ElementRef, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';\nimport { NgIf, NgFor, AsyncPipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { ActivatedRoute, Router, RouterLink } from '@angular/router';\nimport {\n  IonContent,\n  Platform,\n  AlertController,\n  IonFab,\n  IonHeader,\n  IonButton,\n  IonIcon,\n  IonItem,\n  IonThumbnail,\n  IonLabel,\n  IonSpinner,\n  IonText,\n  IonToggle,\n  IonNote,\n  IonFabButton,\n  IonFabList,\n  IonChip,\n  IonCard,\n  IonCardContent,\n  IonSkeletonText,\n} from '@ionic/angular/standalone';\nimport { TranslateService, TranslatePipe } from '@ngx-translate/core';\nimport { BehaviorSubject, Observable, Subject } from 'rxjs';\nimport { distinctUntilChanged, filter, shareReplay, take, takeUntil, tap } from 'rxjs/operators';\nimport { Store } from '@ngrx/store';\nimport { State } from '@store/reducers';\nimport * as stackActions from '@store/actions/stacks.actions';\nimport * as ClipActions from '@store/actions/clips.actions';\nimport { loadMembers } from '@store/actions/members.actions';\nimport { getSelectedStackCurrentPlayClip, selectCurrentPlayIndex } from '@store/selectors/stacks.selectors';\n\nimport { UserService } from '@app/core/services/user.service';\nimport { ToasterService } from '@app/core/services/toaster.service';\nimport { VideoService } from '@app/core/services/video.service';\nimport { ThumbnailPosterComponent } from '@app/shared/components/thumbnail-poster/thumbnail-poster.component';\nimport { UploaderStatsComponent } from '@app/shared/components/ui/upload-stats/uploader-stats.component';\nimport { AvatarStackComponent } from '@app/shared/components/ui/avatar-stack/avatar-stack.component';\nimport { TabFabContainerComponent } from '@app/shared/components/tab-fab-container/tab-fab-container.component';\nimport { TopNavbarComponent } from '@app/shared/components/top-navbar/top-navbar.component';\nimport { Clip } from '@app/shared/models/clip.model';\nimport { HLS_META_UPGRADE_PROP } from '@app/shared/models/clip.model';\nimport { Stack, STACK_PRIVACY } from '@app/shared/models/stack.model';\nimport { User } from '@app/shared/models/user.model';\nimport { StackPopoverActionsComponent } from '@app/shared/components/fs-carousel/fs-slide/stack-slide/stack-popover-actions/stack-popover-actions.component';\nimport { Utils } from '@app/shared/utils';\nimport { ClipsService } from '@app/clips/shared/services/clips.service';\nimport { StackService } from '@app/stacks/shared/services/stack.service';\nimport { CarouselGuidesComponent } from '@app/stacks/carousels/carousel-guides/carousel-guides.component';\nimport { NoStackClipsDisclaimerComponent } from '@app/stacks/shared/components/no-stack-clips-disclaimer/no-stack-clips-disclaimer.component';\nimport { Project } from '@app/projects/shared/project.model';\nimport { ProjectService } from '@app/projects/shared/services/project.service';\nimport { ProjectMemberService } from '@app/project-members/shared/services/project-member.service';\nimport { getInviteTypeFromProject } from '@app/onboarding/shared/onboarding.model';\nimport { isTokenExpired, Token } from '@app/tokens/shared/tokens.model';\nimport { TokensService } from '@app/tokens/shared/services/tokens.service';\nimport { VideoPlayerService } from '@app/modules/video-player/shared/services/video-player.service';\nimport { VideoPlayerComponent } from '@app/modules/video-player/video-player.component';\nimport { PROJECT_DETAIL_ROUTE } from '@app/app.routes';\nimport { ENABLE_EXPLORE } from '@app/app.config';\nimport { environment } from 'src/environments/environment';\n\nconst DEBUG_LOGS = false;\n/**\n * if the stack is ready for transcoding, do we send it?\n * Maybe not... allow the Plyr to handle it? But what about non-optimized stacks?\n */\nconst DO_TRANSCODE_IF_CAN = true;\n\n/** works well in theory, but glitchy in ios */\nconst DO_SCROLL_TO_ITEM = false;\nconst ENABLE_CLIP_DETAILS = true;\n\nconst ITEM_EL_HEIGHT = 125 + 12; // the px height of each item (poster + margin)\nexport const STACK_PLAY_PLAYER_ID = 'stack-play';\n@Component({\n  selector: 'app-stack-play',\n  templateUrl: './stack-play.page.html',\n  styleUrls: ['./stack-play.page.scss'],\n  standalone: true,\n  imports: [\n    NgIf,\n    NgFor,\n    RouterLink,\n    AsyncPipe,\n    TranslatePipe,\n    FormsModule,\n    StackPopoverActionsComponent,\n    TopNavbarComponent,\n    ThumbnailPosterComponent,\n    UploaderStatsComponent,\n    AvatarStackComponent,\n    TabFabContainerComponent,\n    NoStackClipsDisclaimerComponent,\n    CarouselGuidesComponent,\n    VideoPlayerComponent,\n    IonHeader,\n    IonContent,\n    IonButton,\n    IonIcon,\n    IonItem,\n    IonThumbnail,\n    IonLabel,\n    IonSpinner,\n    IonText,\n    IonToggle,\n    IonNote,\n    IonFab,\n    IonFabButton,\n    IonFabList,\n    IonChip,\n    IonCard,\n    IonCardContent,\n    IonSkeletonText,\n  ],\n})\nexport class StackPlayPage implements OnInit, OnDestroy {\n  /** @todo for dev, to be removed */\n  doHlsDestroy = true;\n  doHlsDebug = false;\n\n  stack$: Observable<Stack>;\n  project$: Observable<Project>;\n  currentPlaylistIndex$: Observable<number>;\n  currentClip$: Observable<Clip>;\n  currentClip: Clip;\n  currentPlaylistIndex: number;\n\n  public contributors: Partial<User>[];\n\n  pageTitle = 'Stack';\n  playerId = STACK_PLAY_PLAYER_ID;\n  enableClipDetails = ENABLE_CLIP_DETAILS;\n  isShowingClipDetails = false;\n  enableExplore = ENABLE_EXPLORE;\n  isExploreOpen = false;\n  isPlaylistOpen = false;\n  hasStackClips = false;\n  isStackLoading = true;\n  isVideoPlaying = false;\n  errorMessage = '';\n\n  /** MVP-1003 Project.isModerated */\n  isProjectAdmin = false;\n  isProjectMember = false;\n  isProjectModerated = false;\n  approvingStack = false;\n  isStackPublic = false;\n\n  currentUserId$: Observable<string> = this.userService.userId$;\n\n  inviteType = '';\n\n  get projectId() {\n    return this.activatedRoute.snapshot.paramMap.get('projectId');\n  }\n  get stackId() {\n    return this.activatedRoute.snapshot.paramMap.get('stackId');\n  }\n\n  get canApprove(): boolean {\n    return this.isProjectModerated && this.isProjectAdmin;\n  }\n\n  get routerLinkJoin() {\n    return '/events' + (this.inviteType ? '/' + this.inviteType.toLowerCase() : '') + '/accept/' + this.projectId || '';\n  }\n  routeProjectDetail = `/${PROJECT_DETAIL_ROUTE}`;\n\n  showJoinButton = false;\n  // topDrawerExpand = false;\n  selectedItemSuccess$: BehaviorSubject<boolean> = new BehaviorSubject(false);\n  topDrawerExpand$: BehaviorSubject<{ i: number; showCreateForm?: boolean }> = new BehaviorSubject({ i: 0 });\n  topDrawerClose$: BehaviorSubject<number> = new BehaviorSubject(0);\n\n  /**\n   * Stack Playlist HLS Upgrades MVP-983\n   */\n  isSiteAdmin = false;\n  isAllClipsHls = false;\n  hasYoutubeClips = false;\n  optimizingStack = false;\n\n  @ViewChild(IonContent, { read: IonContent }) content: IonContent;\n  @ViewChild('tabFabPlayer') tabFab: IonFab;\n  @ViewChild('playlistScroller') playlistScroller: ElementRef;\n\n  /** for autoplay logic, based on ionViewEnter/Leave */\n  isPageShowing = true;\n  avatarStackThreshold = null;\n  private _wasPageShowing = true;\n  private isFabOpen = false;\n  private onDestroy$ = new Subject<void>();\n  private loadingTimeout;\n  private contributorTimeout;\n  private itemSelectedTimeout;\n  private _playlistSelected = [];\n  private _incExpandEvent = 0;\n  private _incCloseEvent = 0;\n\n  private token$: Observable<Token> = this.tokensService.token$;\n\n  constructor(\n    private activatedRoute: ActivatedRoute,\n    private platform: Platform,\n    private alertCtrl: AlertController,\n    private toaster: ToasterService,\n    private projectService: ProjectService,\n    private projectMemberService: ProjectMemberService,\n    private stackService: StackService,\n    private clipsService: ClipsService,\n    private userService: UserService,\n    private store: Store<State>,\n    private videoPlayerService: VideoPlayerService,\n    private videoService: VideoService,\n    private tokensService: TokensService,\n    private translate: TranslateService,\n    private router: Router,\n    private changeDetectorRef: ChangeDetectorRef,\n    public renderer: Renderer2\n  ) {}\n\n  ngOnInit(): void {\n    this.platform.ready().then(() => {\n      /**\n       * To not break layout show max of 3 avatars of stack.contributors on desktop\n       * https://filmstacker.atlassian.net/browse/MVP-1236\n       */\n      this.avatarStackThreshold = this.platform.is('desktop') ? 3 : null;\n    });\n    // const projectId = this.activatedRoute.snapshot.paramMap.get('projectId');\n    // const stackId = this.activatedRoute.snapshot.paramMap.get('stackId');\n    this.stack$ = this.stackService.selectAndGetPlay(this.projectId, this.stackId).pipe(\n      takeUntil(this.onDestroy$),\n      distinctUntilChanged(\n        (x, y) =>\n          x &&\n          y &&\n          x.stackId === y.stackId &&\n          x.views === y.views &&\n          x.shares === y.shares &&\n          x.clips &&\n          y.clips &&\n          x.clips.length === y.clips.length &&\n          x.playlist &&\n          y.playlist &&\n          x.playlist.length === y.playlist.length &&\n          x.hlsSrc === y.hlsSrc &&\n          x.error === y.error &&\n          // get changes for playlist\n          JSON.stringify(x.playlist) === JSON.stringify(y.playlist) &&\n          x.isApproved === y.isApproved &&\n          // include hlsMeta changes\n          x.hlsMeta &&\n          y.hlsMeta &&\n          (typeof x.hlsMeta === 'string'\n            ? x.hlsMeta === y.hlsMeta\n            : JSON.stringify(x.hlsMeta) === JSON.stringify(y.hlsMeta))\n      ),\n      tap((stack: Stack) => {\n        DEBUG_LOGS && console.log(`[Play] Stack updated:`, stack);\n        try {\n          if (stack) {\n            //typeof stack !== 'undefined') {\n            this.hasStackClips = stack.clips && !!stack.clips.length;\n            this.pageTitle = stack && stack.title ? stack.title : this.pageTitle;\n\n            this.contributors = stack.contributors;\n            if (stack.contributors?.length > 0) {\n              clearTimeout(this.contributorTimeout);\n              this.contributorTimeout = setTimeout(() => {\n                this.store.dispatch(loadMembers({ userIds: stack.contributors.map((c) => c.userId) }));\n              }, 600);\n            } else {\n              this.contributors = [{ userId: stack.userId }];\n            }\n\n            this.isStackPublic = stack.privacy === STACK_PRIVACY.PUBLIC;\n\n            if (stack.projectId) {\n              this.project$ = this.projectService.getProjectPreview(stack.projectId).pipe(\n                filter((p) => p && p.id && p.id.length > 0),\n                take(1), // make sure you only take 1\n                tap((project) => {\n                  // check if project isModerated and if so am i an admin?\n                  this.isProjectModerated = !!project.isModerated;\n                  this.isProjectAdmin = this.projectService.isProjectAdmin(project);\n                  this.isProjectMember = this.projectService.isProjectMember(project);\n                  // check if it's a wedding\n                  this.inviteType = getInviteTypeFromProject(project);\n                  !environment.production &&\n                    this.inviteType &&\n                    console.log(`check if it's a wedding`, { inviteType: this.inviteType, project });\n                }),\n                shareReplay(1)\n              );\n            }\n            // now done loading if ready\n            if (this.hasStackClips) {\n              clearTimeout(this.loadingTimeout);\n              this.loadingTimeout = setTimeout(() => {\n                this.isStackLoading = false;\n              }, 400); // just a slight delay so we don't show the carousel content...\n            } else {\n              // delay a doneLoading...\n              clearTimeout(this.loadingTimeout);\n              this.loadingTimeout = setTimeout(() => {\n                this.isStackLoading = false;\n              }, 1200);\n            }\n\n            // check if all clips are hls MVP-983\n            if (this.hasStackClips) {\n              if (stack.hlsSrc) {\n                this.optimizingStack = false;\n              } else {\n                // !stack.hlsSrc\n                this.optimizingStack = false;\n                this.hasYoutubeClips = stack.clips.filter((c) => c && (c.providerId || c.youtube_id)).length > 0;\n                this.isAllClipsHls = stack.clips.filter((c) => c && !c.hlsSrc).length < 1 && !this.hasYoutubeClips;\n                // if all the clips have hlsSrc and there's no youtube, do it automatically\n                // there's no hlsSrc right now, so if there's not a upgrade prop set, upgrade..\n                // & if this is NOT A DRAFT (pending MVP-1091)\n                if (\n                  stack.dtePublished &&\n                  DO_TRANSCODE_IF_CAN &&\n                  this.isAllClipsHls &&\n                  (!stack.hlsMeta || !stack.hlsMeta[HLS_META_UPGRADE_PROP])\n                ) {\n                  // not currently set to be upgraded, do it\n                  this.optimizingStack = true;\n                  // the stack is ready to be upgraded, all clips are already done...\n                  this.sendStackForHLSTranscode();\n                }\n              }\n            }\n          }\n          if (stack && stack.error) {\n            this.errorMessage = stack.error;\n            console.warn(`stackService.selectAndGetPlay Error: ${this.errorMessage}`);\n          } else {\n            this.errorMessage = '';\n          }\n        } catch (error) {\n          console.warn(`[Watch] Caught error in stack$.tap`, error);\n        }\n      }),\n      shareReplay(1)\n    );\n\n    this.currentPlaylistIndex$ = this.store.select(selectCurrentPlayIndex).pipe(\n      tap((index) => {\n        this.currentPlaylistIndex = index;\n        if (DO_SCROLL_TO_ITEM) {\n          this.scrollToItem(index);\n        }\n      })\n    );\n    this.currentClip$ = this.store.select(getSelectedStackCurrentPlayClip).pipe(\n      filter((res) => typeof res !== 'undefined'),\n      tap((clip) => {\n        this.currentClip = clip;\n        this.store.dispatch(ClipActions.play({ clip }));\n      })\n    );\n\n    // not crew, check if token for join\n    this.token$\n      .pipe(\n        takeUntil(this.onDestroy$),\n        filter((t) => t && t.id && !isTokenExpired(t))\n      )\n      .subscribe((token: Token) => {\n        const {\n          projectId,\n          projectRole,\n          // eslint-disable-next-line @typescript-eslint/no-unused-vars\n          eventType = '',\n          // eslint-disable-next-line @typescript-eslint/no-unused-vars\n          payload: { returnUrl = '', message = '' },\n        } = token;\n\n        this.showJoinButton = projectRole && projectId === this.projectId;\n        !environment.production &&\n          console.log(`[Token] payload roleMatching:`, { showJoinButton: this.showJoinButton, token });\n      });\n\n    this.platform.resize.subscribe(async () => {\n      if (this.platform.isLandscape() && this.platform.is('desktop')) {\n        /** why was this here? i can think of instances why i wondered why this opened... */\n        // this.isExploreOpen = true;\n      }\n    });\n\n    /**\n     * Check currentUser Cognito Groups for Admin access to platform\n     * MVP-983\n     */\n    this.userService.userIsGlobalAdmin$\n      .pipe(\n        takeUntil(this.onDestroy$)\n        // filter((isAdmin) => !!isAdmin)\n      )\n      .subscribe((isAdmin) => {\n        this.isSiteAdmin = !!isAdmin;\n      });\n\n    /**\n     * MVP-989 Stop Video Player when not active\n     * https://developer.mozilla.org/en-US/docs/Web/API/Window/blur_event\n     */\n    try {\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      window.addEventListener('blur', (evt) => {\n        this._wasPageShowing = !!this.isPageShowing;\n        this.isPageShowing = false;\n      });\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      window.addEventListener('focus', (evt) => {\n        this.isPageShowing = !!this._wasPageShowing;\n      });\n    } catch (error) {\n      console.warn(`No Window, no eventListener`, error);\n    }\n  }\n\n  ionViewWillEnter() {\n    this.isPageShowing = true;\n  }\n  ionViewWillLeave() {\n    !environment.production && console.log(`[DEV] player autoplay should now be false..`);\n\n    // MVP-989 note that this was ngIf for video-player element in template, causing it to restart from the beginning\n    this.isPageShowing = false; // MVP-989\n    this.closeTabFab();\n    this.pausePlayer();\n    this.changeDetectorRef.detectChanges();\n\n    // reset any lingering topnav-drawer playlist actions\n    this.store.dispatch(stackActions.resetAddToStackPlaylist());\n  }\n\n  ngOnDestroy() {\n    this.onDestroy$.next();\n    this.onDestroy$.complete();\n  }\n\n  pausePlayer() {\n    this.videoPlayerService.pause(this.playerId);\n  }\n\n  playIndex(index: number) {\n    if (index === this.currentPlaylistIndex) {\n      if (this.isVideoPlaying) {\n        this.videoPlayerService.pause(this.playerId);\n      } else {\n        this.videoPlayerService.play(this.playerId);\n      }\n    } else {\n      this.store.dispatch(stackActions.playCurrentIndex({ index }));\n    }\n  }\n  scrollToItem(index: number) {\n    try {\n      // if not isPlaylistOpen, avoid any waste of processing to scroll unneccessarily\n      if (!this.playlistScroller || !this.playlistScroller.nativeElement || !this.isPlaylistOpen) {\n        return;\n      }\n      const scrollSpeed = 1000;\n      // subtract 1 to keep one played item above, instead of current at top\n      const scrollTop = index === 0 ? 0 : (index - 1) * ITEM_EL_HEIGHT;\n      Utils.smoothScrollTo(this.playlistScroller.nativeElement, scrollTop, scrollSpeed);\n    } catch (error) {\n      console.error('Scroll to item failed:', error);\n    }\n  }\n  toggleExplore() {\n    this.isExploreOpen = !this.isExploreOpen;\n  }\n  togglePlaylist() {\n    this.isPlaylistOpen = !this.isPlaylistOpen;\n  }\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  onPlaylistDone(event) {\n    this.isShowingClipDetails = false;\n    this.isExploreOpen = true;\n    this.stack$.pipe(take(1)).subscribe((stack) => {\n      this.store.dispatch(stackActions.watchComplete({ projectId: stack.projectId, stackId: stack.stackId }));\n    });\n  }\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  onOrientationChange = (orient) => {\n    this.isExploreOpen = false;\n  };\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  onPlayerEnded(event) {\n    this.store.dispatch(stackActions.playNextClip());\n  }\n  onVideoPlaying(isVideoPlaying: boolean) {\n    !environment.production &&\n      console.log(`[DEV] onVideoPlaying=${isVideoPlaying} isPageShowing=${this.isPageShowing}`);\n    if (this.isPageShowing) {\n      this.isVideoPlaying = isVideoPlaying;\n      if (!this.isShowingClipDetails) {\n        this.isShowingClipDetails = true;\n      }\n    } else {\n      // MVP-989 pause if the page is not showing (view not active or window blurred)\n      this.videoPlayerService.pause(this.playerId);\n      this.isVideoPlaying = false;\n    }\n  }\n\n  /**\n   * user isProjectAdmin and project.isModerated and !stack.isApproved\n   */\n  approveStack(stack: Stack) {\n    //console.log(`set stack.isApproved`, stack);\n    this.store.dispatch(\n      stackActions.setApproved({ projectId: stack.projectId, stackId: stack.stackId, isApproved: true })\n    );\n  }\n\n  expandDraftDrawer(showCreateForm = false) {\n    this.topDrawerExpand$.next({ i: ++this._incExpandEvent, showCreateForm });\n  }\n  closeDraftDrawer() {\n    this.topDrawerClose$.next(++this._incCloseEvent);\n  }\n\n  /**\n   * Event: StatckPopoverActions.addToStack emitted when that is selected,\n   * open tab fab\n   */\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  openTabFab(event) {\n    if (this.tabFab) {\n      this.tabFab.activated = true;\n      this.isFabOpen = true;\n    }\n  }\n  closeTabFab() {\n    this.tabFab?.close();\n    this.isFabOpen = false;\n    // this.store.dispatch(stackActions.resetAddToStackPlaylist()); // this should be in the drawer?\n  }\n\n  /**\n   * FAB Click appears to come just before the element changes its value\n   * fab is open if it is not currently activated\n   */\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  fabClick(event) {\n    this.isFabOpen = !this.tabFab.activated; // !this.isFabOpen;\n    // console.log(`fabClick`, { isFabOpen: this.isFabOpen, activated: this.tabFab.activated });\n    if (!this.isFabOpen) {\n      this.store.dispatch(stackActions.resetAddToStackPlaylist());\n      // this.closeDraftDrawer();// already happens when playlist resets\n    } // else don't open until you get the action click\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  addClipToStack(event) {\n    this.stack$.pipe(take(1)).subscribe((stack) => {\n      if (stack && Array.isArray(stack.playlist) && stack.playlist.length > this.currentPlaylistIndex) {\n        // this.isFabOpen = false;\n        // expandDraftDrawer();// already happens when playlist exists\n        const clip = stack.playlist[this.currentPlaylistIndex];\n        // console.log(`addClipToStack`, { currentPlaylistIndex: this.currentPlaylistIndex, clip, stack, event });\n        this.store.dispatch(stackActions.addToStackDrawer({ playlist: [clip] }));\n      } else {\n        !environment.production &&\n          console.log(`No Playlist.`, { stack, currentPlaylistIndex: this.currentPlaylistIndex });\n      }\n    });\n  }\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  addAllClipsToStack(event) {\n    this.stack$.pipe(take(1)).subscribe((stack) => {\n      if (stack && Array.isArray(stack.playlist) && stack.playlist.length > 0) {\n        // this.isFabOpen = false;\n        // this.expandDraftDrawer();// already happens when playlist exists\n\n        // MVP-1342 add title and description if create new (Restack)\n        this.store.dispatch(\n          stackActions.addToStackDrawer({\n            playlist: stack.playlist,\n            isCreateNew: false,\n            projectId: stack.projectId,\n            title: stack.title,\n            description: stack.description,\n            poster: stack.poster,\n          })\n        );\n        // console.log(`addAllClipsToStack`, { stack, event });\n      } else {\n        !environment.production && console.log(`No Playlist.`, stack);\n      }\n    });\n  }\n\n  /**\n   * Close FAB when drawer closes\n   */\n  draftDrawerExpanded(event) {\n    if (!event) {\n      // closed, close fab?\n      this.closeTabFab();\n    }\n  }\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  draftDrawerSelected(event) {\n    // console.log(`Player draft selected`, event);\n    this.closeTabFab();\n  }\n  draftDrawerNewItem(event: Partial<Stack> = {}) {\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    const { projectId, stackId, title } = event;\n    // console.log(`Player draft new item`);\n    this.closeTabFab();\n    this.router.navigate(['/stack/edit', projectId, stackId]);\n  }\n\n  /**\n   * Stack Playlist HLS Upgrades MVP-983\n   * @todo remove eventually\n   */\n  sendStackForHLSTranscode(): void {\n    this.stack$.pipe(take(1)).subscribe(async (stack) => {\n      try {\n        await this.videoService.sendStackForHLSTranscode(stack);\n        // this.toaster.present(`Submitted for Transcoding...`);\n      } catch (error) {\n        console.warn(`[StackPopover] confirmTranscode caught:`, error);\n        this.toaster.present(this.translate.instant('ERRORS.STACK_OPTIMIZE'));\n      }\n    });\n  }\n\n  /**\n   *\n   * Stack Playlist HLS Upgrades MVP-983\n   */\n  async confirmTranscode() {\n    const alert = await this.alertCtrl.create({\n      header: this.translate.instant('STACK.CONFIRM_OPTIMIZE'),\n      subHeader: this.isAllClipsHls\n        ? this.translate.instant('STACK.SUBMIT_CONFIRM')\n        : this.translate.instant('STACK.SUBMIT_CONFIRM_CLIPS'),\n      message: this.translate.instant('STACK.SUBMIT_MESSAGE'),\n      buttons: [\n        {\n          text: this.translate.instant('COMMON.CANCEL'),\n          role: 'cancel',\n          // eslint-disable-next-line @typescript-eslint/no-unused-vars\n          handler: (_) => {\n            console.log('Confirm Canceled...');\n          },\n        },\n        {\n          text: this.translate.instant('COMMON.TRANSCODE'),\n          cssClass: 'ion-color-secondary',\n          handler: () => {\n            this.sendStackForHLSTranscode();\n            this.toaster.present(this.translate.instant('STACK.TRANSCODE_SUBMITTED'));\n          },\n        },\n      ],\n    });\n    return await alert.present();\n  }\n}\n"],"x_google_ignoreList":[]}