diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle
index 837cd452a..ed5f7e515 100644
--- a/android/app/capacitor.build.gradle
+++ b/android/app/capacitor.build.gradle
@@ -9,7 +9,7 @@ android {
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
-
+ implementation project(':capacitor-blob-writer')
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 0097cac1d..1d2c7a31c 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -28,7 +28,8 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:theme="@style/AppTheme">
+ android:theme="@style/AppTheme"
+ android:networkSecurityConfig="@xml/network_security_config">
diff --git a/android/app/src/main/java/io/numbersprotocol/capturelite/MainActivity.java b/android/app/src/main/java/io/numbersprotocol/capturelite/MainActivity.java
index 49f471042..e855bcb48 100644
--- a/android/app/src/main/java/io/numbersprotocol/capturelite/MainActivity.java
+++ b/android/app/src/main/java/io/numbersprotocol/capturelite/MainActivity.java
@@ -5,6 +5,8 @@
import com.getcapacitor.BridgeActivity;
import com.getcapacitor.Plugin;
+import com.equimaps.capacitorblobwriter.BlobWriter;
+
import java.util.ArrayList;
public class MainActivity extends BridgeActivity {
@@ -15,7 +17,7 @@ public void onCreate(Bundle savedInstanceState) {
// Initializes the Bridge
this.init(savedInstanceState, new ArrayList>() {{
// Additional plugins you've installed go here
- // Ex: add(TotallyAwesomePlugin.class);
+ add(BlobWriter.class);
}});
}
}
diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 000000000..6489d8564
--- /dev/null
+++ b/android/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,6 @@
+
+
+
+ localhost
+
+
\ No newline at end of file
diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle
index 9a5fa872e..f8953f834 100644
--- a/android/capacitor.settings.gradle
+++ b/android/capacitor.settings.gradle
@@ -1,3 +1,6 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
include ':capacitor-android'
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
+
+include ':capacitor-blob-writer'
+project(':capacitor-blob-writer').projectDir = new File('../node_modules/capacitor-blob-writer/android')
diff --git a/ios/App/Podfile b/ios/App/Podfile
index 58615b9fd..6870dc834 100644
--- a/ios/App/Podfile
+++ b/ios/App/Podfile
@@ -10,7 +10,7 @@ def capacitor_pods
# Automatic Capacitor Pod dependencies, do not delete
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
-
+ pod 'CapacitorBlobWriter', :path => '../../node_modules/capacitor-blob-writer'
# Do not delete
end
diff --git a/package-lock.json b/package-lock.json
index a3d8c601e..a721ec7ef 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -29,6 +29,7 @@
"@ngx-formly/material": "^5.10.15",
"@ngx-formly/schematics": "^5.10.15",
"async-mutex": "^0.3.1",
+ "capacitor-blob-writer": "^0.2.1",
"compressorjs": "^1.0.7",
"immutable": "^4.0.0-rc.12",
"lodash-es": "^4.17.21",
@@ -5035,6 +5036,14 @@
"integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==",
"dev": true
},
+ "node_modules/capacitor-blob-writer": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/capacitor-blob-writer/-/capacitor-blob-writer-0.2.1.tgz",
+ "integrity": "sha512-fkad3aJA5/j4WbexCxevtE+SfpBi1gAiaFVCpl+wjlXjTDpRTDjP1n4jWlPrs6K0uT3lMtjJpo4rFZsMcvhrqQ==",
+ "peerDependencies": {
+ "@capacitor/core": "^2.0.0"
+ }
+ },
"node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -26821,6 +26830,12 @@
"integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==",
"dev": true
},
+ "capacitor-blob-writer": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/capacitor-blob-writer/-/capacitor-blob-writer-0.2.1.tgz",
+ "integrity": "sha512-fkad3aJA5/j4WbexCxevtE+SfpBi1gAiaFVCpl+wjlXjTDpRTDjP1n4jWlPrs6K0uT3lMtjJpo4rFZsMcvhrqQ==",
+ "requires": {}
+ },
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
diff --git a/package.json b/package.json
index 8ccfa1cd1..ded01e003 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"@ngx-formly/material": "^5.10.15",
"@ngx-formly/schematics": "^5.10.15",
"async-mutex": "^0.3.1",
+ "capacitor-blob-writer": "^0.2.1",
"compressorjs": "^1.0.7",
"immutable": "^4.0.0-rc.12",
"lodash-es": "^4.17.21",
diff --git a/src/app/shared/media/media-store/media-store.service.ts b/src/app/shared/media/media-store/media-store.service.ts
index 4b19850ae..e6ed9a33c 100644
--- a/src/app/shared/media/media-store/media-store.service.ts
+++ b/src/app/shared/media/media-store/media-store.service.ts
@@ -1,3 +1,4 @@
+import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import {
Capacitor,
@@ -5,12 +6,13 @@ import {
FilesystemPlugin,
} from '@capacitor/core';
import { Mutex } from 'async-mutex';
+import { writeFile } from 'capacitor-blob-writer';
import Compressor from 'compressorjs';
import { defer, merge } from 'rxjs';
import { concatMap, map } from 'rxjs/operators';
import { sha256WithBase64 } from '../../../utils/crypto/crypto';
import { base64ToBlob, blobToBase64 } from '../../../utils/encoding/encoding';
-import { MimeType, toExtension } from '../../../utils/mime-type';
+import { fromExtension, MimeType, toExtension } from '../../../utils/mime-type';
import { toDataUrl } from '../../../utils/url';
import { FILESYSTEM_PLUGIN } from '../../capacitor-plugins/capacitor-plugins.module';
import { Database } from '../../database/database.service';
@@ -38,7 +40,8 @@ export class MediaStore {
constructor(
@Inject(FILESYSTEM_PLUGIN)
private readonly filesystemPlugin: FilesystemPlugin,
- private readonly database: Database
+ private readonly database: Database,
+ private readonly httpClient: HttpClient
) {}
private async initialize() {
@@ -61,7 +64,18 @@ export class MediaStore {
});
}
- async read(index: string) {
+ async read(index: string): Promise {
+ await this.initialize();
+ const extension = await this.getExtension(index);
+ if (!extension) throw new Error(`Cannot get extension of ${index}.`);
+ const url = await this.getUrl(index, fromExtension(extension));
+ const blob = await this.httpClient
+ .get(url, { responseType: 'blob' })
+ .toPromise();
+ return blobToBase64(blob);
+ }
+
+ async readWithFileSystem(index: string) {
await this.initialize();
const extension = await this.getExtension(index);
const result = await this.filesystemPlugin.readFile({
@@ -82,9 +96,7 @@ export class MediaStore {
return this._write(index, base64, mimeType);
}
const exists = await this.exists(index);
- if (exists) {
- return index;
- }
+ if (exists) return index;
return this._write(index, base64, mimeType);
}
@@ -92,12 +104,22 @@ export class MediaStore {
await this.initialize();
return this.mutex.runExclusive(async () => {
const mediaExtension = await this.setMediaExtension(index, mimeType);
- await this.filesystemPlugin.writeFile({
- directory: this.directory,
- path: `${this.rootDir}/${index}.${mediaExtension.extension}`,
- data: base64,
- recursive: true,
- });
+ if (Capacitor.isNative) {
+ const blob = await base64ToBlob(base64, mimeType);
+ await writeFile({
+ directory: this.directory,
+ path: `${this.rootDir}/${index}.${mediaExtension.extension}`,
+ data: blob,
+ recursive: true,
+ });
+ } else {
+ await this.filesystemPlugin.writeFile({
+ directory: this.directory,
+ path: `${this.rootDir}/${index}.${mediaExtension.extension}`,
+ data: base64,
+ recursive: true,
+ });
+ }
return index;
});
}
@@ -158,11 +180,13 @@ export class MediaStore {
private async makeThumbnail(index: string, mimeType: MimeType) {
const thumbnailSize = 100;
- const blob = await base64ToBlob(await this.read(index), mimeType);
const thumbnailBlob = mimeType.startsWith('video')
- ? await makeVideoThumbnail({ video: blob, width: thumbnailSize })
+ ? await makeVideoThumbnail({
+ videoUrl: await this.getUrl(index, mimeType),
+ width: thumbnailSize,
+ })
: await makeImageThumbnail({
- image: blob,
+ image: await base64ToBlob(await this.read(index), mimeType),
width: thumbnailSize,
});
return blobToBase64(thumbnailBlob);
@@ -224,7 +248,7 @@ export class MediaStore {
if (Capacitor.isNative)
return Capacitor.convertFileSrc(await this.getUri(index));
return URL.createObjectURL(
- await base64ToBlob(await this.read(index), mimeType)
+ await base64ToBlob(await this.readWithFileSystem(index), mimeType)
);
}
@@ -317,11 +341,11 @@ async function makeImageThumbnail({
}
async function makeVideoThumbnail({
- video,
+ videoUrl,
width,
quality = 0.6,
}: {
- video: Blob;
+ videoUrl: string;
width: number;
quality?: number;
}) {
@@ -349,13 +373,13 @@ async function makeVideoThumbnail({
resolve(makeImageThumbnail({ image: blob, width, quality }));
else reject(TypeError('canvas.toBlob is null.'));
},
- video.type,
+ 'image/jpeg',
quality
);
}
});
videoElement.preload = 'auto';
- videoElement.src = URL.createObjectURL(video);
+ videoElement.src = videoUrl;
videoElement.load();
});
}
diff --git a/src/app/shared/shared-testing.module.ts b/src/app/shared/shared-testing.module.ts
index e420b92e3..4366b3ec4 100644
--- a/src/app/shared/shared-testing.module.ts
+++ b/src/app/shared/shared-testing.module.ts
@@ -1,4 +1,3 @@
-import { HttpClientTestingModule } from '@angular/common/http/testing';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterTestingModule } from '@angular/router/testing';
@@ -11,7 +10,6 @@ import { SharedModule } from './shared.module';
@NgModule({
imports: [
SharedModule,
- HttpClientTestingModule,
RouterTestingModule,
BrowserAnimationsModule,
getTranslocoTestingModule(),