Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add pre-view page before uploading capture #1805

Merged
merged 2 commits into from Jul 13, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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
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
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
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
@@ -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>
@@ -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;
}
}
@@ -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();
});
});
@@ -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
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
Expand Up @@ -268,6 +268,9 @@
"networkActionsAreUnavailable": "暫時無法使用 Network Action,請稍後再試。"
}
},
"customCamera": {
"confirmCapture": "確認"
},
"wallets": {
"wallets": "錢包",
"pullToRefreshBalance": "下拉以刷新餘額",
Expand Down