{"version":3,"file":"3784.fa24b20fdc00a6f7.js","mappings":"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","names":["i0","_r1","ctx_r1","onDismiss","emit","segmentNames","Trim","Split","ClipperSegmentBarComponent","_ClipperSegmentBarComponent","constructor","this","showBackButton","selectedSegment","ClipperSegments","Settings","onSelectSegment","EventEmitter","enableTrimmer","ENABLE_FEATURE_TRIM_CLIPS","enableSplitter","ENABLE_FEATURE_SPLIT_CLIPS","segmentChanged","event","detail","value","console","warn","selectors","inputs","outputs","standalone","features","decls","vars","consts","template","rf","ctx","ClipperSegmentBarComponent_ion_buttons_1_Template","$event","ClipperSegmentBarComponent_ion_segment_button_3_Template","ClipperSegmentBarComponent_ion_segment_button_4_Template","Poster","IonToolbar","NgIf","IonButtons","IonButton","IonIcon","IonSegment","IonSegmentButton","IonLabel","TranslatePipe","TrimmerComponent_ng_template_2_ion_text_1_Template","TrimmerComponent_ng_template_2_ng_template_2_Template","clipTrimLocked","locked_r1","maxVideoLengthText","TrimmerComponent_ng_template_4_div_24_span_3_Template","enableFeatureTrimUsed","_r3","onLoadedMetadata","onRangeChange","trimRange_r4","timeTinyScrub","TrimmerComponent_ng_template_4_div_23_Template","TrimmerComponent_ng_template_4_div_24_Template","resetDuration","saveTrim","TrimmerComponent_ng_template_4_ion_spinner_29_Template","playerId","_c0","clip","minLabel","maxLabel","rangeObject","rangeMin","rangeMax","usedInStacks","isSaving","PAGE","TrimmerComponent","_TrimmerComponent","alertCtrl","clipService","projectService","toaster","videoPlayerService","title","hasEditPermission","MAX_VIDEO_CAPTURE_LENGTH_TEXT","lower","upper","playlist","left","right","totalDuration","didTrimUsedAlert","startTime","endTime","subscriptions","Subscription","payload","duration","source","durationInSeconds","handleDuration","Utils","convertSecondsToDuration","ngOnChanges","getClipDetails","video","convertVideoFileToClip","numStacks","alertAlreadyUsed","checkCanEdit","id","currentUserId","Math","floor","Date","now","userId","isProjectAdmin","project","isLocked","trimValuesValid","clipUpdates","startChanged","endChanged","present","push","prop","round","log","updateClip","pipe","take","catchError","err","subscribe","next","error","_this","_asyncToGenerator","create","header","subHeader","message","buttons","alertTooLong","secs","_this2","current","toFixed","MAX_VIDEO_CAPTURE_LENGTH_SECONDS","hour","minute","seconds","durations","split","length","parseInt","scaleTimeIn","convertDurationToSeconds","isNaN","parseFloat","seekTo","customEvent","pause","newRangeObject","lowerSecs","scaleTimeOut","upperSecs","lowerArray","toString","upperArray","getTotalDurationNoHours","knob","dir","val","ngOnDestroy","unsubscribe","ms","i1","i2","i3","i4","i5","TrimmerComponent_ng_container_1_Template","TrimmerComponent_ng_template_2_Template","TrimmerComponent_ng_template_4_Template","editable_r6","cannotEdit_r5","IonContent","IonText","VideoPlayerComponent","IonList","IonItem","IonRange","IonSpinner","styles","ctx_r0","poster","SelectPosterComponent_ng_template_2_ng_template_2_div_3_Template","SelectPosterComponent_ng_template_2_ion_text_1_Template","SelectPosterComponent_ng_template_2_ng_template_2_Template","isYoutube","youtubeClip_r2","onPlayerReady","selectImage","SelectPosterComponent_ng_template_4_ion_spinner_13_Template","minRangeValue","maxRangeValue","sliderValue","SelectPosterComponent","_SelectPosterComponent","clipCoreService","clipsService","posterTime","canEdit","loadVideoData","youtube_id","youtube_id_nomusic","getPosterTimeFromPoster","origPosterTime","time","posterTimeInt","savePosterTime","newPoster","updatePosterToPosterTime","SelectPosterComponent_ng_container_1_Template","SelectPosterComponent_ng_template_2_Template","SelectPosterComponent_ng_template_4_Template","editable_r5","cannotEdit_r4","curTitleLen","maxDescLen","onChangeDate","_r4","retryLocationAccess","confirmTranscode","onChangeTitle","ClipSettingsComponent_ng_template_4_form_11_ion_item_4_Template","onChangeDesc","ClipSettingsComponent_ng_template_4_form_11_ion_item_7_Template","ClipSettingsComponent_ng_template_4_form_11_ion_item_8_Template","ClipSettingsComponent_ng_template_4_form_11_ng_template_18_Template","ClipSettingsComponent_ng_template_4_form_11_ng_container_19_Template","ClipSettingsComponent_ng_template_4_form_11_ion_item_21_Template","ClipSettingsComponent_ng_template_4_form_11_ion_label_28_Template","ClipSettingsComponent_ng_template_4_form_11_ion_label_29_Template","ClipSettingsComponent_ng_template_4_form_11_ion_item_30_Template","ClipSettingsComponent_ng_template_4_form_11_ion_item_32_Template","save","ClipSettingsComponent_ng_template_4_form_11_ion_spinner_41_Template","ClipSettingsComponent_ng_template_4_form_11_ion_button_44_Template","formGroup","controls","titleInput","valid","dirty","submitAttempt","descInput","curDescLen","tmp_17_0","appConfig","enableClipLanguage","filmingDate","tmp_20_0","allowPrivateUploads","enableTags","mapLoaded","mapLoadingCanceled","canHlsTranscode","ClipSettingsComponent_ng_template_4_ng_template_9_Template","ClipSettingsComponent_ng_template_4_form_11_Template","_c1","noClip_r5","VALIDATE_SAFE_PATTERN","VALIDATE_SAFE_PATTERN_MULTILINE","ClipSettingsComponent","_ClipSettingsComponent","formBuilder","modalCtrl","platform","configService","userService","videoService","MAX_DESC_LENGTH_CLIPS","isPublic","clipLanguage","tagAutocompleteItems","isPwa","isNative","loadMap","currentLng","currentLat","setMap","getCurrentPosition","google","maps","mapOptions","center","LatLng","zoom","mapTypeId","enableHighAccuracy","timeout","Infinity","gestureHandling","mapElement","nativeElement","map","Map","addMarker","marker","Marker","animation","Animation","DROP","position","getCenter","draggable","addListener","getPosition","lat","lng","ngOnInit","userIsGlobalAdmin$","filter","isAdmin","hlsSrc","determinePlatform","then","setupMap","_b","_a","tags","createForm","group","clipTitle","Validators","compose","required","pattern","maxLength","clipDesc","publicViewing","language","getDateTimeString","patchValue","private","getDateTimeStringWithOffset","lastModifiedDate","getDescription","geoLat","geoLng","isValid","getFormValuesChanged","Object","keys","key","join","hasOwnProperty","control","pristine","description","ready","readySource","info","platforms","addGoogleScriptTagThenLoadMap","getLocationAccess","window","fsrGmapsCallback","tag","document","createElement","src","firstScriptTag","getElementsByTagName","parentNode","insertBefore","navigator","geolocation","coords","latitude","longitude","code","PERMISSION_DENIED","POSITION_UNAVAILABLE","TIMEOUT","UNKNOWN_ERROR","maximumAge","onTagSelected","item","onTagRemoved","removeFromArray","onTagAdded","addToArrayUnique","toLowerCase","openPrivacyPolicy","component","PrivacyPage","componentProps","isModal","openTerms","_this3","TermsPage","_this4","confirmSendClipForHLSTranscode","i6","i7","i8","viewQuery","ClipSettingsComponent_ng_container_1_Template","ClipSettingsComponent_ng_template_2_Template","ClipSettingsComponent_ng_template_4_Template","editable_r7","cannotEdit_r6","FormsModule","ReactiveFormsModule","AsyncPipe","DatePipe","TermsPolicyModalsComponent","IonTextarea","IonSelectOption","IonNote","IonModal","IonToggle","IonListHeader","IonCard","dismiss","currentUserId$","project$","ClipperComponent_div_2_div_1_Template","ClipperComponent_div_2_div_2_Template","ClipperComponent_div_2_div_3_Template","cancelText","ClipperComponent","_ClipperComponent","_clip","projectId","getProject","route","router","defaultReturnUrl","onDestroy$","Subject","isSegment","userId$","queryParams","takeUntil","params","returnUrl","getCurrentNavigation","extras","state","name","values","includes","navTrim","navPoster","navSettings","complete","ClipperComponent_ion_header_0_Template","ClipperComponent_div_2_Template","ClipperComponent_ng_template_3_Template","ClipperComponent_ion_footer_5_Template","noClip_r4","IonHeader","NgSwitch","NgClass","NgSwitchCase","IonFooter"],"ignoreList":[],"sourceRoot":"webpack:///","sources":["./src/app/modules/clipper/clipper-segment-bar/clipper-segment-bar.component.html","./src/app/modules/clipper/clipper-segment-bar/clipper-segment-bar.component.ts","./src/app/modules/clipper/trimmer/trimmer.component.html","./src/app/modules/clipper/trimmer/trimmer.component.ts","./src/app/modules/clipper/select-poster/select-poster.component.html","./src/app/modules/clipper/select-poster/select-poster.component.ts","./src/app/modules/clipper/clip-settings/clip-settings.component.html","./src/app/modules/clipper/clip-settings/clip-settings.component.ts","./src/app/modules/clipper/clipper.component.html","./src/app/modules/clipper/clipper.component.ts"],"sourcesContent":["<ion-toolbar color=\"dark\">\n  <ion-buttons *ngIf=\"showBackButton\" slot=\"start\">\n    <ion-button (click)=\"onDismiss.emit()\">\n      <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n    </ion-button>\n  </ion-buttons>\n  \n  <ion-segment (ionChange)=\"segmentChanged($event)\" [value]=\"selectedSegment\" mode=\"md\">\n    <ion-segment-button [value]=\"segmentNames.Trim\" *ngIf=\"enableTrimmer\">\n      <ion-label>{{ 'CLIP.SETTINGS.TRIM' | translate }}<span class=\"ion-hide-sm-down\"> {{ 'COMMON.CLIP' | translate }}</span></ion-label>\n    </ion-segment-button>\n    <ion-segment-button *ngIf=\"enableSplitter\" [value]=\"segmentNames.Split\">\n      <ion-label>{{ 'CLIP.SETTINGS.SPLIT' | translate }}<span class=\"ion-hide-sm-down\"> {{ 'COMMON.CLIP' | translate }}</span></ion-label>\n    </ion-segment-button>\n    <ion-segment-button [value]=\"segmentNames.Poster\">\n      <ion-label><span class=\"ion-hide-sm-down\">{{ 'COMMON.SELECT' | translate }} </span>{{ 'COMMON.POSTER' | translate }}</ion-label>\n    </ion-segment-button>\n    <ion-segment-button [value]=\"segmentNames.Settings\">\n      <ion-label><span class=\"ion-hide-sm-down\">{{ 'COMMON.CLIP' | translate }} </span>{{ 'COMMON.SETTINGS' | translate }}</ion-label>\n    </ion-segment-button>\n  </ion-segment>\n  \n</ion-toolbar>","/** @format */\n\nimport { Component, Input, Output, EventEmitter } from '@angular/core';\nimport { ClipperSegments } from '../clipper.component';\nimport { ENABLE_FEATURE_SPLIT_CLIPS, ENABLE_FEATURE_TRIM_CLIPS } from '@app/app.config';\nimport { IonToolbar, IonButtons, IonButton, IonIcon, IonSegment, IonSegmentButton, IonLabel } from '@ionic/angular/standalone';\nimport { NgIf } from '@angular/common';\nimport { TranslatePipe } from '@ngx-translate/core';\n\n@Component({\n    selector: 'app-clipper-segment-bar',\n    templateUrl: './clipper-segment-bar.component.html',\n    styleUrls: ['./clipper-segment-bar.component.scss'],\n    standalone: true,\n    imports: [\n        IonToolbar,\n        NgIf,\n        IonButtons,\n        IonButton,\n        IonIcon,\n        IonSegment,\n        IonSegmentButton,\n        IonLabel,\n        TranslatePipe,\n    ],\n})\nexport class ClipperSegmentBarComponent {\n  @Input() showBackButton: boolean = false;\n  @Input() selectedSegment: ClipperSegments = ClipperSegments.Settings;\n  // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n  @Output() onSelectSegment = new EventEmitter<string>();\n  // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n  @Output() onDismiss = new EventEmitter<void>();\n\n  public enableTrimmer = ENABLE_FEATURE_TRIM_CLIPS;\n  public enableSplitter = ENABLE_FEATURE_SPLIT_CLIPS;\n\n  public segmentNames = ClipperSegments;\n\n  segmentChanged(event) {\n    if (event && event.detail && event.detail.value) {\n      this.onSelectSegment.emit(event.detail.value);\n    } else {\n      console.warn(`[ClipperSegmentBar] segmentChanged NO detail.value?:`, event);\n    }\n  }\n}\n","\n<ion-content>\n  <ng-container *ngIf=\"hasEditPermission; then editable else cannotEdit\"></ng-container>\n  \n  <ng-template #cannotEdit>\n    <div class=\"ion-padding ion-text-center ion-margin-top\">\n      <ion-text *ngIf=\"!clipTrimLocked; else locked\" color=\"light\">\n        Sorry, you are not able to Trim this Clip.\n        <br><br>\n        Only the person that uploaded the Clip can Trim.\n      </ion-text>\n      <ng-template #locked>\n        <ion-text color=\"secondary\">\n          Sorry, the owner of this Clip Locked the Trim, so we can't change it.\n        </ion-text>\n      </ng-template>\n      \n    </div>\n  </ng-template>\n\n  <ng-template #editable>\n\n    <div class=\"player-wrap\">\n      <!--[class.video-fullscreen]=\"isLandscape\"-->\n      <app-video-player #trimmerPlayer\n        [playerId]=\"playerId\" \n        [playlist]=\"[clip]\"\n        [autoplay]=\"false\"\n        [handlePlaylistDone]=\"false\"\n        [useTrimmerControls]=\"true\"\n        (loadedMetadata)=\"onLoadedMetadata($event)\"\n      ></app-video-player>\n    </div>\n    <div class=\"trim-tools ion-padding-vertical\">\n     \n      <!-- range selection -->\n      <ion-list class=\"video-range\" lines=\"none\">\n        <ion-item>\n          <div class=\"range-labels\">\n            <ion-label class=\"label-range-left white\">{{ minLabel }}</ion-label>\n            <ion-label class=\"label-range-right white\">{{ maxLabel }}</ion-label>\n          </div>\n          <ion-range #trimRange dualKnobs=\"true\" debounce=\"50\" [value]=\"rangeObject\" [min]=\"rangeMin\" [max]=\"rangeMax\" step=\"1\" (ionChange)=\"onRangeChange($event)\">\n            <ion-buttons slot=\"start\" class=\"fine-trim-btns btns-range-left\">\n              <!-- todo during trimmer refactor: [disabled]=\"trimRange.value.lower <= 0\" -->\n              <ion-button slot=\"start\" fill=\"clear\" class=\"tiny-less\" (click)=\"timeTinyScrub(trimRange, 'start', 'less')\">\n                <ion-icon slot=\"icon-only\" name=\"play-back-circle\"></ion-icon>\n              </ion-button>\n              <!-- todo during trimmer refactor: [disabled]=\"trimRange.value.lower >= trimRange.upper\" -->\n              <ion-button slot=\"start\" fill=\"clear\" class=\"tiny-more\" (click)=\"timeTinyScrub(trimRange, 'start', 'more')\">\n                <ion-icon slot=\"icon-only\" name=\"play-forward-circle\"></ion-icon>\n              </ion-button>\n\n            </ion-buttons>\n\n            <!-- <ion-label slot=\"start\" class=\"label-range-left white\" [style.left]=\"left+'%'\" [ngClass]=\"{'align-left-label': left > 0}\">{{minLabel}}</ion-label>\n            <ion-label slot=\"end\" class=\"label-range-right white\" [style.right]=\"right+'%'\" [ngClass]=\"{'align-right-label': right > 0}\">{{maxLabel}}</ion-label> -->\n            \n            <ion-buttons slot=\"end\" class=\"fine-trim-btns btns-range-right\">\n              <!-- todo during trimmer refactor: [disabled]=\"trimRange.value.upper <= trimRange.value.lower\" -->\n              <ion-button fill=\"clear\" class=\"tiny-less\" (click)=\"timeTinyScrub(trimRange, 'end', 'less')\">\n                <ion-icon slot=\"icon-only\" name=\"play-back-circle\"></ion-icon>\n              </ion-button>\n              <!-- todo during trimmer refactor: [disabled]=\"trimRange.value.upper >= rangeMax\" -->\n              <ion-button fill=\"clear\" class=\"tiny-more\" (click)=\"timeTinyScrub(trimRange, 'end', 'more')\">\n                <ion-icon slot=\"icon-only\" name=\"play-forward-circle\"></ion-icon>\n              </ion-button>\n            </ion-buttons>\n          </ion-range> \n        </ion-item>\n      </ion-list>\n    \n      <div *ngIf=\"!usedInStacks || enableFeatureTrimUsed\" class=\"instructions ion-text-center\">\n        Trim clip to less than {{maxVideoLengthText}}\n        <br>\n        <i>You might need to push play once to start trimming.</i>\n      </div>\n\n      <div *ngIf=\"usedInStacks && !enableFeatureTrimUsed\" class=\"instructions ion-text-center ion-padding-top\">\n        <b>\n          This Clip has already been used in a published Filmstack, so we'll need to create a new Clip.\n        </b>\n        <span *ngIf=\"!enableFeatureTrimUsed\">\n          (<i>Feature in Dev - unable to Save Trim</i>)\n        </span>\n      </div>\n\n    \n      <!-- trim and refresh button -->\n      <div class=\"trim-buttons ion-text-center\">\n        <ion-button fill=\"outline\" shape=\"round\" color=\"light\" (click)=\"resetDuration()\">\n          <ion-icon slot=\"icon-only\" name=\"arrow-undo-outline\"></ion-icon>\n        </ion-button>\n  \n        <ion-button fill=\"outline\" shape=\"round\" color=\"primary\" (click)=\"saveTrim()\" [disabled]=\"isSaving || (usedInStacks && !enableFeatureTrimUsed)\">\n          <ion-spinner *ngIf=\"isSaving\" slot=\"start\" name=\"crescent\"></ion-spinner>\n          TRIM\n        </ion-button>\n\n      </div>\n    \n    </div>\n  </ng-template>\n\n  <div class=\"tab-spacer\"></div>\n\n</ion-content>","/** @format */\n\nimport { Component, OnDestroy, OnChanges, Input } from '@angular/core';\nimport { NgIf } from '@angular/common';\nimport {\n  AlertController,\n  RangeCustomEvent,\n  IonContent,\n  IonText,\n  IonList,\n  IonItem,\n  IonLabel,\n  IonRange,\n  IonButtons,\n  IonButton,\n  IonIcon,\n  IonSpinner,\n} from '@ionic/angular/standalone';\nimport { Subscription } from 'rxjs';\nimport { catchError, take } from 'rxjs/operators';\nimport { Clip, ClipVideoFile, convertVideoFileToClip } from '@app/shared/models/clip.model';\nimport { Utils } from '@app/shared/utils';\nimport { ClipsCoreService } from '@app/core/services/clips.service';\nimport { ToasterService } from '@app/core/services/toaster.service';\nimport { UpdateParam } from '@app/core/api/api-types';\nimport { MAX_VIDEO_CAPTURE_LENGTH_SECONDS, MAX_VIDEO_CAPTURE_LENGTH_TEXT } from '@app/app.config';\nimport { Project } from '@app/projects/shared/project.model';\nimport { ProjectService } from '@app/projects/shared/services/project.service';\nimport { VideoPlayerService } from '@app/modules/video-player/shared/services/video-player.service';\nimport { VideoPlayerComponent } from '@app/modules/video-player/video-player.component';\n// import { RangeValue } from '@ionic/core';\n\nconst DEBUG_LOGS = false;\nconst DEV_NO_SAVE = false; // stop the save process for dev'ing\n\n/**\n * Feature: create a new clip if it's been used in a stack - in dev\n * for now, allow Trimming a Clip even if it was used, for flexibility\n */\nconst ENABLE_FEATURE_TRIM_USED = true;\n\nconst PAGE = '[Trimmer]'; // eslint-disable-line @typescript-eslint/no-unused-vars\n/**\n * @todo C.3. Video preview shows the frame at the time of the handle you are dragging (start handle or end handle)\n * @todo D.1. When trimming handles dragged to desired location, video shows starting from left (starting) handle time\n */\n\n@Component({\n  selector: 'app-trimmer',\n  templateUrl: './trimmer.component.html',\n  styleUrls: ['./trimmer.component.scss'],\n  standalone: true,\n  imports: [\n    IonContent,\n    NgIf,\n    IonText,\n    VideoPlayerComponent,\n    IonList,\n    IonItem,\n    IonLabel,\n    IonRange,\n    IonButtons,\n    IonButton,\n    IonIcon,\n    IonSpinner,\n  ],\n})\nexport class TrimmerComponent implements OnChanges, OnDestroy {\n  @Input() currentUserId: string;\n  @Input() video: ClipVideoFile;\n  @Input() clip: Clip;\n  @Input() project: Project;\n\n  title: string = 'Trimmer';\n  playerId = 'trimmer-player';\n\n  isSaving: boolean = false;\n  hasEditPermission: boolean = false;\n  clipTrimLocked: boolean = false;\n  usedInStacks: boolean = false;\n  maxVideoLengthText = MAX_VIDEO_CAPTURE_LENGTH_TEXT;\n\n  enableFeatureTrimUsed = ENABLE_FEATURE_TRIM_USED;\n\n  rangeObject = { lower: 0, upper: 100 };\n\n  playlist: Clip[] = [];\n  rangeMin: number = 0;\n  rangeMax: number = 100;\n  minLabel: string = '';\n  maxLabel: string = '';\n  left: number = 0;\n  right: number = 0;\n  totalDuration: number = 0;\n\n  private didTrimUsedAlert = false;\n  private startTime: number = 0;\n  private endTime: number = 0;\n  private subscriptions: Subscription = new Subscription();\n\n  constructor(\n    private alertCtrl: AlertController,\n    private clipService: ClipsCoreService,\n    private projectService: ProjectService,\n    private toaster: ToasterService,\n    private videoPlayerService: VideoPlayerService\n  ) {}\n\n  ngOnChanges() {\n    this.getClipDetails();\n  }\n\n  getClipDetails() {\n    if (!this.clip && !this.video) {\n      return; // no clip yet\n    } else if (!this.clip && this.video) {\n      this.clip = convertVideoFileToClip(this.video);\n    }\n\n    if (this.clip.numStacks && this.clip.numStacks > 0) {\n      this.usedInStacks = true;\n\n      if (!this.enableFeatureTrimUsed && !this.didTrimUsedAlert) {\n        this.didTrimUsedAlert = true;\n        this.alertAlreadyUsed();\n      }\n    }\n\n    this.checkCanEdit();\n\n    DEBUG_LOGS && console.log(`${PAGE} getClipDetails`, { hasEditPermission: this.hasEditPermission, clip: this.clip });\n\n    if (this.hasEditPermission) {\n      if (!this.clip.id) {\n        // clip has not been saved to DB yet, create temp id\n        this.clip.id = `${this.currentUserId}__${Math.floor(Date.now() / 1000)}`;\n      }\n\n      if (this.clip.duration) {\n        this.handleDuration();\n      }\n    }\n  }\n\n  checkCanEdit() {\n    // if there's a clip and userId, check for canEdit permission\n    if (this.currentUserId && this.clip && this.clip.userId && this.clip.userId === this.currentUserId) {\n      this.hasEditPermission = true;\n    } else if (this.projectService.isProjectAdmin(this.project, this.currentUserId)) {\n      this.clipTrimLocked = typeof this.clip.isLocked === 'boolean' ? this.clip.isLocked : false;\n      this.hasEditPermission = !this.clipTrimLocked;\n    } else {\n      this.hasEditPermission = false;\n    }\n  }\n\n  /**\n   * Form Submit\n   */\n  saveTrim() {\n    this.isSaving = true;\n\n    if (!this.trimValuesValid()) {\n      this.isSaving = false;\n      return;\n    }\n\n    const clipUpdates: UpdateParam[] = [];\n\n    const startChanged = this.startTime && this.startTime !== this.clip.startTime,\n      endChanged = this.endTime && this.endTime !== this.clip.endTime;\n\n    if (!startChanged && !endChanged) {\n      this.isSaving = false;\n      this.toaster.present(`No changes to Save.`);\n      return;\n    }\n\n    if (startChanged) {\n      // this.clip.source.startTime = startTime; // only if we need to re-transcode\n      this.clip.startTime = this.startTime;\n      clipUpdates.push({\n        prop: 'startTime',\n        value: this.startTime,\n      });\n    }\n    if (endChanged) {\n      // this.clip.source.endTime = endTime; // only if we need to re-transcode\n      this.clip.endTime = this.endTime;\n      clipUpdates.push({\n        prop: 'endTime',\n        value: this.endTime,\n      });\n    }\n\n    if (startChanged || endChanged) {\n      clipUpdates.push({\n        prop: 'duration',\n        value: Utils.convertSecondsToDuration(Math.round(this.endTime - this.startTime)),\n      });\n    }\n\n    if (DEV_NO_SAVE) {\n      console.log(`${PAGE} updateClip(dev):`, { clip: this.clip, clipUpdates });\n      setTimeout(() => {\n        this.isSaving = false;\n        this.toaster.present(`Feature in DEV - not saved. startTime=${this.startTime} endTime=${this.endTime}`);\n      }, 1000);\n      return;\n    }\n\n    console.log(`${PAGE} updateClip(dev):`, { clip: this.clip, clipUpdates });\n\n    this.clipService\n      .updateClip(this.clip, clipUpdates)\n      .pipe(\n        take(1),\n        catchError((err) => {\n          this.isSaving = false;\n          console.warn('error in source. Details:', err);\n          throw err;\n        })\n      )\n      .subscribe({\n        next: () => {\n          this.isSaving = false;\n          this.toaster.present(`Clip Updated.`);\n        },\n        error: (err) => {\n          this.isSaving = false;\n          console.warn(err);\n          this.toaster.present(`Oops, Clip not updated - please refresh and try again.`);\n        },\n      });\n  }\n\n  async alertAlreadyUsed() {\n    const alert = await this.alertCtrl.create({\n      header: `Unable to Trim`,\n      subHeader: `This Clip has already been used in a published Filmstack, so we'll need to create a new Clip.`,\n      message: `This feature is in Development, and is coming soon!`,\n      buttons: ['Ok'],\n    });\n    return await alert.present();\n  }\n\n  async alertTooLong(secs) {\n    let current = secs.toFixed(1); //Math.round(secs * 10) / 10; // one decimal place\n    if (current === MAX_VIDEO_CAPTURE_LENGTH_SECONDS.toFixed(1)) {\n      current = (secs + 0.1).toFixed(1);\n    }\n    const alert = await this.alertCtrl.create({\n      header: `Filmstacker works best with shorter clips`,\n      subHeader: `Max clip duration is ${MAX_VIDEO_CAPTURE_LENGTH_TEXT}, you're at ${current} seconds. <br><br>Please trim a bit more...`,\n      buttons: ['Ok'],\n    });\n    return await alert.present();\n  }\n\n  handleDuration(duration = '00:00:00') {\n    if (!this.clip) {\n      console.warn(`${PAGE} handleDuration - No Clip?`, this.clip);\n      return;\n    }\n    DEBUG_LOGS && console.log(`${PAGE} handleDuration (${duration}) clip.duration: ${this.clip.duration}`);\n    if (duration && duration !== '00:00:00' && duration !== this.clip.duration) {\n      this.clip.duration = duration;\n    }\n    if (!this.clip.duration) {\n      this.clip.duration = '00:00:00';\n    }\n\n    let hour = 0;\n    let minute = 0;\n    let seconds = 0;\n    const durations = this.clip.duration.split(':');\n    switch (durations.length) {\n      case 3: {\n        hour = parseInt(durations[0], 10);\n        minute = parseInt(durations[1], 10);\n        seconds = parseInt(durations[2], 10);\n        break;\n      }\n      case 2: {\n        minute = parseInt(durations[0], 10);\n        seconds = parseInt(durations[1], 10);\n        break;\n      }\n      case 1: {\n        console.log(`${PAGE} only seconds in the duration..`);\n        seconds = parseInt(durations[0], 10);\n        break;\n      }\n      default:\n        console.warn(`${PAGE} no durations?`);\n    }\n\n    // set maximum range value\n\n    if (this.clip.source && typeof this.clip.source.durationInSeconds === 'number') {\n      this.rangeMax = this.scaleTimeIn(this.clip.source.durationInSeconds);\n      this.totalDuration = this.clip.source.durationInSeconds;\n    } else if (this.clip.source && this.clip.source.duration) {\n      this.totalDuration = Utils.convertDurationToSeconds(this.clip.source.duration);\n      this.rangeMax = this.scaleTimeIn(this.totalDuration);\n    } else if (durations.length >= 1) {\n      this.totalDuration = hour * 3600 + minute * 60 + seconds;\n      this.rangeMax = this.scaleTimeIn(this.totalDuration);\n    } else {\n      console.warn(`${PAGE} unable to determine duration | rangeMax`, { durations, clip: this.clip });\n      this.rangeMax = 0;\n      this.totalDuration = 0;\n    }\n\n    if (this.clip.startTime !== null && !isNaN(this.clip.startTime) && typeof this.clip.startTime === 'string') {\n      this.clip.startTime = parseFloat(this.clip.startTime);\n    }\n    if (this.clip.endTime !== null && !isNaN(this.clip.endTime) && typeof this.clip.endTime === 'string') {\n      this.clip.endTime = parseFloat(this.clip.endTime);\n    }\n\n    this.startTime = typeof this.clip.startTime === 'number' && this.clip.startTime >= 0 ? this.clip.startTime : 0;\n    this.endTime =\n      typeof this.clip.endTime === 'number' && this.clip.endTime > 0 ? this.clip.endTime : this.totalDuration;\n\n    // set range object\n    this.rangeObject = { lower: this.scaleTimeIn(this.startTime), upper: this.scaleTimeIn(this.endTime) };\n\n    // set range's label\n    this.minLabel = Utils.convertSecondsToDuration(Math.round(this.startTime));\n    this.maxLabel = hour > 0 ? this.clip.duration : `${durations[1]}:${durations[2]}`;\n\n    DEBUG_LOGS &&\n      console.log(`${PAGE} DEV handleDuration rangeMax parse with ms`, {\n        durations,\n        totalDuration: this.totalDuration,\n        clipDuration: this.clip.duration,\n        rangeMax: this.rangeMax,\n        clip: this.clip,\n        startTime: this.startTime,\n        endTime: this.endTime,\n        rangeObject: this.rangeObject,\n      });\n\n    this.videoPlayerService.seekTo(this.playerId, this.startTime, this.endTime);\n  }\n\n  /**\n   * set video's duration as per range value changes\n   * Debounced this event as elem attr\n   */\n  onRangeChange(event: Event) {\n    const customEvent = event as RangeCustomEvent;\n    this.videoPlayerService.pause(this.playerId);\n\n    const newRangeObject = customEvent.detail.value;\n\n    if (typeof newRangeObject == 'number') {\n      /**\n       * @todo during refactor of trimmer - validate this logic: will this ever be a number?\n       *\n       * Trim action needs dual knobs on range => {lower: number, upper: number}\n       */\n      // DEBUG_LOGS && console.log(`${PAGE} onRangeChange: `, { customEvent });\n    } else {\n      // scale back to seconds\n      const lowerSecs = this.scaleTimeOut(newRangeObject.lower);\n      const upperSecs = this.scaleTimeOut(newRangeObject.upper);\n\n      // console.log(`${PAGE} getTrimDuration  DEV `, {upperSecs, upper: this.rangeObject.upper, rangeO: this.rangeObject});\n\n      // set the range's label\n      const lowerArray = [lowerSecs.toString()];\n      const upperArray = [upperSecs.toString()];\n      this.minLabel = Utils.getTotalDurationNoHours(lowerArray);\n      this.maxLabel = Utils.getTotalDurationNoHours(upperArray);\n\n      // change the poistion of label (%)\n      // this.left = (lowerSecs * 100) / this.totalDuration;\n      // this.right = 100 - (upperSecs * 100) / this.totalDuration;\n\n      // set starttime and endtime of video\n      this.startTime = lowerSecs;\n      this.endTime = upperSecs;\n      // DEBUG_LOGS && console.log(`${PAGE} onRangeChange Start time: ${this.startTime} End time: ${this.endTime}`);\n      this.videoPlayerService.seekTo(this.playerId, this.startTime, this.endTime);\n    }\n  }\n\n  // reset duration of video\n  resetDuration() {\n    this.rangeObject = { lower: 0, upper: this.rangeMax };\n    this.startTime = 0;\n    this.endTime = this.rangeMax;\n  }\n\n  timeTinyScrub(event, knob: 'start' | 'end', dir: 'less' | 'more') {\n    if (!event || !event.value) return;\n    // DEBUG_LOGS && console.log(`${PAGE} timeTinyScrub val: ${event.value}`, { knob, dir, event });\n    let lower: number, upper: number;\n    if (knob === 'start' && typeof event.value.lower === 'number') {\n      const val: number = event.value.lower;\n      switch (dir) {\n        case 'more': {\n          lower = val + 30;\n          break;\n        }\n        case 'less':\n        default:\n          lower = val - 30 >= 0 ? val - 30 : 0;\n      }\n      this.rangeObject = {\n        lower,\n        upper: event.value.upper >= lower ? event.value.upper : lower + 30,\n      };\n    } else if (knob === 'end' && typeof event.value.upper === 'number') {\n      const val: number = event.value.upper;\n      switch (dir) {\n        case 'more': {\n          upper = val + 30 < this.rangeMax ? val + 30 : this.rangeMax;\n          break;\n        }\n        case 'less':\n        default:\n          upper = val - 30 > event.value.lower ? val - 30 : event.value.lower + 30;\n      }\n      this.rangeObject = {\n        lower: event.value.lower,\n        upper,\n      };\n    } else {\n      console.warn(`${PAGE} timeTinyScrub UNHANDLED val: ${event.value}`, { knob, dir, event });\n    }\n\n    // DEBUG_LOGS && console.log(`${PAGE} timeTinyScrub result:`, { result: this.rangeObject, knob, dir, event });\n  }\n\n  // skipLeft(event) {\n  //   if (!event || !event.value || typeof event.value.lower !== 'number') return;\n  //   // DEBUG_LOGS && console.log(`${PAGE} startTimeTinyLess lower: ${event.value.lower} to: ${event.value.lower - 30}`, event);\n  //   if (event.value.lower - 30 >= 0) {\n  //     this.rangeObject = {\n  //       lower: event.value.lower - 30,\n  //       upper: event.value.upper,\n  //     };\n  //   }\n  // }\n  // skipRight(event) {\n  //   if (!event || !event.value || typeof event.value.upper !== 'number') return;\n  //   // DEBUG_LOGS && console.log(`${PAGE} skipRight upper: ${event.value.upper} to: ${event.value.upper + 30} rangeMax: ${this.rangeMax}`, event);\n  //   if (event.value.upper + 30 <= this.rangeMax) {\n  //     this.rangeObject = {\n  //       lower: event.value.lower,\n  //       upper: event.value.upper + 30,\n  //     };\n  //   }\n  // }\n\n  onLoadedMetadata = (event) => {\n    if (event && event.playerId && event.playerId === this.playerId) {\n      DEBUG_LOGS && console.log(`${PAGE} onLoadedMetadata... ${event.playerId}`, event);\n\n      if (event.payload && typeof event.payload.duration === 'number' && event.payload.duration > 0) {\n        if (!this.clip.source) {\n          this.clip.source = {};\n        }\n        this.clip.source.durationInSeconds = event.payload.duration;\n        this.handleDuration(Utils.convertSecondsToDuration(event.payload.duration));\n      }\n    }\n  };\n\n  ngOnDestroy() {\n    this.videoPlayerService.pause(this.playerId);\n    this.subscriptions.unsubscribe();\n  }\n\n  /**\n   * Validate the form values\n   */\n  private trimValuesValid(): boolean {\n    if (typeof this.endTime !== 'number') {\n      console.warn(`${PAGE} endTime NaN?`, this.endTime);\n      this.endTime = 0;\n    }\n    if (typeof this.startTime !== 'number') {\n      console.warn(`${PAGE} startTime NaN?`, this.startTime);\n      this.startTime = 0;\n    }\n    if (this.endTime <= 0) {\n      console.warn(`${PAGE} endTime ZERO?`, this.endTime);\n      this.toaster.present(`Oops! endTime really should not be Zero... please reload and try again!`);\n      // return false;\n    }\n    if (this.endTime - this.startTime > MAX_VIDEO_CAPTURE_LENGTH_SECONDS) {\n      // TODO: endTime is not correct...\n      DEBUG_LOGS &&\n        console.log(`${PAGE} DEV ENDTIME OK? getTrimValues`, {\n          endTime: this.endTime,\n          startTime: this.startTime,\n          diff: this.endTime - this.startTime,\n          maxDuration: MAX_VIDEO_CAPTURE_LENGTH_SECONDS,\n          tooLong: this.endTime - this.startTime > MAX_VIDEO_CAPTURE_LENGTH_SECONDS,\n        });\n\n      this.alertTooLong(this.endTime - this.startTime);\n\n      return false;\n    }\n    return true;\n  }\n\n  private scaleTimeIn(seconds: number): number {\n    // convert to framerate\n    // second=1000ms, so 24fps= 1000/24, milliseconds per frame = 41.667ms\n    // for now, just ms:\n    return seconds * 1000;\n  }\n  private scaleTimeOut(ms: number): number {\n    // back to seconds\n    return ms / 1000;\n  }\n}\n","<ion-content>\n  <ng-container *ngIf=\"canEdit && !isYoutube; then editable else cannotEdit\"></ng-container>\n  \n  <ng-template #cannotEdit>\n\n    <div class=\"ion-padding ion-text-center ion-margin-top\">\n      <ion-text *ngIf=\"!isYoutube; else youtubeClip\" color=\"light\">\n        {{ 'CLIP.SETTINGS.POSTER_PERMISSION' | translate }}\n        <!-- Sorry, you are not able to Change the Poster Image for this Clip. -->\n        <br><br>\n        {{ 'CLIP.SETTINGS.POSTER_PERMISSION_2' | translate }}\n        <!-- Only the person that uploaded the Clip can change the Poster Image. -->\n      </ion-text>\n      <ng-template #youtubeClip>\n        <ion-text color=\"light\">\n          {{ 'CLIP.SETTINGS.POSTER_YOUTUBE' | translate }}\n        </ion-text>\n  \n        <div *ngIf=\"clip?.poster\" class=\"poster\">\n          <img [src]=\"clip.poster\">\n        </div>\n      </ng-template>\n    </div>\n\n  </ng-template>\n  \n\n \n\n  <ng-template #editable>\n\n    <div class=\"player-wrap diet-limit-width\">\n      <!--[class.video-fullscreen]=\"isLandscape\"-->\n      <app-video-player #selectPosterPlayer\n        [playerId]=\"playerId\" \n        [playlist]=\"[clip]\"\n        [autoplay]=\"false\"\n        [handlePlaylistDone]=\"false\"\n        [showOverlayPlay]=\"false\"\n        [showControls]=\"false\"\n        (playerReady)=\"onPlayerReady($event)\"\n        (loadedMetadata)=\"onLoadedMetadata($event)\"\n      ></app-video-player>\n    </div>\n    <div class=\"ion-text-center ion-padding diet-limit-width\">\n    \n      <!-- title -->\n      <div class=\"main-title\">\n        <h1>\n          {{ 'CLIP.SETTINGS.POSTER_HELP' | translate }}\n          <!-- Select poster image <small>Thumbnail of your clip</small> -->\n        </h1>\n      </div>\n    \n      <!-- range selection -->\n      <ion-list class=\"video-range\" lines=\"none\">\n        <ion-item class=\"image-range\">\n          <!-- <ion-label [style.left]=\"left+'%'\">{{rangeLabel}}</ion-label> -->\n          <ion-range \n            [min]=\"minRangeValue\" \n            [max]=\"maxRangeValue\" \n            [value]=\"sliderValue\" \n            debounce=\"50\" \n            pin=\"true\"\n            snaps=\"true\"\n            (ionChange)=\"onRangeChange($event)\"></ion-range>\n        </ion-item>\n      </ion-list>\n    \n    \n      <!-- save button -->\n      <div class=\"ion-text-center action-buttons ion-padding-top ion-text-uppercase\">\n        <ion-button fill=\"outline\" shape=\"round\" color=\"primary\" (click)=\"selectImage()\" [disabled]=\"isSaving\">\n          <ion-spinner *ngIf=\"isSaving\" slot=\"start\" name=\"crescent\"></ion-spinner>\n          {{ 'CLIP.SETTINGS.POSTER_ACTION' | translate }}\n        </ion-button>\n    \n      </div>\n    \n    </div>\n</ng-template>\n\n<div class=\"tab-spacer\"></div>\n\n  \n</ion-content>","/** @format */\n\nimport { Component, Input, OnChanges } from '@angular/core';\nimport { NgIf } from '@angular/common';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { IonContent, IonText, IonList, IonItem, IonRange, IonButton, IonSpinner } from '@ionic/angular/standalone';\nimport { take } from 'rxjs/operators';\nimport { UpdateParam } from '@app/core/api/api-types';\nimport { ClipsCoreService } from '@app/core/services/clips.service';\nimport { ToasterService } from '@app/core/services/toaster.service';\nimport { Clip, ClipVideoFile, convertVideoFileToClip } from '@app/shared/models/clip.model';\nimport { Utils } from '@app/shared/utils';\nimport { ClipsService } from '@app/clips/shared/services/clips.service';\nimport { Project } from '@app/projects/shared/project.model';\nimport { ProjectService } from '@app/projects/shared/services/project.service';\nimport { VideoPlayerService } from '@app/modules/video-player/shared/services/video-player.service';\nimport { VideoPlayerComponent } from '@app/modules/video-player/video-player.component';\n\nconst DEBUG_LOGS = false;\nconst DEV_NO_SAVE = false; // stop the save process for dev'ing\n\nconst PAGE = '[SelectPoster]';\n\n@Component({\n  selector: 'app-select-poster',\n  templateUrl: './select-poster.component.html',\n  styleUrls: ['./select-poster.component.scss'],\n  standalone: true,\n  imports: [\n    NgIf,\n    VideoPlayerComponent,\n    IonContent,\n    IonText,\n    IonList,\n    IonItem,\n    IonRange,\n    IonButton,\n    IonSpinner,\n    TranslatePipe,\n  ],\n})\nexport class SelectPosterComponent implements OnChanges {\n  @Input() clip: Clip;\n  @Input() video: ClipVideoFile;\n  @Input() posterTime: number = 0;\n  @Input() currentUserId: string;\n  @Input() project: Project;\n\n  isSaving: boolean = false;\n  canEdit: boolean = false;\n  isYoutube: boolean = false;\n\n  sliderValue: number = 0;\n  playerId = 'select-poster-player';\n\n  minRangeValue: number = 0;\n  maxRangeValue: number = 0;\n  // rangeLabel: any = \"\";\n  left: number = 0;\n\n  private origPosterTime: number;\n\n  constructor(\n    private toaster: ToasterService,\n    private clipCoreService: ClipsCoreService,\n    private clipsService: ClipsService,\n    private projectService: ProjectService,\n    private videoPlayerService: VideoPlayerService\n  ) {}\n\n  ngOnChanges() {\n    this.getClipDetails();\n  }\n\n  getClipDetails() {\n    if (this.clip) {\n      DEBUG_LOGS && console.log(`${PAGE} getClipDetails`, { clip: this.clip });\n      if (this.clip.youtube_id || this.clip.youtube_id_nomusic) {\n        this.isYoutube = true;\n        this.canEdit = false;\n        return; // can't change the poster of a youtube video\n      }\n      this.posterTime = this.clipsService.getPosterTimeFromPoster(this.clip);\n      this.origPosterTime = this.posterTime;\n    } else if (this.video) {\n      // this is a video file, convert it to a clip so we can play it\n      this.clip = convertVideoFileToClip(this.video);\n    }\n    DEBUG_LOGS && console.log(`${PAGE} getClipDetails`, { posterTime: this.posterTime, clip: this.clip });\n\n    if (typeof this.posterTime !== 'number' || this.posterTime < 0) {\n      this.posterTime = 0;\n    }\n\n    this.checkCanEdit();\n  }\n\n  checkCanEdit() {\n    // if there's a clip and userId, check for canEdit permission\n    if (this.currentUserId && this.clip && this.clip.userId && this.clip.userId === this.currentUserId) {\n      this.canEdit = true;\n    } else if (this.projectService.isProjectAdmin(this.project, this.currentUserId)) {\n      this.canEdit = true;\n    } else {\n      this.canEdit = false;\n    }\n  }\n\n  onPlayerReady(value: boolean) {\n    DEBUG_LOGS && console.log(`${PAGE} onPlayerReady`, value);\n    this.getClipDetails();\n  }\n\n  onLoadedMetadata = (event) => {\n    DEBUG_LOGS && console.log(`${PAGE} onLoadedMetadata... ${event.playerId}`, event);\n    if (event && event.playerId && event.playerId === this.playerId) {\n      if (event.payload.duration) {\n        if (!this.clip.source) {\n          this.clip.source = {};\n        }\n        this.clip.source.durationInSeconds = event.payload.duration;\n        this.clip.duration = Utils.convertSecondsToDuration(event.payload.duration);\n        this.loadVideoData();\n      }\n    }\n  };\n\n  loadVideoData() {\n    DEBUG_LOGS && console.log(`${PAGE} loadVideoData...`, this.clip);\n\n    const startTime = this.clip.startTime || this.clip.source.startTime || 0;\n    const endTime = this.clip.endTime || this.clip.source.endTime || this.clip.source.durationInSeconds;\n\n    // restrict the range to be just the trim (required due to elastic transcoder job)\n    this.minRangeValue = startTime;\n    this.maxRangeValue = endTime;\n\n    // set poster time\n    const time = this.clipsService.getPosterTimeFromPoster(this.clip);\n    const posterTimeInt = this.clip.source && this.clip.source.posterTimeInt; // been here before\n    if (typeof posterTimeInt === 'number' && posterTimeInt >= startTime) {\n      this.posterTime = posterTimeInt;\n    } else if (time >= startTime) {\n      this.posterTime = time || startTime || 0;\n    } else {\n      this.posterTime = startTime || 0;\n    }\n    DEBUG_LOGS &&\n      console.log(`${PAGE} loadVideoData... posterTime:`, {\n        posterTime: this.posterTime,\n        posterTimeInt,\n        time,\n        startTime,\n      });\n    this.videoPlayerService.seekTo(this.playerId, this.posterTime);\n\n    // set range's label\n    // let rangeArray = [this.posterTime.toString()];\n    // this.rangeLabel = Utils.getTotalDuration(rangeArray);\n\n    this.left = (this.posterTime * 100) / this.clip.source.durationInSeconds;\n    this.sliderValue = this.posterTime;\n  }\n\n  /**\n   * ionRange ionChange event\n   */\n  onRangeChange(event) {\n    if (!event || !event.detail || typeof event.detail.value !== 'number') {\n      console.warn(`${PAGE} onRangeChange event.detail.value NaN!`, event);\n      return;\n    }\n    DEBUG_LOGS && console.log(`${PAGE} onRangeChange ev:`, event.detail);\n    this.videoPlayerService.pause(this.playerId);\n\n    this.posterTime = event.detail.value;\n    this.clip.source.posterTimeInt = this.posterTime;\n\n    // set poster time\n    this.videoPlayerService.seekTo(this.playerId, this.posterTime);\n\n    // set range's label\n    // let rangeArray = [this.posterTime.toString()];\n    // this.rangeLabel = Utils.getTotalDuration(rangeArray);\n\n    // change position of label\n    this.left = (this.posterTime * 100) / this.clip.source.durationInSeconds;\n  }\n\n  /**\n   * on Submit - select and save\n   */\n  selectImage() {\n    if (typeof this.posterTime !== 'number' || this.posterTime < 0) {\n      this.toaster.present(`Oops! Poster Time is not valid. Please reload and try again.`);\n      return;\n    }\n\n    if (this.origPosterTime === this.posterTime) {\n      this.toaster.present(`Poster time did not change, no save necessary.`);\n      DEBUG_LOGS &&\n        console.log(`${PAGE} savePosterTime No Change needed`, {\n          origPosterTime: this.origPosterTime,\n          posterTime: this.posterTime,\n        });\n      return;\n    }\n\n    this.savePosterTime();\n  }\n\n  /**\n   * Do the save..\n   */\n  savePosterTime() {\n    this.isSaving = true;\n\n    const clipUpdates: UpdateParam[] = [];\n\n    const newPoster = this.clipsService.updatePosterToPosterTime(this.clip, this.posterTime);\n\n    if (!newPoster) {\n      this.isSaving = false;\n      this.toaster.present(`Hmm, Poster not updated - please try again.`);\n      return;\n    }\n\n    clipUpdates.push({\n      prop: 'poster',\n      value: newPoster,\n    });\n\n    if (DEV_NO_SAVE) {\n      DEBUG_LOGS && console.log(`${PAGE} savePosterTime:`, { clipUpdates });\n      this.toaster.present(`Feature in DEV: posterTime NOT saved: '${this.posterTime}'`);\n      setTimeout(() => {\n        this.isSaving = false;\n      }, 1000);\n      return;\n    }\n\n    this.clipCoreService\n      .updateClip(this.clip, clipUpdates)\n      .pipe(take(1))\n      .subscribe({\n        next: () => {\n          this.isSaving = false;\n          this.toaster.present(`Poster Updated.`);\n        },\n        error: (err) => {\n          this.isSaving = false;\n          console.warn(err);\n          this.toaster.present(`Oops, Poster not updated - please try again.`);\n        },\n      });\n  }\n}\n","<ion-content>\n  <ng-container *ngIf=\"canEdit; then editable else cannotEdit\"></ng-container>\n  \n  <ng-template #cannotEdit>  \n    <div class=\"ion-padding ion-text-center ion-margin-top\">\n      <ion-text color=\"light\">\n        Sorry, you are not able to Edit this Clip.\n        <br><br>\n        Only the person that uploaded the Clip can change the Settings.\n      </ion-text>\n    </div>\n  </ng-template>\n\n  <ng-template #editable>\n\n    <div class=\"player-wrap diet-limit-width\">\n      <!--[class.video-fullscreen]=\"isLandscape\"-->\n      <app-video-player #selectPosterPlayer\n        [playerId]=\"playerId\" \n        [playlist]=\"[clip]\" \n        [autoplay]=\"false\"\n        [showOverlayPlay]=\"true\"\n        [handlePlaylistDone]=\"false\"\n      ></app-video-player>\n    </div>\n\n    <div class=\"limit-width ion-padding ion-text-center diet-limit-width\">\n\n      <div class=\"main-title\">\n        <h1>Settings &amp; Metadata</h1>\n        <h5>The more details you add, the more likely your clip will be discovered.</h5>\n      </div>\n\n      <ng-template #noClip>\n        <p  class=\"ion-text-center\">\n          Oops! We didn't load the Clip correctly, please try again.\n        </p>\n      </ng-template>\n\n      <form *ngIf=\"clip; else noClip\" [formGroup]=\"formGroup\" (ngSubmit)=\"confirmTranscode()\">\n        <ion-list class=\"setting-list\" lines=\"none\">\n          \n          <ion-item>\n            <ion-input formControlName=\"titleInput\" type=\"text\" \n              label=\"Clip Title\"\n              labelPlacement=\"floating\"\n              [class.invalid]=\"!formGroup.controls.titleInput.valid && (formGroup.controls.titleInput.dirty || submitAttempt)\"\n              (ionChange)=\"onChangeTitle($event)\"\n            ></ion-input>\n          </ion-item>\n          <ion-item *ngIf=\"!formGroup.controls.titleInput.valid && (formGroup.controls.titleInput.dirty || submitAttempt)\">\n            <!-- formGroup.controls.titleInput.errors?.pattern -->\n            <p class=\"error\">\n              Please enter a valid Title <br>\n              <i>Max length 140 characters (currently: {{curTitleLen}}), no</i> / &gt; &lt; \\\n            </p>\n          </ion-item>\n          <ion-item>\n            <ion-textarea name=\"descInput\" [autoGrow]=\"true\" [debounce]=\"50\" [rows]=\"3\"\n              [maxlength]=\"maxDescLen\" type=\"text\"\n              labelPlacement=\"floating\"\n              label=\"Clip Description ({{curDescLen}}/{{maxDescLen}})\"\n              formControlName=\"descInput\"\n              [class.invalid]=\"!formGroup.controls.descInput.valid && (formGroup.controls.descInput.dirty || submitAttempt)\" \n              (ionChange)=\"onChangeDesc($event)\">\n            </ion-textarea>\n          </ion-item>\n          <ion-item *ngIf=\"!formGroup.controls.descInput.valid && (formGroup.controls.descInput.dirty || submitAttempt)\">\n            <p class=\"error\">\n              Please enter a valid Description<br>\n              <i>Max length {{maxDescLen}} characters, no</i> &gt; or &lt;\n            </p>\n          </ion-item>\n\n          \n          <!-- language dropdown -->\n          <ion-item *ngIf=\"(appConfig | async)?.enableClipLanguage\" class=\"language-select\">\n            <ion-select name=\"language\" formControlName=\"language\" interface=\"popover\" placeholder=\"Select Language\">\n              <div slot=\"label\">{{ 'COMMON.LANGUAGE' | translate }}</div>\n              <ion-select-option value=\"english\">{{ 'COMMON.ENGLISH' | translate }}</ion-select-option>\n              <ion-select-option value=\"spanish\">{{ 'COMMON.SPANISH' | translate }}</ion-select-option>\n            </ion-select>\n          </ion-item>\n          <ion-item slot=\"header\" id=\"open-modal\" class=\"datetime-modal-action\">\n            <ion-label class=\"bold\">{{ 'COMMON.DATE' | translate }}</ion-label>\n            <ion-note slot=\"end\">{{ formGroup.value.filmingDate | date:'short'}}</ion-note>\n          </ion-item>\n\n          <ion-modal trigger=\"open-modal\">\n            <ng-template>\n              <ion-content>\n                <ion-datetime\n                  #filmingdate\n                  presentation=\"date-time\"\n                  size=\"cover\"\n                  formControlName=\"filmingDate\"\n                  showDefaultButtons=\"true\"\n                  (ionChange)=\"onChangeDate($event)\"\n                >\n                </ion-datetime>\n              </ion-content>\n            </ng-template>\n          </ion-modal>\n          <ng-container *ngIf=\"(appConfig | async)?.allowPrivateUploads\">\n            <ion-item class=\"ion-margin-top toggle-item-pad-left\">\n              <!-- public viewing -->\n              <ion-toggle \n                formControlName=\"publicViewing\" \n                justify=\"space-between\"\n                [enableOnOffLabels]=\"true\">\n                <div class=\"ion-text-uppercase bold\">\n                  {{ 'CLIP.SETTINGS.PUBLIC_VIEWING' | translate }}\n                </div>\n                <div class=\"instructions ion-text-wrap\">\n                  {{ 'CLIP.SETTINGS.PUBLIC_VIEWING_HINT' | translate }}\n                </div>\n              </ion-toggle>\n            </ion-item>\n          </ng-container>\n\n          <ion-item *ngIf=\"enableTags\" class=\"ion-margin-top\">\n            <!-- <app-tagger-input \n              [id]=\"'clip_uploader'\"\n              [heading]=\"'Add Tags'\"\n              [items]=\"clip.tags\"\n              [autocompleteItems]=\"tagAutocompleteItems\"\n              (tagSelected)=\"onTagSelected($event)\"\n              (tagRemoved)=\"onTagRemoved($event)\"\n              (tagAdded)=\"onTagAdded($event)\"\n            ></app-tagger-input> -->\n          </ion-item>\n\n        </ion-list>\n\n\n        <ion-list class=\"setting-list map-list\" lines=\"none\">\n          <!-- location -->\n          <ion-list-header class=\"no-margin-bottom\">\n            <ion-label>\n              {{ 'CLIP.SETTINGS.LOCATION' | translate }}\n            </ion-label>\n          </ion-list-header>\n          <ion-item>\n            <ion-label *ngIf=\"mapLoaded && !mapLoadingCanceled\" class=\"goof-title instructions ion-text-wrap\">\n              {{ 'CLIP.SETTINGS.LOCATION_HELP' | translate }}\n            </ion-label>\n            <ion-label *ngIf=\"!mapLoaded || mapLoadingCanceled\" class=\"goof-title instructions ion-text-wrap\">\n              {{ 'CLIP.SETTINGS.LOCATION_PROMPT' | translate }}\n            </ion-label>\n          </ion-item>\n          <ion-item *ngIf=\"!mapLoaded && mapLoadingCanceled\" class=\"ion-text-center\">\n            <ion-button shape=\"round\" fill=\"outline\" size=\"default\" (click)=\"retryLocationAccess()\" class=\"margin-center\">Get My Location</ion-button>\n          </ion-item>\n          <ion-card class=\"ion-no-margin\">\n            <ion-item *ngIf=\"!mapLoaded && !mapLoadingCanceled\" class=\"ion-text-center\">\n                <ion-spinner name=\"crescent\" class=\"margin-center\"></ion-spinner>\n            </ion-item>\n            <ion-item class=\"location-item ion-text-center\">\n              <div #map id=\"map\" [class.map-loaded]=\"mapLoaded\"></div>\n            </ion-item>\n          </ion-card>\n          \n        </ion-list>\n\n        <div class=\"ion-text-center ion-padding ion-margin-top\">\n\n          <app-terms-policy-modals\n            [agreeTo] = \"'POLICIES.AGREE_TO_TERMS_PREFIX' | translate\"\n          ></app-terms-policy-modals>\n          \n        </div>\n\n        <div class=\"action-buttons ion-text-center ion-padding ion-margin-top ion-text-uppercase\">\n          <ion-button fill=\"solid\" shape=\"round\" color=\"primary\" (click)=\"save()\" [disabled]=\"isSaving\">\n            <ion-spinner *ngIf=\"isSaving\" slot=\"start\" name=\"crescent\"></ion-spinner>\n            {{ 'COMMON.SAVE' | translate }}\n          </ion-button>\n\n          <ion-button *ngIf=\"canHlsTranscode\" \n            type=\"submit\"\n            style=\"position:absolute;right:20px\" color=\"medium\" size=\"small\" fill=\"outline\" \n            title=\"Transcode to HLS\">\n            <ion-icon slot=\"icon-only\" name=\"beer-outline\"></ion-icon>\n          </ion-button>\n        </div>\n        \n      </form>\n\n\n    \n    </div>\n  </ng-template>\n\n  <div class=\"tab-spacer\"></div>\n</ion-content>\n","/** @format */\n\nimport { Component, Input, OnChanges, ViewChild, ElementRef, OnInit } from '@angular/core';\nimport { UntypedFormBuilder, UntypedFormGroup, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { NgIf, AsyncPipe, DatePipe } from '@angular/common';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport {\n  Platform,\n  ModalController,\n  InputCustomEvent,\n  TextareaCustomEvent,\n  IonContent,\n  IonText,\n  IonList,\n  IonItem,\n  IonTextarea,\n  IonSelectOption,\n  IonLabel,\n  IonNote,\n  IonModal,\n  IonToggle,\n  IonListHeader,\n  IonButton,\n  IonCard,\n  IonSpinner,\n  IonIcon,\n} from '@ionic/angular/standalone';\n// import { Diagnostic } from '@awesome-cordova-plugins/diagnostic'; // TODO: native\n// import { Geolocation } from '@awesome-cordova-plugins/geolocation'; // TODO: native\nimport { catchError, filter, take } from 'rxjs/operators';\nimport { UpdateParam } from '@app/core/api/api-types';\nimport { AppConfig } from '@app/core/config/config.model';\nimport { ConfigService } from '@app/core/config/config.service';\nimport { ClipsCoreService } from '@app/core/services/clips.service';\nimport { ToasterService } from '@app/core/services/toaster.service';\nimport { VideoService } from '@app/core/services/video.service';\nimport { UserService } from '@app/core/services/user.service';\nimport { Clip, MAX_DESC_LENGTH_CLIPS } from '@app/shared/models/clip.model';\nimport { TermsPolicyModalsComponent } from '@app/shared/components/terms-policy-modals/terms-policy-modals.component';\nimport { Utils } from '@app/shared/utils';\n// modals\nimport { PrivacyPage } from '@app/pages/privacy/privacy.page';\nimport { TermsPage } from '@app/pages/terms/terms.page';\nimport { Project } from '@app/projects/shared/project.model';\nimport { ProjectService } from '@app/projects/shared/services/project.service';\nimport { VideoPlayerComponent } from '@app/modules/video-player/video-player.component';\n\nconst DEBUG_LOGS = false;\nconst DEV_NO_SAVE = false; // stop the save process for dev'ing\n\nconst PAGE = '[ClipSettings]';\n\n/**\n * Clip Title and Description should be html safe\n */\nconst VALIDATE_SAFE_PATTERN = /^[a-zA-Z0-9,._\\-\\?!@#$%^&*[\\]|\\(\\)–+=’\\\"\\'{}:;\\s]*$/;\nconst VALIDATE_SAFE_PATTERN_MULTILINE = /^[a-zA-Z0-9,._\\-\\?!@#$%^&*[\\]|\\(\\)–+=’\\\"\\'{}:;\\r\\n\\\\\\/\\s]*$/;\n\ndeclare let google; // geolocation\n\n@Component({\n  selector: 'app-clip-settings',\n  templateUrl: './clip-settings.component.html',\n  styleUrls: ['./clip-settings.component.scss'],\n  standalone: true,\n  imports: [\n    NgIf,\n    FormsModule,\n    ReactiveFormsModule,\n    AsyncPipe,\n    DatePipe,\n    TranslatePipe,\n    TermsPolicyModalsComponent,\n    VideoPlayerComponent,\n    IonContent,\n    IonText,\n    IonList,\n    IonItem,\n    IonTextarea,\n    IonSelectOption,\n    IonLabel,\n    IonNote,\n    IonModal,\n    IonToggle,\n    IonListHeader,\n    IonButton,\n    IonCard,\n    IonSpinner,\n    IonIcon,\n  ],\n})\nexport class ClipSettingsComponent implements OnInit, OnChanges {\n  /** @todo reenable tags with refactor */\n  enableTags = false;\n\n  @Input() currentUserId: string;\n  @Input() clip: Clip;\n  @Input() project: Project;\n\n  @ViewChild('map') mapElement: ElementRef;\n\n  public canEdit: boolean = false;\n\n  playerId = 'edit-clip-settings';\n\n  /** type: new google.maps.Map */\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  map: any;\n  mapLoaded: boolean = false;\n  mapLoadingCanceled: boolean = false;\n  currentLat: string;\n  currentLng: string;\n\n  formGroup: UntypedFormGroup;\n  submitAttempt: boolean = false;\n\n  maxDescLen: number = MAX_DESC_LENGTH_CLIPS;\n  curDescLen: number = 0;\n  curTitleLen: number = 0;\n\n  appConfig: Promise<AppConfig>;\n  filmingDate;\n\n  clipTitle: string;\n  clipDesc: string;\n  isPublic: boolean = false;\n  clipLanguage: string = 'english';\n\n  tagAutocompleteItems: string[] = [];\n\n  canHlsTranscode = false;\n  public isSaving: boolean = false;\n\n  private isPwa = false;\n  private isNative = false;\n\n  constructor(\n    private formBuilder: UntypedFormBuilder,\n    private modalCtrl: ModalController,\n    private platform: Platform,\n    private configService: ConfigService,\n    private toaster: ToasterService,\n    private clipService: ClipsCoreService,\n    private projectService: ProjectService,\n    private userService: UserService,\n    private videoService: VideoService\n  ) {\n    this.appConfig = this.configService.appConfig;\n  }\n\n  ngOnInit() {\n    /**\n     * Check currentUser Cognito Groups for Admin access to platform\n     */\n    this.userService.userIsGlobalAdmin$\n      .pipe(\n        filter((isAdmin) => typeof isAdmin === 'boolean'),\n        take(1),\n        filter((isAdmin) => isAdmin)\n      )\n      .subscribe((isAdmin) => {\n        console.log(`sub userGroups isAdmin:`, { isAdmin, clip: this.clip });\n        /**\n         * DEV HLS TRANSCODE MVP-742\n         */\n        if (this.clip && !this.clip.hlsSrc) {\n          this.canHlsTranscode = true;\n        }\n      });\n    // only do this once onInit, not onChanges...\n    this.determinePlatform().then(() => {\n      DEBUG_LOGS && console.log(`${PAGE} determinePlatform -> setupMap`);\n      this.setupMap();\n    });\n\n    // currently we are only handling this if project already exists,\n    // so may not work if app loaded on this route (project was loaded async)\n    // which aligns with TaggerInput.autocompleteItems which is only considered during OnInit\n    if (this.project?.tags?.length > 0) {\n      // get tags from project, to add to global ALL_TAGS (provided by tagger-input)\n      this.tagAutocompleteItems = this.project.tags;\n    }\n  }\n\n  ngOnChanges() {\n    this.checkCanEdit();\n    if (this.canEdit) {\n      this.getClipDetails();\n      this.createForm();\n    }\n  }\n\n  checkCanEdit() {\n    // if there's a clip and userId, check for canEdit permission\n    if (this.currentUserId && this.clip && this.clip.userId && this.clip.userId === this.currentUserId) {\n      this.canEdit = true;\n    } else if (this.projectService.isProjectAdmin(this.project, this.currentUserId)) {\n      this.canEdit = true;\n    } else {\n      this.canEdit = false;\n    }\n  }\n\n  createForm() {\n    this.formGroup = this.formBuilder.group({\n      titleInput: [\n        this.clipTitle,\n        Validators.compose([Validators.required, Validators.pattern(VALIDATE_SAFE_PATTERN), Validators.maxLength(140)]),\n      ],\n      descInput: [\n        this.clipDesc,\n        Validators.compose([\n          Validators.maxLength(this.maxDescLen),\n          Validators.pattern(VALIDATE_SAFE_PATTERN_MULTILINE),\n        ]),\n      ],\n      publicViewing: [this.isPublic],\n      language: [this.clipLanguage],\n      filmingDate: [this.filmingDate],\n    });\n  }\n  onChangeDate(event: Event) {\n    const customEvent = event as TextareaCustomEvent;\n    if (customEvent?.detail?.value) {\n      // have to convert the ion-datetime result to our DB style\n      const filmingDate = Utils.getDateTimeString(customEvent.detail.value);\n      this.formGroup.patchValue({ filmingDate });\n      DEBUG_LOGS && console.log('onChangeDate', { filmingDate, value: customEvent?.detail?.value });\n    }\n  }\n\n  /**\n   * Get Clip Data for Form\n   * (why was this async?)\n   */\n  getClipDetails() {\n    if (!this.clip) {\n      console.warn(`${PAGE} getClipDetails NO CLIP?`, this.clip);\n      return;\n    }\n    // this.projectId = this.clip.projectId;\n    this.clipTitle = this.clip.title;\n    this.curTitleLen = this.clipTitle.length;\n\n    /**\n     * @todo implement other settings for Clip Privacy\n     *\n     * isPublic = clip.private == null || undefined || typeof 'boolean' and !private\n     */\n    this.isPublic = !(typeof this.clip.private === 'boolean' && this.clip.private);\n\n    // let zoneOffset = (new Date()).getTimezoneOffset() * 60000;\n    if (this.clip.filmingDate) {\n      this.filmingDate = Utils.getDateTimeStringWithOffset(this.clip.filmingDate);\n    } else if (this.clip.source && this.clip.source.lastModifiedDate) {\n      this.filmingDate = Utils.getDateTimeStringWithOffset(this.clip.source.lastModifiedDate);\n      // DEBUG_LOGS && console.log(`${PAGE} filmingDate:`, this.filmingDate);\n    } else {\n      DEBUG_LOGS && console.log(`${PAGE} NO filmingDate?`, this.clip);\n    }\n\n    this.clipDesc = this.clipService.getDescription(this.clip);\n\n    this.curDescLen = this.clipDesc.length;\n\n    if (this.clip.language) {\n      this.clipLanguage = this.clip.language;\n    }\n\n    this.currentLat = this.clip.geoLat || null;\n    this.currentLng = this.clip.geoLng || null;\n  }\n\n  save() {\n    this.isSaving = true;\n\n    const { clip, isValid } = this.getFormValuesChanged();\n    if (!isValid) {\n      // if not valid - throw alert and stop save\n      console.warn(`${PAGE} save formValues !isValid`, clip);\n      this.toaster.present(`Clip Settings Not Valid - please correct the fields and try again.`);\n      this.isSaving = false;\n      return;\n    }\n    // @todo handle this.isPublic = !(typeof this.clip.private === 'boolean' && this.clip.private);\n    const clipUpdates: UpdateParam[] = [\n      ...Object.keys(clip).map((key) => ({\n        prop: key,\n        value: clip[key],\n      })),\n    ];\n\n    if (DEV_NO_SAVE) {\n      console.log(`${PAGE} save todo: `, { clipUpdates, clipChanges: clip, origClip: this.clip });\n\n      setTimeout(() => {\n        this.isSaving = false;\n        this.toaster.present(`Updated Clip ${Object.keys(clip).join(', ')}.`);\n      }, 1000);\n      return;\n    }\n\n    DEBUG_LOGS && console.log(`${PAGE} saving: `, { clipUpdates, clipChanges: clip, origClip: this.clip });\n\n    // save changes\n    this.clipService\n      .updateClip(this.clip, clipUpdates)\n      .pipe(\n        take(1),\n        catchError((err) => {\n          console.warn(`updateClip caught`, err);\n          throw err;\n        })\n      )\n      .subscribe({\n        next: () => {\n          this.isSaving = false;\n          this.toaster.present(`Save Success: Updated Clip ${Object.keys(clip).join(', ')}.`);\n        },\n        error: (err) => {\n          console.warn(err);\n          this.isSaving = false;\n          this.toaster.present(`Oops, Clip not updated - please try again.`);\n        },\n      });\n  }\n\n  /**\n   * Get the Changed form values\n   */\n  public getFormValuesChanged(): { clip: Partial<Clip>; isValid: boolean } {\n    const controls = this.formGroup.controls;\n    const clip: Partial<Clip> = {};\n    let isValid = true;\n    for (const key in controls) {\n      if (controls.hasOwnProperty(key)) {\n        const control = controls[key];\n        if (!control.pristine) {\n          if (!control.valid) {\n            isValid = false;\n            DEBUG_LOGS && console.log(`${PAGE} invalid form control: '${key}' value:`, control.value);\n          }\n          switch (key) {\n            case 'titleInput': {\n              clip.title = control.value;\n              break;\n            }\n            case 'descInput': {\n              clip.description = control.value;\n              break;\n            }\n            case 'publicViewing': {\n              DEBUG_LOGS &&\n                console.log(`${PAGE}'${key}' value:`, { value: control.value, clip_private: !control.value });\n              clip.private = !control.value;\n              break;\n            }\n            case 'language':\n            case 'filmingDate': {\n              clip[key] = control.value;\n              break;\n            }\n          }\n        }\n      }\n    }\n    if (this.currentLat !== this.clip.geoLat) {\n      clip.geoLat = this.currentLat;\n    }\n    if (this.currentLng !== this.clip.geoLng) {\n      clip.geoLng = this.currentLng;\n    }\n    if (this.enableTags) {\n      clip.tags = this.clip.tags;\n    }\n\n    return { clip, isValid };\n  }\n\n  determinePlatform() {\n    return this.platform.ready().then((readySource) => {\n      if (readySource === 'dom') {\n        this.isPwa = true;\n        this.isNative = false;\n      } else if (readySource === 'cordova') {\n        // For native app\n        this.isPwa = false;\n        this.isNative = true;\n      } else {\n        console.info(\n          `${PAGE} determinePlatform readySource (${readySource}) NOT dom or cordova? platforms:`,\n          this.platform.platforms()\n        );\n        this.isPwa = true;\n        this.isNative = false;\n      }\n      return true;\n    });\n  }\n\n  setupMap() {\n    if (this.isPwa) {\n      // For browser\n      this.addGoogleScriptTagThenLoadMap();\n    } else if (this.isNative) {\n      // For mobile app\n      this.getLocationAccess();\n    } else {\n      console.warn(`${PAGE} setupMap platform UNKNOWN`);\n    }\n  }\n\n  async getLocationAccess() {\n    // For mobile app\n    if (this.isNative) {\n      try {\n        this.toaster.present(`Native Diagnotic in DEV...`);\n        // // detect if device's location is on or off\n        // const data = await this.diagnostic.isLocationEnabled();\n        // // if location is turned on\n        // if (data == true) {\n        //   this.loadMap();\n        // }\n        // // if location is turned off\n        // else if (data == false) {\n        //   // prompt user to turned on location\n        //   let alert = await this.alertCtrl.create({\n        //     header: 'Filmstacker',\n        //     message: \"To continue, please allow location services for your device.\",\n        //     buttons: [\n        //       {\n        //         text: 'Cancel',\n        //         role: 'cancel',\n        //         handler: () => {\n        //           console.log('Cancel clicked');\n        //           this.mapLoadingCanceled = true;\n        //         }\n        //       },\n        //       {\n        //         text: 'Ok',\n        //         handler: () => {\n        //           this.retryLocationAccess();\n        //         }\n        //       }\n        //     ]\n        //   });\n        //   await alert.present();\n        // }\n      } catch (error) {\n        console.warn(error);\n      }\n    }\n  }\n\n  retryLocationAccess() {\n    if (this.isNative) {\n      this.toaster.present(`Native Diagnotic in DEV...`);\n      //// redirect to setting for turned on location\n      // this.diagnostic.switchToLocationSettings(); // todo: re-enable\n\n      // // after coming back to app it will load map if location is turned on\n      // this.platform.resume.subscribe((e) => {\n      //   this.loadMap();\n      // })\n    } else {\n      this.setupMap();\n    }\n  }\n\n  /**\n   * load the G Maps API code asynchronously\n   * convert script tag in index.html to only load when needed\n   * <script async defer src=\"https://maps.google.com/maps/api/js?key=AIzaSyBnMwLZWa8o2AmTWJbVfd_bp44IvvgdkA4&callback=initGMap\"></script>\n   */\n  addGoogleScriptTagThenLoadMap(): void {\n    // console.log(`${PAGE} addGoogleScriptTag google:`, typeof google);\n\n    if (typeof google === 'undefined' || !google || !google.maps) {\n      console.log(`${PAGE} gMaps Adding google.maps script...`);\n      if (window) {\n        window['fsrGmapsCallback'] = () => {\n          console.log(`${PAGE} gMaps ready... mapLoaded?: ${this.mapLoaded}`);\n          if (!this.mapLoaded) {\n            this.loadMap();\n          }\n        };\n      } else {\n        console.warn(`${PAGE} WARN: no Window object...`);\n        this.loadMap();\n      }\n\n      const tag = document.createElement('script');\n      tag.src =\n        'https://maps.google.com/maps/api/js?key=AIzaSyBnMwLZWa8o2AmTWJbVfd_bp44IvvgdkA4&callback=fsrGmapsCallback';\n      const firstScriptTag = document.getElementsByTagName('script')[0];\n      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);\n    } else {\n      console.log(`${PAGE} gMaps google.maps already exists -> loadMap`);\n      this.loadMap();\n    }\n  }\n\n  loadMap = () => {\n    if (this.isNative) {\n      console.log(`${PAGE} loadMap TODO: native implementation`);\n      this.toaster.present(`Native Load Map implementation in dev...`);\n      // TODO: Native\n      // this.geolocation.getCurrentPosition().then((position) => {\n      //   // console.log(\"longitude: \" + position.coords.longitude);\n      //   this.currentLat = position.coords.latitude;\n      //   this.currentLng = position.coords.longitude;\n      //   this.setMap();\n      // }, (err) => {\n      //   console.log(err);\n      // });\n    } else {\n      if (this.currentLng && this.currentLat) {\n        this.setMap();\n      } else {\n        this.getCurrentPosition();\n      }\n    }\n  };\n\n  getCurrentPosition() {\n    if (navigator && navigator.geolocation) {\n      /**\n       * Create local functions due to callback having different 'this' context\n       * fix: Cannot read property 'toaster' of null\n       */\n      const positionError = (error) => {\n        switch (error.code) {\n          case error.PERMISSION_DENIED:\n            console.warn('User denied the request for Geolocation.');\n            this.mapLoadingCanceled = true;\n            break;\n          case error.POSITION_UNAVAILABLE:\n            console.warn('Location information is unavailable.');\n            this.toaster.present(`Location information is unavailable. Please reload the page and try again.`);\n            break;\n          case error.TIMEOUT:\n            console.warn('The request to get user location timed out.');\n            this.toaster.present(`The request to get user location timed out. Please reload the page and try again.`);\n            break;\n          case error.UNKNOWN_ERROR:\n            console.warn('An unknown error occurred.', error);\n            this.toaster.present(`An unknown location error occurred. Please reload the page and try again.`);\n            break;\n          default:\n            console.warn('An uncaught error occurred.', error);\n        }\n      };\n\n      const setCurrentPosition = (position) => {\n        if (!position || !position.coords) {\n          console.warn(`${PAGE} setCurrentPosition !position.coords?`, position);\n          return;\n        }\n        DEBUG_LOGS &&\n          console.log(`${PAGE} setCurrentPosition`, {\n            accuracy: position.coords.accuracy,\n            altitude: position.coords.altitude,\n            altitudeAccuracy: position.coords.altitudeAccuracy,\n            heading: position.coords.heading,\n            latitude: position.coords.latitude,\n            longitude: position.coords.longitude,\n            speed: position.coords.speed,\n          });\n        this.currentLat = position.coords.latitude;\n        this.currentLng = position.coords.longitude;\n\n        this.setMap();\n      };\n\n      navigator.geolocation.getCurrentPosition(setCurrentPosition, positionError, {\n        enableHighAccuracy: false,\n        timeout: 15000,\n        maximumAge: 0,\n      });\n    } else {\n      console.warn(`${PAGE} getCurrentPosition !navigator.geolocation`, navigator);\n      this.toaster.present(`We were not able to access the geolocation api. Please try reloading the page...`);\n    }\n  }\n\n  setMap = () => {\n    if (typeof google != 'undefined' && google && google.maps) {\n      this.mapLoaded = true;\n      const latLng = new google.maps.LatLng(this.currentLat, this.currentLng);\n      const mapOptions = {\n        center: latLng,\n        zoom: 6,\n        mapTypeId: 'hybrid',\n        enableHighAccuracy: true,\n        timeout: Infinity,\n        gestureHandling: 'cooperative', // Prevents map pan and zoom on page scroll (https://developers.google.com/maps/documentation/javascript/interaction)\n      };\n\n      /**\n       * SENTRY-HS EXCEPTION:\n       * TypeError: undefined is not an object (evaluating 'this.mapElement.nativeElement') at setMap\n       */\n      if (!this.mapElement || !this.mapElement.nativeElement) {\n        console.warn(`WARN: setMap this.mapElement.nativeElement is UNDEFINED`);\n        this.toaster.present(`Hmm. We were unable to load the Map. Please refresh to try again.`);\n        return;\n      }\n\n      this.map = new google.maps.Map(this.mapElement.nativeElement, mapOptions);\n      this.addMarker();\n    }\n  };\n\n  addMarker = () => {\n    const marker = new google.maps.Marker({\n      map: this.map,\n      animation: google.maps.Animation.DROP,\n      position: this.map.getCenter(),\n      draggable: true,\n    });\n\n    new google.maps.event.addListener(marker, 'dragend', () => {\n      this.currentLat = marker.getPosition().lat();\n      this.currentLng = marker.getPosition().lng();\n      DEBUG_LOGS &&\n        console.log(`${PAGE} Marker dragend:`, { currentLat: this.currentLat, currentLng: this.currentLng });\n    });\n  };\n\n  onTagSelected(item: string) {\n    DEBUG_LOGS && console.log(`${PAGE} onTagSelected: %o`, item);\n  }\n  onTagRemoved(item: string) {\n    this.clip.tags = Utils.removeFromArray(this.clip.tags, item);\n    DEBUG_LOGS && console.log(`${PAGE} onTagRemoved: %o`, item, this.clip.tags);\n  }\n  onTagAdded(item: string) {\n    Utils.addToArrayUnique(this.clip.tags, item.toLowerCase());\n    DEBUG_LOGS && console.log(`${PAGE} onTagAdded: %o`, item, this.clip.tags);\n  }\n\n  onChangeTitle(event: Event) {\n    const customEvent = event as InputCustomEvent;\n\n    const value = customEvent.detail.value;\n    this.curTitleLen = value ? value.length : 0;\n  }\n  onChangeDesc(event: Event) {\n    const customEvent = event as TextareaCustomEvent;\n\n    const value = customEvent.detail.value;\n    this.curDescLen = value ? value.length : 0;\n  }\n\n  async openPrivacyPolicy() {\n    const modal = await this.modalCtrl.create({\n      component: PrivacyPage,\n      componentProps: {\n        isModal: true,\n      },\n    });\n    return await modal.present();\n  }\n\n  async openTerms() {\n    const modal = await this.modalCtrl.create({\n      component: TermsPage,\n      componentProps: {\n        isModal: true,\n      },\n    });\n    return await modal.present();\n  }\n\n  /**\n   * DEV HLS TRANSCODE MVP-742\n   */\n  async confirmTranscode() {\n    return await this.videoService.confirmSendClipForHLSTranscode(this.clip);\n  }\n}\n","<ion-header *ngIf=\"isModal\">\n\n  <app-clipper-segment-bar\n    [showBackButton]=\"true\"\n    [selectedSegment]=\"selectedSegment\"\n    (onSelectSegment)=\"onSelectSegment($event)\"\n    (onDismiss)=\"dismiss()\"\n  ></app-clipper-segment-bar>\n\n</ion-header>\n\n<ion-content color=\"dark\">\n\n  <div [ngSwitch]=\"selectedSegment\" *ngIf=\"clip; else noClip\" class=\"segment-wrap\" [ngClass]=\"{ 'modal': isModal }\">\n\n    <div *ngSwitchCase=\"segmentNames.Trim\" class=\"trim segment-view\">\n      <app-trimmer\n        [clip]=\"clip\"\n        [currentUserId]=\"currentUserId$ | async\"\n        [project]=\"project$ | async\"\n      ></app-trimmer>\n    </div>\n      \n    <div *ngSwitchCase=\"segmentNames.Poster\" class=\"poster segment-view\">\n      <app-select-poster\n        [clip]=\"clip\"\n        [currentUserId]=\"currentUserId$ | async\"\n        [project]=\"project$ | async\"\n      ></app-select-poster>\n    </div>\n    \n    <div *ngSwitchCase=\"segmentNames.Settings\" class=\"settings segment-view\">\n      <app-clip-settings\n        [clip]=\"clip\"\n        [currentUserId]=\"currentUserId$ | async\"\n        [project]=\"project$ | async\"\n      ></app-clip-settings>\n    </div>\n  </div>\n\n\n\n  <ng-template #noClip>\n    <p class=\"ion-padding ion-text-center\">{{ 'ERRORS.NO_CLIP_FOUND' | translate }}</p>\n  </ng-template>\n\n</ion-content>\n\n<ion-footer *ngIf=\"isModal\">\n  <ion-toolbar color=\"dark\">\n    <ion-buttons slot=\"start\">\n      <ion-button (click)=\"dismiss()\">\n        {{ cancelText }}\n      </ion-button>\n    </ion-buttons>\n  </ion-toolbar>\n</ion-footer>","/** @format */\n\nimport { Component, OnInit, Input, OnDestroy } from '@angular/core';\nimport { NgIf, NgSwitch, NgClass, NgSwitchCase, AsyncPipe } from '@angular/common';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport {\n  ModalController,\n  IonHeader,\n  IonContent,\n  IonFooter,\n  IonToolbar,\n  IonButtons,\n  IonButton,\n} from '@ionic/angular/standalone';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { Observable, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { UserService } from '@app/core/services/user.service';\nimport { Clip } from '@app/shared/models/clip.model';\nimport { Project } from '@app/projects/shared/project.model';\nimport { ProjectService } from '@app/projects/shared/services/project.service';\nimport { ClipperSegmentBarComponent } from './clipper-segment-bar/clipper-segment-bar.component';\nimport { TrimmerComponent } from './trimmer/trimmer.component';\nimport { SelectPosterComponent } from './select-poster/select-poster.component';\nimport { ClipSettingsComponent } from './clip-settings/clip-settings.component';\n\nconst PAGE = '[Clipper]';\n\nexport enum ClipperSegments {\n  Trim = 'TRIM',\n  Split = 'SPLIT',\n  Poster = 'POSTER',\n  Settings = 'SETTINGS',\n  // Preview = \"PREVIEW\",\n}\n\n@Component({\n  selector: 'app-clipper',\n  templateUrl: './clipper.component.html',\n  styleUrls: ['./clipper.component.scss'],\n  standalone: true,\n  imports: [\n    NgIf,\n    IonHeader,\n    ClipperSegmentBarComponent,\n    IonContent,\n    NgSwitch,\n    NgClass,\n    NgSwitchCase,\n    TrimmerComponent,\n    SelectPosterComponent,\n    ClipSettingsComponent,\n    IonFooter,\n    IonToolbar,\n    IonButtons,\n    IonButton,\n    AsyncPipe,\n    TranslatePipe,\n  ],\n})\nexport class ClipperComponent implements OnInit, OnDestroy {\n  @Input()\n  set clip(val) {\n    this._clip = val;\n    if (val && val.projectId) {\n      /**\n       * @todo validate this logic...\n       */\n      this.project$ = this.projectService.getProject(val.projectId);\n    }\n  }\n  get clip() {\n    return this._clip;\n  }\n  @Input() selectedSegment: ClipperSegments = ClipperSegments.Settings;\n  @Input() isModal: boolean = false;\n  @Input() cancelText: string = 'Cancel'; // if isModal, show in footer\n  @Input() returnUrl: string;\n  @Input() defaultReturnUrl = '/stack/studio';\n\n  // @ViewChild(ClipSettingsComponent, {static: false}) clipSettingsComponent: ClipSettingsComponent;\n  // @ViewChild(TrimmerComponent, {static: false}) trimmerComponent: TrimmerComponent;\n  // @ViewChild(SelectPosterComponent, {static: false}) selectPosterComponent: SelectPosterComponent;\n\n  currentUserId$: Observable<string>;\n  project$: Observable<Project>;\n  segmentNames = ClipperSegments;\n\n  private _clip: Clip;\n  private onDestroy$ = new Subject<void>();\n\n  constructor(\n    private modalCtrl: ModalController,\n    private userService: UserService,\n    private projectService: ProjectService,\n    private route: ActivatedRoute,\n    private router: Router\n  ) {}\n\n  ngOnInit() {\n    // intended as a \"Cancel\" button, but not necessary with the back button\n    // this.returnUrl = this.returnUrl || this.defaultReturnUrl;\n    this.selectedSegment = this.isSegment(this.selectedSegment) ? this.selectedSegment : ClipperSegments.Settings;\n\n    this.currentUserId$ = this.userService.userId$;\n\n    this.route.queryParams.pipe(takeUntil(this.onDestroy$)).subscribe((params) => {\n      if (params?.returnUrl) {\n        this.returnUrl = params.returnUrl; //JSON.parse(params.returnUrl);\n        console.log(`${PAGE} queryParams returnUrl:`, this.returnUrl);\n      } else if (this.router.getCurrentNavigation()?.extras?.state) {\n        this.returnUrl = this.router.getCurrentNavigation().extras.state.returnUrl || '';\n        console.log(`${PAGE} navState:`, { returnUrl: this.returnUrl });\n      }\n    });\n  }\n\n  isSegment(name: string): boolean {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    return (Object as any).values(ClipperSegments).includes(name);\n  }\n\n  dismiss() {\n    if (!this.isModal) return;\n    // using the injected ModalController this page\n    // can \"dismiss\" itself and optionally pass back data\n    this.modalCtrl.dismiss({\n      clip: this.clip,\n    });\n  }\n\n  onSelectSegment(event) {\n    if (event && this.isSegment(event)) {\n      this.selectedSegment = event;\n    } else {\n      console.warn(`${PAGE} onSelectSegment NO VALUE or !isSegment?:`, event);\n    }\n  }\n\n  navTrim() {\n    this.selectedSegment = ClipperSegments.Trim;\n  }\n  navPoster() {\n    this.selectedSegment = ClipperSegments.Poster;\n  }\n  navSettings() {\n    this.selectedSegment = ClipperSegments.Settings;\n  }\n\n  ngOnDestroy() {\n    this.onDestroy$.next();\n    this.onDestroy$.complete();\n  }\n}\n"],"x_google_ignoreList":[]}