diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b4be9a76..6dcd04e99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.61.2 - 2022-07-20 + +### Fixed + +- Hide camera flash button for front camera +- Android flash light on only on capture photo or record video + +## 0.61.1 - 2022-07-19 + +### Added + +- Camera flash light + +### Fixed + +- Capture flow, confirm button work smoothly +- Use high resolution as default camera settings + ## 0.60.2 - 2022-07-07 ### Changed @@ -15,6 +33,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix withdraw page the text color +## 0.61.0 - 2022-07-14 + +### Added + +- Show discard/confirm capture before upload +- Send generate SEO img & description on share asset + +### Fixed + +- Remove capture after discard/confirm + ## 0.60.1 - 2022-07-06 ### Fixed diff --git a/README.md b/README.md index 13341cbea..d9b000a4e 100644 --- a/README.md +++ b/README.md @@ -77,12 +77,10 @@ cordova-res android --skip-config --copy #### Android -If your operating system is Linux, set the `linuxAndroidStudioPath` in `capacitor.config.json`. For example, +If your operating system is Linux, set the environment variable `CAPACITOR_ANDROID_STUDIO_PATH` for your Android Studio. The default value is `/usr/local/android-studio/bin/studio.sh`. -```json -{ - "linuxAndroidStudioPath": "/home/username/android-studio/bin/studio.sh" -} +```sh +export CAPACITOR_ANDROID_STUDIO_PATH="/home/username/android-studio/bin/studio.sh" ``` Before running the app with Android Studio, build and sync the dependencies and web assets. diff --git a/android/app/build.gradle b/android/app/build.gradle index 07c85a749..4e09291be 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -6,8 +6,8 @@ android { applicationId "io.numbersprotocol.capturelite" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 422 - versionName "0.60.2" + versionCode 432 + versionName "0.61.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildFeatures { diff --git a/package-lock.json b/package-lock.json index 5b2129103..f04aee225 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "capture-lite", - "version": "0.60.2", + "version": "0.61.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "capture-lite", - "version": "0.60.2", + "version": "0.61.2", "dependencies": { "@angular/animations": "^12.2.4", "@angular/cdk": "^12.2.4", @@ -48,7 +48,7 @@ "@ngx-formly/core": "^5.10.22", "@ngx-formly/material": "^5.10.22", "@ngx-formly/schematics": "^5.10.22", - "@numbersprotocol/preview-camera": "github:numbersprotocol/preview-camera#release-0.0.2-auto-rotate-fix", + "@numbersprotocol/preview-camera": "github:numbersprotocol/preview-camera", "@numbersprotocol/preview-video": "github:numbersprotocol/preview-video", "@techiediaries/ngx-qrcode": "^9.1.0", "async-mutex": "^0.3.2", @@ -4157,8 +4157,8 @@ } }, "node_modules/@numbersprotocol/preview-camera": { - "version": "0.0.2", - "resolved": "git+ssh://git@github.com/numbersprotocol/preview-camera.git#2ce3dc63f83780c4c8e7afe8291238b9c838eb5c", + "version": "0.0.5", + "resolved": "git+ssh://git@github.com/numbersprotocol/preview-camera.git#460cdc935ff16e14feca062c0d3cd6b35cf9996b", "license": "MIT", "peerDependencies": { "@capacitor/core": "^3.0.0" @@ -8111,18 +8111,18 @@ } }, "node_modules/date-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz", - "integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.11.tgz", + "integrity": "sha512-VS20KRyorrbMCQmpdl2hg5KaOUsda1RbnsJg461FfrcyCUg+pkd0b40BSW4niQyTheww4DBXQnS7HwSrKkipLw==", "dev": true, "engines": { "node": ">=4.0" } }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -10346,9 +10346,9 @@ } }, "node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", "dev": true }, "node_modules/flatten": { @@ -13727,27 +13727,21 @@ } }, "node_modules/log4js": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz", - "integrity": "sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.6.0.tgz", + "integrity": "sha512-3v8R7fd45UB6THucSht6wN2/7AZEruQbXdjygPZcxt5TA/msO6si9CN5MefUuKXbYnJHTBnYcx4famwcyQd+sA==", "dev": true, "dependencies": { - "date-format": "^3.0.0", - "debug": "^4.1.1", - "flatted": "^2.0.1", - "rfdc": "^1.1.4", - "streamroller": "^2.2.4" + "date-format": "^4.0.11", + "debug": "^4.3.4", + "flatted": "^3.2.5", + "rfdc": "^1.3.0", + "streamroller": "^3.1.1" }, "engines": { "node": ">=8.0" } }, - "node_modules/log4js/node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, "node_modules/loglevel": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", @@ -21610,40 +21604,52 @@ } }, "node_modules/streamroller": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz", - "integrity": "sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.1.tgz", + "integrity": "sha512-iPhtd9unZ6zKdWgMeYGfSBuqCngyJy1B/GPi/lTpwGpa3bajuX30GjUVd0/Tn/Xhg0mr4DOSENozz9Y06qyonQ==", "dev": true, "dependencies": { - "date-format": "^2.1.0", - "debug": "^4.1.1", - "fs-extra": "^8.1.0" + "date-format": "^4.0.10", + "debug": "^4.3.4", + "fs-extra": "^10.1.0" }, "engines": { "node": ">=8.0" } }, - "node_modules/streamroller/node_modules/date-format": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", - "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", + "node_modules/streamroller/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": ">=4.0" + "node": ">=12" } }, - "node_modules/streamroller/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/streamroller/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "universalify": "^2.0.0" }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/streamroller/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, "engines": { - "node": ">=6 <7 || >=8" + "node": ">= 10.0.0" } }, "node_modules/strict-uri-encode": { @@ -28525,8 +28531,8 @@ } }, "@numbersprotocol/preview-camera": { - "version": "git+ssh://git@github.com/numbersprotocol/preview-camera.git#2ce3dc63f83780c4c8e7afe8291238b9c838eb5c", - "from": "@numbersprotocol/preview-camera@github:numbersprotocol/preview-camera#release-0.0.2-auto-rotate-fix", + "version": "git+ssh://git@github.com/numbersprotocol/preview-camera.git#460cdc935ff16e14feca062c0d3cd6b35cf9996b", + "from": "@numbersprotocol/preview-camera@github:numbersprotocol/preview-camera", "requires": {} }, "@numbersprotocol/preview-video": { @@ -31611,15 +31617,15 @@ } }, "date-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz", - "integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.11.tgz", + "integrity": "sha512-VS20KRyorrbMCQmpdl2hg5KaOUsda1RbnsJg461FfrcyCUg+pkd0b40BSW4niQyTheww4DBXQnS7HwSrKkipLw==", "dev": true }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -33455,9 +33461,9 @@ } }, "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", "dev": true }, "flatten": { @@ -36020,24 +36026,16 @@ } }, "log4js": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz", - "integrity": "sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.6.0.tgz", + "integrity": "sha512-3v8R7fd45UB6THucSht6wN2/7AZEruQbXdjygPZcxt5TA/msO6si9CN5MefUuKXbYnJHTBnYcx4famwcyQd+sA==", "dev": true, "requires": { - "date-format": "^3.0.0", - "debug": "^4.1.1", - "flatted": "^2.0.1", - "rfdc": "^1.1.4", - "streamroller": "^2.2.4" - }, - "dependencies": { - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - } + "date-format": "^4.0.11", + "debug": "^4.3.4", + "flatted": "^3.2.5", + "rfdc": "^1.3.0", + "streamroller": "^3.1.1" } }, "loglevel": { @@ -42024,32 +42022,42 @@ } }, "streamroller": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz", - "integrity": "sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.1.tgz", + "integrity": "sha512-iPhtd9unZ6zKdWgMeYGfSBuqCngyJy1B/GPi/lTpwGpa3bajuX30GjUVd0/Tn/Xhg0mr4DOSENozz9Y06qyonQ==", "dev": true, "requires": { - "date-format": "^2.1.0", - "debug": "^4.1.1", - "fs-extra": "^8.1.0" + "date-format": "^4.0.10", + "debug": "^4.3.4", + "fs-extra": "^10.1.0" }, "dependencies": { - "date-format": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", - "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", - "dev": true - }, "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "requires": { "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true } } }, diff --git a/package.json b/package.json index 434af9dda..37fe08243 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "capture-lite", - "version": "0.60.2", + "version": "0.61.2", "author": "numbersprotocol", "homepage": "https://numbersprotocol.io/", "scripts": { @@ -59,7 +59,7 @@ "@ngx-formly/core": "^5.10.22", "@ngx-formly/material": "^5.10.22", "@ngx-formly/schematics": "^5.10.22", - "@numbersprotocol/preview-camera": "github:numbersprotocol/preview-camera#release-0.0.2-auto-rotate-fix", + "@numbersprotocol/preview-camera": "github:numbersprotocol/preview-camera", "@numbersprotocol/preview-video": "github:numbersprotocol/preview-video", "@techiediaries/ngx-qrcode": "^9.1.0", "async-mutex": "^0.3.2", diff --git a/src/app/features/home/custom-camera/custom-camera-routing.module.ts b/src/app/features/home/custom-camera/custom-camera-routing.module.ts index 471a97ef7..fbba440f6 100644 --- a/src/app/features/home/custom-camera/custom-camera-routing.module.ts +++ b/src/app/features/home/custom-camera/custom-camera-routing.module.ts @@ -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'; diff --git a/src/app/features/home/custom-camera/custom-camera.module.ts b/src/app/features/home/custom-camera/custom-camera.module.ts index c4b4c14b7..c5d485bb5 100644 --- a/src/app/features/home/custom-camera/custom-camera.module.ts +++ b/src/app/features/home/custom-camera/custom-camera.module.ts @@ -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: [ @@ -16,6 +17,6 @@ import { CustomCameraService } from './custom-camera.service'; JoyrideModule.forChild(), ], providers: [CustomCameraService], - declarations: [CustomCameraPage], + declarations: [CustomCameraPage, PrePublishModeComponent], }) export class CustomCameraPageModule {} diff --git a/src/app/features/home/custom-camera/custom-camera.page.html b/src/app/features/home/custom-camera/custom-camera.page.html index 313f5fc19..21ff52413 100644 --- a/src/app/features/home/custom-camera/custom-camera.page.html +++ b/src/app/features/home/custom-camera/custom-camera.page.html @@ -3,61 +3,83 @@ [style.--background]="'transparent'" *transloco="let t" > -
-
- GoPro - featured_video -
+ +
- - close - - -
- - video_collection + + {{ isFlashOn ? 'flash_on' : 'flash_off' }} - +
+ GoPro + featured_video +
- flip_camera_android + close -
+ +
+ + video_collection + + + + + + flip_camera_android + +
+
+ + + diff --git a/src/app/features/home/custom-camera/custom-camera.page.scss b/src/app/features/home/custom-camera/custom-camera.page.scss index 9331afe28..e367e6529 100644 --- a/src/app/features/home/custom-camera/custom-camera.page.scss +++ b/src/app/features/home/custom-camera/custom-camera.page.scss @@ -13,6 +13,12 @@ mat-icon { width: 36px; } +mat-icon.flash-camera-button { + position: absolute; + top: 16px; + left: 16px; +} + mat-icon.close-camera-button { position: absolute; top: 16px; diff --git a/src/app/features/home/custom-camera/custom-camera.page.ts b/src/app/features/home/custom-camera/custom-camera.page.ts index d6a4b1585..41698a600 100644 --- a/src/app/features/home/custom-camera/custom-camera.page.ts +++ b/src/app/features/home/custom-camera/custom-camera.page.ts @@ -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'; @@ -33,6 +34,16 @@ 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; + + isFlashOn = false; + isFlashAvailable = false; + readonly lastConnectedGoProDevice$ = this.goProBluetoothService.lastConnectedDevice$; @@ -59,6 +70,8 @@ export class CustomCameraPage implements OnInit, OnDestroy { ).then((listener: any) => (this.captureVideoFinishedListener = listener)); this.startPreviewCamera(); + + this.syncCameraState(); } async ionViewDidEnter() { @@ -85,12 +98,24 @@ 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(); } } - startPreviewCamera() { - this.customCameraService.startPreviewCamera(); + async startPreviewCamera() { + await this.customCameraService.startPreviewCamera(); + await this.syncCameraState(); } // eslint-disable-next-line class-methods-use-this @@ -98,8 +123,14 @@ export class CustomCameraPage implements OnInit, OnDestroy { this.customCameraService.stopPreviewCamera(); } - flipCamera() { - this.customCameraService.flipCamera(); + async flipCamera() { + await this.customCameraService.flipCamera(); + await this.syncCameraState(); + } + + async syncCameraState() { + this.isFlashOn = (await this.isTorchOn()).result; + this.isFlashAvailable = await this.customCameraService.isTorchAvailable(); } onPress() { @@ -131,6 +162,31 @@ export class CustomCameraPage implements OnInit, OnDestroy { } } + discardCurrentCapture() { + this.mode$.next('capture'); + this.startPreviewCamera(); + this.removeCurrentCapture(); + } + + async confirmCurrentCapture() { + if (this.curCaptureFilePath && this.curCaptureType) { + this.customCameraService.uploadToCapture( + this.curCaptureFilePath, + this.curCaptureType + ); + this.leaveCustomCamera(); + } + } + + async isTorchOn() { + return this.customCameraService.isTorchOn(); + } + + async enableTorch() { + await this.customCameraService.enableTorch(!this.isFlashOn); + this.isFlashOn = (await this.customCameraService.isTorchOn()).result; + } + async leaveCustomCamera() { return this.location.back(); } @@ -142,6 +198,13 @@ export class CustomCameraPage implements OnInit, OnDestroy { }); } + private removeCurrentCapture() { + this.customCameraService.removeFile(this.curCaptureFilePath); + 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 diff --git a/src/app/features/home/custom-camera/custom-camera.service.spec.ts b/src/app/features/home/custom-camera/custom-camera.service.spec.ts index 288da8ca1..383e6e88c 100644 --- a/src/app/features/home/custom-camera/custom-camera.service.spec.ts +++ b/src/app/features/home/custom-camera/custom-camera.service.spec.ts @@ -1,14 +1,30 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed, waitForAsync } from '@angular/core/testing'; +import { Platform } from '@ionic/angular'; import { SharedTestingModule } from '../../../shared/shared-testing.module'; import { CustomCameraService } from './custom-camera.service'; describe('CustomCameraService', () => { let service: CustomCameraService; + let platformReadySpy: Promise; + let platformIsSpy: boolean | undefined; + let platformSpy: Platform; - beforeEach(() => { - TestBed.configureTestingModule({ imports: [SharedTestingModule] }); - service = TestBed.inject(CustomCameraService); - }); + beforeEach( + waitForAsync(() => { + platformReadySpy = Promise.resolve(); + platformIsSpy = false; + platformSpy = jasmine.createSpyObj('Platform', { + ready: platformReadySpy, + is: platformIsSpy, + }); + + TestBed.configureTestingModule({ + imports: [SharedTestingModule], + providers: [{ provide: Platform, useValue: platformSpy }], + }).compileComponents(); + service = TestBed.inject(CustomCameraService); + }) + ); it('should be created', () => { expect(service).toBeTruthy(); diff --git a/src/app/features/home/custom-camera/custom-camera.service.ts b/src/app/features/home/custom-camera/custom-camera.service.ts index 30febf614..2e7143fbc 100644 --- a/src/app/features/home/custom-camera/custom-camera.service.ts +++ b/src/app/features/home/custom-camera/custom-camera.service.ts @@ -1,10 +1,13 @@ import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; +import { Inject, Injectable } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { Capacitor } from '@capacitor/core'; +import { FilesystemPlugin } from '@capacitor/filesystem'; +import { Platform } from '@ionic/angular'; import { TranslocoService } from '@ngneat/transloco'; import { PreviewCamera } from '@numbersprotocol/preview-camera'; import { BehaviorSubject } from 'rxjs'; +import { FILESYSTEM_PLUGIN } from '../../../shared/capacitor-plugins/capacitor-plugins.module'; import { CaptureService } from '../../../shared/capture/capture.service'; import { ErrorService } from '../../../shared/error/error.service'; import { blobToBase64 } from '../../../utils/encoding/encoding'; @@ -27,7 +30,10 @@ export class CustomCameraService { private readonly httpClient: HttpClient, private readonly captureService: CaptureService, private readonly errorService: ErrorService, - private readonly translocoService: TranslocoService + private readonly translocoService: TranslocoService, + @Inject(FILESYSTEM_PLUGIN) + private readonly filesystemPlugin: FilesystemPlugin, + private readonly platform: Platform ) {} private mediaItemFromFilePath( @@ -52,6 +58,7 @@ export class CustomCameraService { const base64 = await blobToBase64(itemBlob); const mimeType = itemToUpload.mimeType; await this.captureService.capture({ base64, mimeType }); + await this.removeFile(filePath); } catch (error) { const errMsg = this.translocoService.translate(`error.internetError`); await this.errorService.toastError$(errMsg).toPromise(); @@ -89,6 +96,36 @@ export class CustomCameraService { return PreviewCamera.stopRecord().catch(() => ({})); } + async removeFile(filePath: string | undefined) { + if (!filePath) return; + await this.filesystemPlugin.deleteFile({ path: filePath }); + } + + async isTorchOn() { + if (this.isNativePlatform) { + return await PreviewCamera.isTorchOn(); + } + return { result: false }; + } + + async enableTorch(enable: boolean): Promise { + if (this.isNativePlatform) { + return await PreviewCamera.enableTorch({ enable }); + } + return Promise.resolve(); + } + + async isTorchAvailable(): Promise { + if (this.isNativePlatform) { + return (await PreviewCamera.isTorchAvailable()).result; + } + return false; + } + + private get isNativePlatform() { + return this.platform.is('ios') || this.platform.is('android'); + } + private changeGlobalCSSBackgroundToTransparent() { document.querySelector('body')?.classList.add(this.globalCSSClass); document.querySelector('ion-app')?.classList.add(this.globalCSSClass); diff --git a/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.html b/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.html new file mode 100644 index 000000000..eadb07419 --- /dev/null +++ b/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.html @@ -0,0 +1,20 @@ +
+ + + +
+ +
+ +
+ + diff --git a/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.scss b/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.scss new file mode 100644 index 000000000..174d93691 --- /dev/null +++ b/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.scss @@ -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; + } +} diff --git a/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.spec.ts b/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.spec.ts new file mode 100644 index 000000000..1aacbb205 --- /dev/null +++ b/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.spec.ts @@ -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; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [PrePublishModeComponent], + imports: [SharedTestingModule], + }).compileComponents(); + + fixture = TestBed.createComponent(PrePublishModeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }) + ); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.ts b/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.ts new file mode 100644 index 000000000..1fea586aa --- /dev/null +++ b/src/app/features/home/custom-camera/pre-publish-mode/pre-publish-mode.component.ts @@ -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 = new EventEmitter(); + + @Output() confirm: EventEmitter = new EventEmitter(); + + onDiscard() { + this.discard.emit(null); + } + + onConfirm() { + this.confirm.emit(null); + } +} diff --git a/src/app/features/home/details/details.page.ts b/src/app/features/home/details/details.page.ts index 7403f8762..e22a25305 100644 --- a/src/app/features/home/details/details.page.ts +++ b/src/app/features/home/details/details.page.ts @@ -22,6 +22,7 @@ import { tap, } from 'rxjs/operators'; import SwiperCore, { Swiper, Virtual } from 'swiper/core'; +import { ActionsService } from '../../../shared/actions/service/actions.service'; import { BlockingActionService } from '../../../shared/blocking-action/blocking-action.service'; import { ConfirmAlert } from '../../../shared/confirm-alert/confirm-alert.service'; import { ContactSelectionDialogComponent } from '../../../shared/contact-selection-dialog/contact-selection-dialog.component'; @@ -207,7 +208,8 @@ export class DetailsPage { private readonly diaBackendWorkflowService: DiaBackendWorkflowService, private readonly alertController: AlertController, private readonly changeDetectorRef: ChangeDetectorRef, - private readonly userGuideService: UserGuideService + private readonly userGuideService: UserGuideService, + private readonly actionsService: ActionsService ) { this.initializeActiveDetailedCapture$ .pipe(untilDestroyed(this)) @@ -467,6 +469,11 @@ export class DetailsPage { activeDetailedCapture => activeDetailedCapture.diaBackendAsset$ ), isNonNullable(), + tap(diaBackendAsset => + this.actionsService + .generateSeoImageAndDescription$(diaBackendAsset) + .toPromise() + ), concatMap(diaBackendAsset => this.shareService.share(diaBackendAsset)), catchError((err: unknown) => this.errorService.toastError$(err)), untilDestroyed(this) diff --git a/src/app/shared/actions/service/actions.service.ts b/src/app/shared/actions/service/actions.service.ts index 0ac2eeedc..8076937f3 100644 --- a/src/app/shared/actions/service/actions.service.ts +++ b/src/app/shared/actions/service/actions.service.ts @@ -2,6 +2,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { defer, forkJoin, of } from 'rxjs'; import { map } from 'rxjs/operators'; +import { DiaBackendAsset } from '../../dia-backend/asset/dia-backend-asset-repository.service'; import { BUBBLE_DB_URL } from '../../dia-backend/secret'; @Injectable({ @@ -34,6 +35,16 @@ export class ActionsService { send$(url: string, body: any) { return this.httpClient.post(url, body); } + + generateSeoImageAndDescription$(diaBackendAsset: DiaBackendAsset) { + return this.httpClient.post( + `https://authmedia.net/api/1.1/obj/nftprofile`, + { + asset_url: diaBackendAsset.asset_file, + Description: diaBackendAsset.cid, + } + ); + } } export interface Action { diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 86caac067..314f771b7 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -268,6 +268,9 @@ "networkActionsAreUnavailable": "Network Actions are unavailable. Please try again later." } }, + "customCamera": { + "confirmCapture": "Confirm" + }, "wallets": { "wallets": "Wallets", "pullToRefreshBalance": "Pull to refresh balance", diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 0e7d43cf0..a7f060682 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -268,6 +268,9 @@ "networkActionsAreUnavailable": "暫時無法使用 Network Action,請稍後再試。" } }, + "customCamera": { + "confirmCapture": "確認" + }, "wallets": { "wallets": "錢包", "pullToRefreshBalance": "下拉以刷新餘額",