Skip to content

Commit

Permalink
migrate camera to capacitor. (#721)
Browse files Browse the repository at this point in the history
* migrate camera to capacitor.

* add dependency on lodash

* add www to gitignore

* add camera capacitor to readme.

* inject capacitor cors settings instead of using another profile

* add generators/** and mjs files to prettier.

* run prettier.

* add types to readme

* add android cors.

* add e2e-cors spring profile

* update snapshot

* run install

* drop prettier-plugin-java and update package lock
  • Loading branch information
mshima committed Jan 9, 2023
1 parent 3e85213 commit ddf136e
Show file tree
Hide file tree
Showing 55 changed files with 6,244 additions and 2,887 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ from the main (upstream) repository:

## <a name="setup"></a> Generator development setup

Ionic for JHipster is a [JHipster Blueprint](https://www.jhipster.tech/modules/creating-a-blueprint/).
Ionic for JHipster is a [JHipster Blueprint](https://www.jhipster.tech/modules/creating-a-blueprint/).

Here are the most important steps.

Expand Down
28 changes: 15 additions & 13 deletions generators/ionic/generator.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -198,19 +198,21 @@ export default class extends GeneratorBaseEntities {
async writeEntities({ entities }) {
const { enableTranslation } = this.application;
await Promise.all(
entities.filter(entity => !entity.builtIn).map(async entity => {
await this.writeFiles({
sections: entityFiles,
context: {
...entity,
enableTranslation,
},
});
// write client side files for angular
const { entityClassHumanized, entityAngularName, entityFileName, entityFolderName } = entity;
this.addEntityToModule({ entityClassHumanized, entityAngularName, entityFileName });
this.addEntityRouteToModule({ entityAngularName, entityFolderName, entityFileName });
})
entities
.filter(entity => !entity.builtIn)
.map(async entity => {
await this.writeFiles({
sections: entityFiles,
context: {
...entity,
enableTranslation,
},
});
// write client side files for angular
const { entityClassHumanized, entityAngularName, entityFileName, entityFolderName } = entity;
this.addEntityToModule({ entityClassHumanized, entityAngularName, entityFileName });
this.addEntityRouteToModule({ entityAngularName, entityFolderName, entityFileName });
})
);
},
};
Expand Down
2 changes: 2 additions & 0 deletions generators/ionic/resources/base/.gitignore.jhi.ionic
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<&_ if (!fragment.section) { -&>
# Ionic rules:
.angular
cypress/screenshots
cypress/videos
cypress/downloads
public
www
<&_ } -&>
3 changes: 3 additions & 0 deletions generators/ionic/resources/base/.prettierignore.jhi.ionic
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
.angular
cypress/screenshots
cypress/videos
cypress/downloads
public
www
<&_ } -&>
33 changes: 24 additions & 9 deletions generators/ionic/resources/base/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,36 @@ Then, run your project using the Capacitor CLI:
npx cap run ios
```

### Camera capacitor

When adding image fields, you need to add privacy notices to your `ios/App/App/Info.plist`.

```xml
<key>NSCameraUsageDescription</key>
<string>Privacy - Camera Usage Description</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Privacy - Photo Library Additions Usage Description</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Privacy - Photo Library Usage Description</string>
```

For more information refer to [@capacitor/camera](https://capacitorjs.com/docs/apis/camera#ios)

### Modify CORS Settings in JHipster

In order to communicate with your JHipster app, you'll need to modify its CORS settings (in `src/main/resources/config/application-dev.yml`) to allow `capacitor://localhost` as an origin.
In order to communicate with your JHipster app, you'll need to modify its CORS settings (in `src/main/resources/config/application-dev.yml`) make sure `capacitor://localhost` is allowed as an origin.

To run your app in iOS Simulator with hot-reload, run:

```
```bash
npx cap run ios -l --external
```

You will need to modify your JHipster app to allow your external IP as a trusted origin for this to work!

You can also open your project in Xcode and configure code signing.

```
```bash
npx cap open ios
```

Expand All @@ -101,7 +116,7 @@ Enable clear text traffic and add `dev.localhost.ionic` as a scheme in `android/
<data android:scheme="dev.localhost.ionic" />
<!--data android:scheme="com.okta.dev-133337" /-->
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
Expand All @@ -111,13 +126,13 @@ Enable clear text traffic and add `dev.localhost.ionic` as a scheme in `android/

Then, run your project using the Capacitor CLI:

```
```bash
npx cap run android
```

You'll need to run a couple commands to allow the emulator to communicate with JHipster (and Keycloak if you're using OIDC for authentication).

```
```bash
adb reverse tcp:8080 tcp:8080
adb reverse tcp:9080 tcp:9080
```
Expand All @@ -128,15 +143,15 @@ In order to communicate with your JHipster app, you'll need to modify its CORS s

To run your app in iOS Simulator with hot-reload, run:

```
```bash
npx cap run android -l --external
```

You will need to modify your JHipster app to allow your external IP as a trusted origin for this to work!

You can also open your project in Android Studio and run your app.

```
```bash
npx cap open android
```

Expand Down Expand Up @@ -174,7 +189,7 @@ This app comes with internationalization (i18n) out of the box with [ngx-transla

### Adding Languages

To add new languages, add new files to the `src/assets/i18n` directory, following the pattern of LANGCODE.json where LANGCODE is the language/locale code (ex: en/gb/de/es/etc.).
To add new languages, add new files to the `src/assets/i18n` directory, following the pattern of LANGCODE.json where LANGCODE is the language/locale code (ex: en/gb/de/es/etc.).

## Testing

Expand Down
16 changes: 4 additions & 12 deletions generators/ionic/resources/base/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@
"output": "./svg"
}
],
"styles": [
"src/theme/variables.scss",
"src/global.scss"
],
"styles": ["src/theme/variables.scss", "src/global.scss"],
"scripts": [],
"aot": false,
"vendorChunk": true,
Expand Down Expand Up @@ -99,9 +96,7 @@
"options": {
"polyfills": ["src/polyfills.ts"],
"tsConfig": "tsconfig.spec.json",
"testMatch": [
"**/?(*.)+(spec).[t]s?(x)"
]
"testMatch": ["**/?(*.)+(spec).[t]s?(x)"]
},
"configurations": {
"ci": {
Expand All @@ -113,10 +108,7 @@
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
}
},
"e2e": {
Expand Down Expand Up @@ -165,7 +157,7 @@
},
"configurations": {
"production": {
"devServerTarget": "app:serve:production",
"devServerTarget": "app:serve:production"
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion generators/ionic/resources/base/cypress/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ export default async (on: Cypress.PluginEvents, config: Cypress.PluginConfigOpti
}
});
return config;
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Page } from './app.po';

export class EntityComponentsPage extends Page {
clickOnCreateButton() {
cy.get(`${this.pageSelector } ion-fab-button`).click();
cy.get(`${this.pageSelector} ion-fab-button`).click();
}
}

Expand Down Expand Up @@ -56,10 +56,10 @@ export class EntityUpdatePage extends Page {

export class EntityDetailPage extends Page {
edit() {
cy.get(`${this.pageSelector } ion-button[color="primary"]`).click();
cy.get(`${this.pageSelector} ion-button[color="primary"]`).click();
}

delete() {
cy.get(`${this.pageSelector } ion-button[color="danger"]`).click();
cy.get(`${this.pageSelector} ion-button[color="danger"]`).click();
}
}
5 changes: 1 addition & 4 deletions generators/ionic/resources/base/cypress/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
"include": ["**/*.ts"],
"compilerOptions": {
"sourceMap": false,
"types": [
"cypress",
"node"
]
"types": ["cypress", "node"]
}
}
2 changes: 1 addition & 1 deletion generators/ionic/resources/base/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const config = {
coverageDirectory: "./public/coverage"
coverageDirectory: './public/coverage',
};

module.exports = config;
11 changes: 6 additions & 5 deletions generators/ionic/resources/base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"author": "Ionic Framework + JHipster",
"scripts": {
"build": "ionic build",
"cypress:open": "cypress open",
"cypress:run": "cypress run",
"e2e": "ng e2e",
"e2e:ci": "ng run app:cypress-headless",
"e2e:open": "ng run app:cypress-open",
Expand All @@ -14,9 +16,7 @@
"prettier": "prettier --write \"{,e2e/**/,src/**/}*.{js,json,html,md,ts,css,scss,yml}\" --loglevel silent",
"start": "ionic serve",
"test": "ng test --coverage",
"test:watch": "ng test --watch",
"cypress:open": "cypress open",
"cypress:run": "cypress run"
"test:watch": "ng test --watch"
},
"dependencies": {
"@angular/common": "~14.1.3",
Expand All @@ -29,17 +29,18 @@
"@capacitor-community/http": "1.4.1",
"@capacitor/app": "4.0.1",
"@capacitor/browser": "4.0.1",
"@capacitor/camera": "4.1.0",
"@capacitor/core": "4.1.0",
"@capacitor/haptics": "4.0.1",
"@capacitor/keyboard": "4.0.1",
"@capacitor/preferences": "4.0.1",
"@capacitor/splash-screen": "4.0.1",
"@capacitor/status-bar": "4.0.1",
"@capacitor/preferences": "4.0.1",
"@fortawesome/angular-fontawesome": "0.11.1",
"@fortawesome/fontawesome-svg-core": "6.1.2",
"@fortawesome/free-solid-svg-icons": "6.1.2",
"@ionic-native/camera": "5.36.0",
"@ionic/angular": "^6.2.4",
"@ionic/pwa-elements": "^3.1.1",
"@ionic/storage": "^3.0.6",
"@ionic/storage-angular": "^3.0.6",
"@ngx-translate/core": "14.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const routes: Routes = [
children: [
{
path: '',
loadChildren: () => import('../home/home.module').then((m) => m.HomePageModule),
loadChildren: () => import('../home/home.module').then(m => m.HomePageModule),
},
],
},
Expand All @@ -21,7 +21,7 @@ const routes: Routes = [
children: [
{
path: '',
loadChildren: () => import('../entities/entities.module').then((m) => m.EntitiesPageModule),
loadChildren: () => import('../entities/entities.module').then(m => m.EntitiesPageModule),
},
],
},
Expand All @@ -30,7 +30,7 @@ const routes: Routes = [
children: [
{
path: '',
loadChildren: () => import('../account/account.module').then((m) => m.AccountPageModule),
loadChildren: () => import('../account/account.module').then(m => m.AccountPageModule),
},
],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class AccountService {
}

return this.identity().then(
(id) => {
id => {
return Promise.resolve(id.authorities && id.authorities.includes(authority));
},
() => {
Expand All @@ -76,7 +76,7 @@ export class AccountService {
// retrieve the userIdentity data from the server, update the identity object, and then resolve.
return this.fetch()
.toPromise()
.then((response) => {
.then(response => {
const account = response.body;
if (account) {
this.userIdentity = account;
Expand All @@ -93,7 +93,7 @@ export class AccountService {
this.authenticationState.next(this.userIdentity);
return this.userIdentity;
})
.catch((err) => {
.catch(err => {
this.userIdentity = null;
this.authenticated = false;
this.authenticationState.next(this.userIdentity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class UserRouteAccessService implements CanActivate {
}

checkLogin(authorities: string[], url: string): Promise<boolean> {
return this.accountService.identity().then((account) => {
return this.accountService.identity().then(account => {
if (!authorities || authorities.length === 0) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe('Data Utils Service Test', () => {

service.setFileData(eventSake, null, null, true).then(
() => fail('Should not resolve'),
(error) => expect(error).toMatch(/^File was expected to be an image but was found to be /)
error => expect(error).toMatch(/^File was expected to be an image but was found to be /)
);
})
));
Expand All @@ -90,15 +90,15 @@ describe('Data Utils Service Test', () => {

service
.setFileData(eventSake, {}, 'document', false)
.then((modifiedEntity) => expect(modifiedEntity).toEqual({ document: 'ZmlsZSBjb250ZW50', documentContentType: '' }));
.then(modifiedEntity => expect(modifiedEntity).toEqual({ document: 'ZmlsZSBjb250ZW50', documentContentType: '' }));
})
));

it('should return a promise that rejects with an error message when passed event does not contain a file', async(
inject([JhiDataUtils], (service: JhiDataUtils) => {
service.setFileData(null, null, null, false).then(
() => fail('Should not resolve'),
(error) => expect(error).toMatch(/^Base64 data was not set as file could not be extracted from passed parameter: /)
error => expect(error).toMatch(/^Base64 data was not set as file could not be extracted from passed parameter: /)
);
})
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export class JhiDataUtils {
if (isImage && !file.type.startsWith('image/')) {
reject(`File was expected to be an image but was found to be ${file.type}`);
} else {
this.toBase64(file, (base64Data) => {
this.toBase64(file, base64Data => {
entity[field] = base64Data;
entity[`${field}ContentType`] = file.type;
resolve(entity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { HttpParams } from '@angular/common/http';
export const createRequestOption = (req?: any): HttpParams => {
let options: HttpParams = new HttpParams();
if (req) {
Object.keys(req).forEach((key) => {
Object.keys(req).forEach(key => {
if (key !== 'sort') {
options = options.set(key, req[key]);
}
});
if (req.sort) {
req.sort.forEach((val) => {
req.sort.forEach(val => {
options = options.append('sort', val);
});
}
Expand Down
Loading

0 comments on commit ddf136e

Please sign in to comment.