Skip to content

Commit d8b4eab

Browse files
authored
Merge pull request #3 from ionic-team/web-mobile-support
Finish cross plat support
2 parents fe884a3 + d0c66f0 commit d8b4eab

3 files changed

Lines changed: 99 additions & 24 deletions

File tree

src/app/app.component.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { Component } from '@angular/core';
22

33
import { Platform } from '@ionic/angular';
4-
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
54
import { StatusBar } from '@ionic-native/status-bar/ngx';
5+
import { Plugins } from '@capacitor/core';
6+
const { SplashScreen } = Plugins;
67

78
@Component({
89
selector: 'app-root',
@@ -12,7 +13,6 @@ import { StatusBar } from '@ionic-native/status-bar/ngx';
1213
export class AppComponent {
1314
constructor(
1415
private platform: Platform,
15-
private splashScreen: SplashScreen,
1616
private statusBar: StatusBar
1717
) {
1818
this.initializeApp();
@@ -21,7 +21,8 @@ export class AppComponent {
2121
initializeApp() {
2222
this.platform.ready().then(() => {
2323
this.statusBar.styleDefault();
24-
this.splashScreen.hide();
24+
25+
SplashScreen.hide();
2526
});
2627
}
2728
}

src/app/services/photo.service.ts

Lines changed: 93 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Injectable } from '@angular/core';
22
import { Plugins, CameraResultType, Capacitor, FilesystemDirectory, CameraPhoto, CameraSource } from '@capacitor/core';
3+
import { Platform } from '@ionic/angular';
34

45
const { Camera, Filesystem, Storage } = Plugins;
56

@@ -9,13 +10,31 @@ const { Camera, Filesystem, Storage } = Plugins;
910
export class PhotoService {
1011
public photos: Photo[] = [];
1112
private PHOTO_STORAGE: string = "photos";
13+
private platform: Platform;
1214

13-
constructor() { }
15+
constructor(platform: Platform) {
16+
this.platform = platform;
17+
}
1418

1519
async loadSaved() {
1620
// Retrieve cached photo array data
1721
const photos = await Storage.get({ key: this.PHOTO_STORAGE });
1822
this.photos = JSON.parse(photos.value) || [];
23+
24+
// If running on the web...
25+
if (!this.platform.is('hybrid')) {
26+
// Display the photo by reading into base64 format
27+
for (let photo of this.photos) {
28+
// Read each saved photo's data from the Filesystem
29+
const readFile = await Filesystem.readFile({
30+
path: photo.filepath,
31+
directory: FilesystemDirectory.Data
32+
});
33+
34+
// Web platform only: Save the photo into the base64 field
35+
photo.base64 = `data:image/jpeg;base64,${readFile.data}`;
36+
}
37+
}
1938
}
2039

2140
/* Use the device camera to take a photo:
@@ -27,7 +46,7 @@ export class PhotoService {
2746
// Store a reference to all photo filepaths using Storage API:
2847
// https://capacitor.ionicframework.com/docs/apis/storage
2948
*/
30-
public async takePhoto() {
49+
public async addNewToGallery() {
3150
// Take a photo
3251
const capturedPhoto = await Camera.getPhoto({
3352
resultType: CameraResultType.Uri, // file-based data; provides best performance
@@ -38,40 +57,85 @@ export class PhotoService {
3857
const savedImageFile = await this.savePicture(capturedPhoto);
3958

4059
// Add new photo to Photos array
41-
this.photos.unshift({
42-
filepath: savedImageFile,
43-
webviewPath: Capacitor.convertFileSrc(savedImageFile)
44-
});
60+
this.photos.unshift(savedImageFile);
4561

4662
// Cache all photo data for future retrieval
4763
Storage.set({
4864
key: this.PHOTO_STORAGE,
49-
value: JSON.stringify(this.photos)
65+
value: this.platform.is('hybrid')
66+
? JSON.stringify(this.photos)
67+
: JSON.stringify(this.photos.map(p => {
68+
// Don't save the base64 representation of the photo data,
69+
// since it's already saved on the Filesystem
70+
const photoCopy = { ...p };
71+
delete photoCopy.base64;
72+
73+
return photoCopy;
74+
}))
5075
});
5176
}
5277

5378
// Save picture to file on device
5479
private async savePicture(cameraPhoto: CameraPhoto) {
55-
// Read the file into its base64 version
56-
const readFile = await Filesystem.readFile({
57-
path: cameraPhoto.path
58-
});
80+
// Convert photo to base64 format, required by Filesystem API to save
81+
const base64Data = await this.readAsBase64(cameraPhoto);
5982

60-
// Write the file to the data directory (instead of temp storage)
83+
// Write the file to the data directory
6184
const fileName = new Date().getTime() + '.jpeg';
6285
await Filesystem.writeFile({
6386
path: fileName,
64-
data: readFile.data,
87+
data: base64Data,
6588
directory: FilesystemDirectory.Data
6689
});
6790

68-
// Get the new, complete filepath
69-
const fileUri = await Filesystem.getUri({
70-
directory: FilesystemDirectory.Data,
71-
path: fileName
72-
});
91+
// Get platform-specific photo filepaths
92+
return await this.getPhotoFile(cameraPhoto, fileName);
93+
}
7394

74-
return fileUri.uri;
95+
// Read camera photo into base64 format based on the platform the app is running on
96+
private async readAsBase64(cameraPhoto: CameraPhoto) {
97+
// "hybrid" will detect Cordova or Capacitor
98+
if (this.platform.is('hybrid')) {
99+
// Read the file into base64 format
100+
const file = await Filesystem.readFile({
101+
path: cameraPhoto.path
102+
});
103+
104+
return file.data;
105+
}
106+
else {
107+
// Fetch the photo, read as a blob, then convert to base64 format
108+
const response = await fetch(cameraPhoto.webPath);
109+
const blob = await response.blob();
110+
111+
return await this.convertBlobToBase64(blob) as string;
112+
}
113+
}
114+
115+
// Retrieve the photo metadata based on the platform the app is running on
116+
private async getPhotoFile(cameraPhoto, fileName) {
117+
if (this.platform.is('hybrid')) {
118+
// Get the new, complete filepath of the photo saved on filesystem
119+
const fileUri = await Filesystem.getUri({
120+
directory: FilesystemDirectory.Data,
121+
path: fileName
122+
});
123+
124+
// Display the new image by rewriting the 'file://' path to HTTP
125+
// Details: https://ionicframework.com/docs/building/webview#file-protocol
126+
return {
127+
filepath: fileUri.uri,
128+
webviewPath: Capacitor.convertFileSrc(fileUri.uri),
129+
};
130+
}
131+
else {
132+
// Use webPath to display the new image instead of base64 since it's
133+
// already loaded into memory
134+
return {
135+
filepath: fileName,
136+
webviewPath: cameraPhoto.webPath
137+
};
138+
}
75139
}
76140

77141
// Delete picture by removing it from reference data and the filesystem
@@ -92,9 +156,19 @@ export class PhotoService {
92156
directory: FilesystemDirectory.Data
93157
});
94158
}
159+
160+
convertBlobToBase64 = blob => new Promise((resolve, reject) => {
161+
const reader = new FileReader;
162+
reader.onerror = reject;
163+
reader.onload = () => {
164+
resolve(reader.result);
165+
};
166+
reader.readAsDataURL(blob);
167+
});
95168
}
96169

97170
class Photo {
98171
filepath: string;
99172
webviewPath: string;
173+
base64?: string;
100174
}

src/app/tab2/tab2.page.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
<ion-grid>
1111
<ion-row>
1212
<ion-col size="6" *ngFor="let photo of photoService.photos; index as position">
13-
<ion-img src="{{ photo.webviewPath }}" (click)="showActionSheet(photo, position)"></ion-img>
13+
<ion-img src="{{ photo.base64 ? photo.base64 : photo.webviewPath }}" (click)="showActionSheet(photo, position)"></ion-img>
1414
</ion-col>
1515
</ion-row>
1616
</ion-grid>
1717

1818
<ion-fab vertical="bottom" horizontal="center" slot="fixed">
19-
<ion-fab-button (click)="photoService.takePhoto()">
19+
<ion-fab-button (click)="photoService.addNewToGallery()">
2020
<ion-icon name="camera"></ion-icon>
2121
</ion-fab-button>
2222
</ion-fab>

0 commit comments

Comments
 (0)