{"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 & 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> / > < \\\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> > or <\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":[]}