Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { RouterModule, Routes } from '@angular/router';

import { CustomCameraPage } from './custom-camera.page';

Expand Down
3 changes: 2 additions & 1 deletion src/app/features/home/custom-camera/custom-camera.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SharedModule } from '../../../shared/shared.module';
import { CustomCameraPageRoutingModule } from './custom-camera-routing.module';
import { CustomCameraPage } from './custom-camera.page';
import { CustomCameraService } from './custom-camera.service';
import { PrePublishModeComponent } from './pre-publish-mode/pre-publish-mode.component';

@NgModule({
imports: [
Expand All @@ -16,6 +17,6 @@ import { CustomCameraService } from './custom-camera.service';
JoyrideModule.forChild(),
],
providers: [CustomCameraService],
declarations: [CustomCameraPage],
declarations: [CustomCameraPage, PrePublishModeComponent],
})
export class CustomCameraPageModule {}
117 changes: 65 additions & 52 deletions src/app/features/home/custom-camera/custom-camera.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,61 +3,74 @@
[style.--background]="'transparent'"
*transloco="let t"
>
<div id="camera-flash-placeholder"></div>
<div
class="select-from-go-pro-camera-button"
*ngIf="lastConnectedGoProDevice$ | ngrxPush"
(click)="captureFromGoPro()"
>
GoPro
<mat-icon> featured_video </mat-icon>
</div>

<mat-icon
class="close-camera-button"
(click)="leaveCustomCamera()"
joyrideStep="highlightCustomCameraCloseButton"
[title]="t('userGuide.cameraUsageGuide')"
[text]="t('userGuide.afterTakingPhotosOrRecordingVideosCloseAndGoBackHome')"
>
close
</mat-icon>

<div class="camera-buttons-container">
<mat-icon class="temporarily-hidden" id="gallery-icon">
video_collection
</mat-icon>

<circle-progress
(click)="onPress()"
[maxTime]="maxRecordTimeInMilliseconds"
ngxLongPress2
(onLongPress)="onLongPress()"
(onLongPressing)="onLongPressing($event)"
(onReleasePressing)="onReleasePressing()"
[percent]="curRecordTimeInPercent"
[radius]="38"
[outerStrokeWidth]="6"
[innerStrokeWidth]="4"
[outerStrokeColor]="'#78C000'"
[innerStrokeColor]="'#F2F2F2'"
[showTitle]="false"
[showUnits]="false"
[showSubtitle]="false"
[animation]="false"
[animationDuration]="0"
joyrideStep="highlightCustomCameraCaptureButton"
[title]="t('userGuide.cameraUsageGuide')"
[text]="t('userGuide.tapToTakeAPhotoAndLongPressToRecordVideo')"
></circle-progress>
<ng-container *ngIf="(mode$ | ngrxPush) === 'capture'">
<div id="camera-flash-placeholder"></div>
<div
class="select-from-go-pro-camera-button"
*ngIf="lastConnectedGoProDevice$ | ngrxPush"
(click)="captureFromGoPro()"
>
GoPro
<mat-icon> featured_video </mat-icon>
</div>

<mat-icon
(click)="flipCamera()"
joyrideStep="highlightCustomCameraFlipButton"
class="close-camera-button"
(click)="leaveCustomCamera()"
joyrideStep="highlightCustomCameraCloseButton"
[title]="t('userGuide.cameraUsageGuide')"
[text]="t('userGuide.flipTheCameraToSwitchBetweenFrontAndBackCameras')"
[text]="
t('userGuide.afterTakingPhotosOrRecordingVideosCloseAndGoBackHome')
"
>
flip_camera_android
close
</mat-icon>
</div>

<div class="camera-buttons-container">
<mat-icon class="temporarily-hidden" id="gallery-icon">
video_collection
</mat-icon>

<circle-progress
(click)="onPress()"
[maxTime]="maxRecordTimeInMilliseconds"
ngxLongPress2
(onLongPress)="onLongPress()"
(onLongPressing)="onLongPressing($event)"
(onReleasePressing)="onReleasePressing()"
[percent]="curRecordTimeInPercent"
[radius]="38"
[outerStrokeWidth]="6"
[innerStrokeWidth]="4"
[outerStrokeColor]="'#78C000'"
[innerStrokeColor]="'#F2F2F2'"
[showTitle]="false"
[showUnits]="false"
[showSubtitle]="false"
[animation]="false"
[animationDuration]="0"
joyrideStep="highlightCustomCameraCaptureButton"
[title]="t('userGuide.cameraUsageGuide')"
[text]="t('userGuide.tapToTakeAPhotoAndLongPressToRecordVideo')"
></circle-progress>

<mat-icon
(click)="flipCamera()"
joyrideStep="highlightCustomCameraFlipButton"
[title]="t('userGuide.cameraUsageGuide')"
[text]="t('userGuide.flipTheCameraToSwitchBetweenFrontAndBackCameras')"
>
flip_camera_android
</mat-icon>
</div>
</ng-container>
<ng-container *ngIf="(mode$ | ngrxPush) === 'pre-publish'">
<app-pre-publish-mode
[curCaptureFilePath]="curCaptureFilePath"
[curCaptureMimeType]="curCaptureMimeType"
[curCaptureSrc]="curCaptureSrc"
(confirm)="confirmCurrentCapture()"
(discard)="discardCurrentCapture()"
></app-pre-publish-mode>
</ng-container>
</ion-content>
47 changes: 45 additions & 2 deletions src/app/features/home/custom-camera/custom-camera.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
import { Location } from '@angular/common';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { PluginListenerHandle } from '@capacitor/core';
import { Capacitor, PluginListenerHandle } from '@capacitor/core';
import { UntilDestroy } from '@ngneat/until-destroy';
import { CaptureResult, PreviewCamera } from '@numbersprotocol/preview-camera';
import { BehaviorSubject } from 'rxjs';
import { ErrorService } from '../../../shared/error/error.service';
import { UserGuideService } from '../../../shared/user-guide/user-guide.service';
import { GoProBluetoothService } from '../../settings/go-pro/services/go-pro-bluetooth.service';
Expand Down Expand Up @@ -33,6 +34,13 @@ export class CustomCameraPage implements OnInit, OnDestroy {

curSessionCaptureMediaItems: CustomCameraMediaItem[] = [];

mode$ = new BehaviorSubject<'capture' | 'pre-publish'>('capture');

curCaptureFilePath?: string;
curCaptureMimeType?: 'image/jpeg' | 'video/mp4';
curCaptureType?: 'image' | 'video' = 'image';
curCaptureSrc?: string;

readonly lastConnectedGoProDevice$ =
this.goProBluetoothService.lastConnectedDevice$;

Expand Down Expand Up @@ -85,7 +93,18 @@ export class CustomCameraPage implements OnInit, OnDestroy {
if (data.errorMessage) {
await this.errorService.toastError$(data.errorMessage).toPromise();
} else if (data.filePath) {
this.customCameraService.uploadToCapture(data.filePath, type);
const filePath = data.filePath;

let mimeType: 'image/jpeg' | 'video/mp4' = 'image/jpeg';
if (type === 'video') mimeType = 'video/mp4';

this.curCaptureFilePath = filePath;
this.curCaptureMimeType = mimeType;
this.curCaptureType = type;
this.curCaptureSrc = Capacitor.convertFileSrc(filePath);
this.mode$.next('pre-publish');

this.stopPreviewCamera();
}
}

Expand Down Expand Up @@ -131,6 +150,23 @@ export class CustomCameraPage implements OnInit, OnDestroy {
}
}

discardCurrentCapture() {
this.mode$.next('capture');
this.startPreviewCamera();
this.removeCurrentCapture();
}

confirmCurrentCapture() {
if (this.curCaptureFilePath && this.curCaptureType) {
this.customCameraService.uploadToCapture(
this.curCaptureFilePath,
this.curCaptureType
);
this.removeCurrentCapture();
}
this.leaveCustomCamera();
}

async leaveCustomCamera() {
return this.location.back();
}
Expand All @@ -142,6 +178,13 @@ export class CustomCameraPage implements OnInit, OnDestroy {
});
}

private removeCurrentCapture() {
// TODO: remove file this.curCaptureFilePath to free space
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sultanmyrza Can we remove the unconfirmed file in this PR, or can you share some details of the difficulty, and we can open a following-up task for it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bafu, when user take photos or videos it's kept in file system so we need to clean up files. I don't think it's hard by I will add another pull req that will implement this feature (today)

this.curCaptureFilePath = undefined;
this.curCaptureMimeType = undefined;
this.curCaptureSrc = undefined;
}

// eslint-disable-next-line class-methods-use-this
private debugOnlyPreventContextMenuFromLongPressContextMenu() {
// Prevent showing context menu on long press
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<div class="action-buttons">
<button (click)="onDiscard()" class="back-button" mat-mini-fab>
<mat-icon>arrow_back</mat-icon>
</button>

<button
(click)="onConfirm()"
class="confirm-button"
mat-flat-button
*transloco="let t"
>
{{ t('customCamera.confirmCapture') | uppercase }}
</button>
</div>

<div class="preview" *ngIf="curCaptureFilePath && curCaptureMimeType">
<app-media [src]="curCaptureSrc" [mimeType]="curCaptureMimeType"></app-media>
</div>

<div class="footer"></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.action-buttons {
position: absolute;
top: 0;
left: 0;
right: 0;
padding: calc(var(--ion-safe-area-top) + 4px) 16px;
background-color: black;
display: flex;
flex-direction: row;
justify-content: space-between;
z-index: 100;
}

.footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: calc(var(--ion-safe-area-bottom) + 4px) 16px;
background-color: black;
display: flex;
flex-direction: row;
justify-content: space-between;
z-index: 100;
height: 75px;
}

.back-button {
background: #ffffff40 !important; /* stylelint-disable-line declaration-no-important */
color: white !important; /* stylelint-disable-line declaration-no-important */
backdrop-filter: blur(4px);
box-shadow: none;
}

.confirm-button {
background: #486cd9 !important; /* stylelint-disable-line declaration-no-important */
color: white !important; /* stylelint-disable-line declaration-no-important */
border-radius: 37px;
height: 38px;
}

.preview {
height: 100%;
overflow: auto;
display: flex;
flex-direction: column;
justify-content: center;

app-media {
width: 100%;
object-fit: cover;
object-position: center;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SharedTestingModule } from '../../../../shared/shared-testing.module';

import { PrePublishModeComponent } from './pre-publish-mode.component';

describe('PrePublishModeComponent', () => {
let component: PrePublishModeComponent;
let fixture: ComponentFixture<PrePublishModeComponent>;

beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [PrePublishModeComponent],
imports: [SharedTestingModule],
}).compileComponents();

fixture = TestBed.createComponent(PrePublishModeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
})
);

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
selector: 'app-pre-publish-mode',
templateUrl: './pre-publish-mode.component.html',
styleUrls: ['./pre-publish-mode.component.scss'],
})
export class PrePublishModeComponent {
@Input()
curCaptureFilePath?: string;

@Input()
curCaptureMimeType?: 'image/jpeg' | 'video/mp4';

@Input()
curCaptureSrc?: string;

@Output() discard: EventEmitter<any> = new EventEmitter();

@Output() confirm: EventEmitter<any> = new EventEmitter();

onDiscard() {
this.discard.emit(null);
}

onConfirm() {
this.confirm.emit(null);
}
}
3 changes: 3 additions & 0 deletions src/assets/i18n/en-us.json
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@
"networkActionsAreUnavailable": "Network Actions are unavailable. Please try again later."
}
},
"customCamera": {
"confirmCapture": "Confirm"
},
"wallets": {
"wallets": "Wallets",
"pullToRefreshBalance": "Pull to refresh balance",
Expand Down
3 changes: 3 additions & 0 deletions src/assets/i18n/zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@
"networkActionsAreUnavailable": "暫時無法使用 Network Action,請稍後再試。"
}
},
"customCamera": {
"confirmCapture": "確認"
},
"wallets": {
"wallets": "錢包",
"pullToRefreshBalance": "下拉以刷新餘額",
Expand Down